summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSES/Unicode-DFS-2016.txt22
-rw-r--r--LICENSES/blessing.txt5
-rw-r--r--cmake/FindWrapBrotli.cmake7
-rw-r--r--cmake/FindWrapSystemHarfbuzz.cmake7
-rw-r--r--cmake/FindWrapSystemPCRE2.cmake7
-rw-r--r--cmake/FindWrapSystemZLIB.cmake10
-rw-r--r--cmake/FindWrapZSTD.cmake7
-rw-r--r--cmake/QtBuildRepoHelpers.cmake5
-rw-r--r--cmake/QtExecutableHelpers.cmake97
-rw-r--r--cmake/QtHeadersClean.cmake1
-rw-r--r--cmake/QtPkgConfigHelpers.cmake2
-rw-r--r--cmake/QtPluginHelpers.cmake108
-rw-r--r--cmake/QtPostProcessHelpers.cmake10
-rw-r--r--cmake/QtPriHelpers.cmake2
-rw-r--r--cmake/QtProcessConfigureArgs.cmake9
-rw-r--r--cmake/QtPublicWalkLibsHelpers.cmake14
-rw-r--r--cmake/QtPublicWasmToolchainHelpers.cmake4
-rw-r--r--cmake/QtTargetHelpers.cmake17
-rw-r--r--cmake/QtTestHelpers.cmake8
-rw-r--r--cmake/configure-cmake-mapping.md5
-rw-r--r--cmake/visionos/Info.plist.app.in8
-rw-r--r--config_help.txt6
-rw-r--r--configure.cmake15
-rw-r--r--doc/README109
-rw-r--r--doc/global/externalsites/external-resources.qdoc4
-rw-r--r--doc/global/externalsites/rfc.qdoc10
-rw-r--r--doc/global/macros.qdocconf8
-rw-r--r--examples/corelib/platform/androidnotifier/androidnotifier.pro3
-rw-r--r--examples/widgets/doc/src/simpletreemodel.qdoc8
-rw-r--r--examples/widgets/gallery/main.cpp1
-rw-r--r--examples/widgets/gallery/widgetgallery.cpp24
-rw-r--r--examples/widgets/itemviews/editabletreemodel/default.txt10
-rw-r--r--examples/widgets/itemviews/simpletreemodel/default.txt10
-rw-r--r--licenseRule.json32
-rw-r--r--qt_cmdline.cmake3
-rw-r--r--src/3rdparty/harfbuzz-ng/CMakeLists.txt1
-rw-r--r--src/3rdparty/harfbuzz-ng/README.md8
-rw-r--r--src/3rdparty/harfbuzz-ng/qt_attribution.json4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh96
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh68
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh78
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/graph.hh96
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc223
-rw-r--r--src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-algs.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.cc21
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.cc44
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.h6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.h15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-features.h119
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ft.cc16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-icu.cc13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-limits.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-map.hh23
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-object.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-type.hh7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh81
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh57
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh111
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh284
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh32
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh33
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh28
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh450
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh27
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-repacker.hh52
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-serialize.hh66
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc105
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc532
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc71
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.cc3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.h16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-vector.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-version.h4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb.hh12
-rw-r--r--src/3rdparty/libjpeg/LICENSE31
-rwxr-xr-xsrc/3rdparty/libjpeg/import_from_libjpeg_tarball.sh2
-rw-r--r--src/3rdparty/libjpeg/qt_attribution.json8
-rw-r--r--src/3rdparty/libjpeg/src/ChangeLog.md24
-rw-r--r--src/3rdparty/libjpeg/src/jcmaster.c122
-rw-r--r--src/3rdparty/libjpeg/src/jconfig.h4
-rw-r--r--src/3rdparty/libjpeg/src/jconfigint.h2
-rw-r--r--src/3rdparty/libjpeg/src/jerror.c14
-rw-r--r--src/3rdparty/libjpeg/src/jversion.h7
-rw-r--r--src/3rdparty/libjpeg/zlib-license.txt15
-rw-r--r--src/3rdparty/sqlite/qt_attribution.json4
-rw-r--r--src/android/CMakeLists.txt1
-rw-r--r--src/android/jar/CMakeLists.txt2
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java9
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java27
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java8
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java48
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java1
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java15
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java8
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtNative.java13
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java115
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtView.java25
-rw-r--r--src/android/templates/build.gradle6
-rw-r--r--src/android/templates/doc/src/android-manifest-file-configuration.qdoc2
-rw-r--r--src/android/templates_aar/AndroidManifest.xml9
-rw-r--r--src/android/templates_aar/CMakeLists.txt24
-rw-r--r--src/corelib/CMakeLists.txt4
-rw-r--r--src/corelib/Qt6AndroidMacros.cmake50
-rw-r--r--src/corelib/Qt6CoreMacros.cmake8
-rw-r--r--src/corelib/compat/removed_api.cpp110
-rw-r--r--src/corelib/configure.cmake33
-rw-r--r--src/corelib/doc/src/cmake/cmake-properties.qdoc49
-rw-r--r--src/corelib/doc/src/cmake/qt_android_generate_deployment_settings.qdoc1
-rw-r--r--src/corelib/doc/src/foreach-keyword.qdoc3
-rw-r--r--src/corelib/global/qcomparehelpers.h28
-rw-r--r--src/corelib/global/qcompilerdetection.h6
-rw-r--r--src/corelib/global/qglobal.cpp13
-rw-r--r--src/corelib/global/qglobal.h3
-rw-r--r--src/corelib/global/qlibraryinfo.cpp4
-rw-r--r--src/corelib/global/qnamespace.h6
-rw-r--r--src/corelib/global/qnamespace.qdoc12
-rw-r--r--src/corelib/global/qtconfigmacros.h1
-rw-r--r--src/corelib/global/qversiontagging.h6
-rw-r--r--src/corelib/io/qabstractfileengine.cpp8
-rw-r--r--src/corelib/io/qabstractfileengine_p.h11
-rw-r--r--src/corelib/io/qbuffer.cpp3
-rw-r--r--src/corelib/io/qdir.cpp5
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp2
-rw-r--r--src/corelib/io/qfsfileengine.cpp21
-rw-r--r--src/corelib/io/qfsfileengine_p.h3
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp3
-rw-r--r--src/corelib/io/qprocess.cpp4
-rw-r--r--src/corelib/io/qprocess_unix.cpp1
-rw-r--r--src/corelib/io/qresource.cpp289
-rw-r--r--src/corelib/io/qsavefile.cpp8
-rw-r--r--src/corelib/io/qtemporaryfile.cpp8
-rw-r--r--src/corelib/io/qtemporaryfile_p.h3
-rw-r--r--src/corelib/io/qurl.cpp21
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.cpp11
-rw-r--r--src/corelib/kernel/qcore_mac.mm2
-rw-r--r--src/corelib/kernel/qcore_mac_p.h5
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp19
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h1
-rw-r--r--src/corelib/kernel/qcoreapplication_platform.h2
-rw-r--r--src/corelib/kernel/qelapsedtimer.cpp5
-rw-r--r--src/corelib/kernel/qelapsedtimer.h39
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm.cpp9
-rw-r--r--src/corelib/kernel/qeventloop.cpp6
-rw-r--r--src/corelib/kernel/qjniarray.h6
-rw-r--r--src/corelib/kernel/qjnienvironment.h1
-rw-r--r--src/corelib/kernel/qjniobject.cpp4
-rw-r--r--src/corelib/kernel/qjniobject.h4
-rw-r--r--src/corelib/kernel/qjnitypes.h9
-rw-r--r--src/corelib/kernel/qmetacontainer.cpp16
-rw-r--r--src/corelib/kernel/qmetacontainer.h31
-rw-r--r--src/corelib/kernel/qmetaobject.cpp13
-rw-r--r--src/corelib/kernel/qmetaobject.h10
-rw-r--r--src/corelib/kernel/qmetaobject_p.h20
-rw-r--r--src/corelib/kernel/qmetatype.cpp74
-rw-r--r--src/corelib/kernel/qmetatype.h40
-rw-r--r--src/corelib/kernel/qmimedata.cpp5
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/kernel/qproperty_p.h5
-rw-r--r--src/corelib/kernel/qpropertyprivate.h34
-rw-r--r--src/corelib/kernel/qsingleshottimer_p.h15
-rw-r--r--src/corelib/kernel/qsocketnotifier.h16
-rw-r--r--src/corelib/kernel/qsystemerror_p.h7
-rw-r--r--src/corelib/kernel/qtimer.cpp8
-rw-r--r--src/corelib/mimetypes/mime/packages/freedesktop.org.xml62
-rw-r--r--src/corelib/mimetypes/qmimetype.cpp15
-rw-r--r--src/corelib/mimetypes/qmimetype.h8
-rw-r--r--src/corelib/platform/android/qandroidnativeinterface.cpp4
-rw-r--r--src/corelib/serialization/qcborvalue_p.h2
-rw-r--r--src/corelib/serialization/qdatastream.cpp49
-rw-r--r--src/corelib/serialization/qxmlstream.h2
-rw-r--r--src/corelib/text/UNICODE_LICENSE.txt46
-rw-r--r--src/corelib/text/qlatin1stringmatcher.cpp42
-rw-r--r--src/corelib/text/qlatin1stringmatcher.h9
-rw-r--r--src/corelib/text/qlocale.cpp23
-rw-r--r--src/corelib/text/qlocale.h7
-rw-r--r--src/corelib/text/qlocale.qdoc1
-rw-r--r--src/corelib/text/qlocale_data_p.h1430
-rw-r--r--src/corelib/text/qlocale_mac.mm8
-rw-r--r--src/corelib/text/qregularexpression.cpp96
-rw-r--r--src/corelib/text/qregularexpression.h57
-rw-r--r--src/corelib/text/qstaticlatin1stringmatcher.h23
-rw-r--r--src/corelib/text/qstaticlatin1stringmatcher.qdoc1
-rw-r--r--src/corelib/text/qstring.cpp19
-rw-r--r--src/corelib/text/qstringalgorithms.h11
-rw-r--r--src/corelib/text/qstringconverter.cpp20
-rw-r--r--src/corelib/text/qstringconverter.h6
-rw-r--r--src/corelib/text/qt_attribution.json6
-rw-r--r--src/corelib/text/qunicodetables.cpp2
-rw-r--r--src/corelib/text/qunicodetables_p.h2
-rw-r--r--src/corelib/thread/qfuture.h8
-rw-r--r--src/corelib/thread/qfuture.qdoc8
-rw-r--r--src/corelib/thread/qfuture_impl.h4
-rw-r--r--src/corelib/thread/qresultstore.cpp10
-rw-r--r--src/corelib/thread/qresultstore.h9
-rw-r--r--src/corelib/thread/qthread.cpp83
-rw-r--r--src/corelib/thread/qthread.h3
-rw-r--r--src/corelib/thread/qthread_p.h1
-rw-r--r--src/corelib/thread/qthread_unix.cpp26
-rw-r--r--src/corelib/thread/qthread_win.cpp9
-rw-r--r--src/corelib/thread/qthreadpool.cpp39
-rw-r--r--src/corelib/thread/qthreadpool.h13
-rw-r--r--src/corelib/thread/qthreadpool_p.h3
-rw-r--r--src/corelib/time/qcalendar.cpp4
-rw-r--r--src/corelib/time/qdatetime.h2
-rw-r--r--src/corelib/time/qdatetimeparser.cpp6
-rw-r--r--src/corelib/time/qdatetimeparser_p.h4
-rw-r--r--src/corelib/time/qtimezone.cpp2
-rw-r--r--src/corelib/time/qtimezonelocale.cpp99
-rw-r--r--src/corelib/time/qtimezonelocale_p.h13
-rw-r--r--src/corelib/time/qtimezoneprivate.cpp110
-rw-r--r--src/corelib/time/qtimezoneprivate_data_p.h21
-rw-r--r--src/corelib/time/qtimezoneprivate_icu.cpp73
-rw-r--r--src/corelib/time/qtimezoneprivate_p.h41
-rw-r--r--src/corelib/time/qtimezoneprivate_tz.cpp150
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.h5
-rw-r--r--src/corelib/tools/qbitarray.cpp10
-rw-r--r--src/corelib/tools/qbitarray.h13
-rw-r--r--src/corelib/tools/qeasingcurve.cpp33
-rw-r--r--src/corelib/tools/qeasingcurve.h8
-rw-r--r--src/corelib/tools/qline.cpp41
-rw-r--r--src/corelib/tools/qline.h42
-rw-r--r--src/corelib/tools/qmargins.cpp32
-rw-r--r--src/corelib/tools/qmargins.h49
-rw-r--r--src/corelib/tools/qpoint.cpp47
-rw-r--r--src/corelib/tools/qpoint.h26
-rw-r--r--src/corelib/tools/qrect.cpp44
-rw-r--r--src/corelib/tools/qrect.h28
-rw-r--r--src/corelib/tools/qsize.cpp33
-rw-r--r--src/corelib/tools/qsize.h23
-rw-r--r--src/corelib/tools/qvarlengtharray.h7
-rw-r--r--src/corelib/tools/qversionnumber.cpp1
-rw-r--r--src/corelib/tools/qversionnumber.h32
-rw-r--r--src/dbus/qdbusextratypes.cpp2
-rw-r--r--src/dbus/qdbusextratypes.h5
-rw-r--r--src/dbus/qdbusintegrator.cpp3
-rw-r--r--src/dbus/qdbusmarshaller.cpp2
-rw-r--r--src/dbus/qdbusutil.cpp8
-rw-r--r--src/gui/CMakeLists.txt20
-rw-r--r--src/gui/accessible/linux/atspiadaptor.cpp38
-rw-r--r--src/gui/accessible/linux/atspiadaptor_p.h5
-rw-r--r--src/gui/accessible/qaccessible.cpp74
-rw-r--r--src/gui/accessible/qaccessible.h32
-rw-r--r--src/gui/accessible/qaccessible_base.h6
-rw-r--r--src/gui/compat/removed_api.cpp39
-rw-r--r--src/gui/configure.cmake2
-rw-r--r--src/gui/image/qicon.cpp24
-rw-r--r--src/gui/image/qicon_p.h20
-rw-r--r--src/gui/image/qiconengine.h1
-rw-r--r--src/gui/image/qimage.cpp9
-rw-r--r--src/gui/image/qmovie.cpp6
-rw-r--r--src/gui/image/qpixmap.cpp9
-rw-r--r--src/gui/kernel/qguiapplication.cpp50
-rw-r--r--src/gui/kernel/qguiapplication.h2
-rw-r--r--src/gui/kernel/qguiapplication_p.h4
-rw-r--r--src/gui/kernel/qguiapplication_platform.h30
-rw-r--r--src/gui/kernel/qguivariant.cpp2
-rw-r--r--src/gui/kernel/qhighdpiscaling_p.h4
-rw-r--r--src/gui/kernel/qopenglcontext.cpp3
-rw-r--r--src/gui/kernel/qplatformtheme.cpp5
-rw-r--r--src/gui/kernel/qplatformtheme.h1
-rw-r--r--src/gui/kernel/qplatformwindow.cpp9
-rw-r--r--src/gui/kernel/qstylehints.cpp91
-rw-r--r--src/gui/kernel/qstylehints.h10
-rw-r--r--src/gui/kernel/qstylehints_p.h3
-rw-r--r--src/gui/kernel/qwindow.cpp8
-rw-r--r--src/gui/kernel/qwindow_p.h10
-rw-r--r--src/gui/painting/qbackingstore.cpp29
-rw-r--r--src/gui/painting/qcolorspace.cpp8
-rw-r--r--src/gui/painting/qcolortransfertable_p.h54
-rw-r--r--src/gui/painting/qcolortransform.cpp116
-rw-r--r--src/gui/painting/qcolortransform_p.h6
-rw-r--r--src/gui/painting/qicc.cpp13
-rw-r--r--src/gui/painting/qpagelayout.cpp150
-rw-r--r--src/gui/painting/qpagelayout.h13
-rw-r--r--src/gui/painting/qpagesize.h2
-rw-r--r--src/gui/platform/ios/qiosnativeinterface.cpp26
-rw-r--r--src/gui/platform/unix/qgenericunixthemes.cpp2
-rw-r--r--src/gui/platform/windows/qwindowsnativeinterface.cpp10
-rw-r--r--src/gui/qt_cmdline.cmake3
-rw-r--r--src/gui/rhi/qrhigles2.cpp16
-rw-r--r--src/gui/rhi/qrhigles2_p.h6
-rw-r--r--src/gui/rhi/qrhimetal.mm35
-rw-r--r--src/gui/rhi/qrhivulkan.cpp24
-rw-r--r--src/gui/rhi/qrhivulkan_p.h4
-rw-r--r--src/gui/text/coretext/qfontengine_coretext.mm30
-rw-r--r--src/gui/text/coretext/qfontengine_coretext_p.h2
-rw-r--r--src/gui/text/freetype/qfontengine_ft.cpp11
-rw-r--r--src/gui/text/freetype/qfontengine_ft_p.h2
-rw-r--r--src/gui/text/qcssparser.cpp62
-rw-r--r--src/gui/text/qcssparser_p.h17
-rw-r--r--src/gui/text/qfont.cpp14
-rw-r--r--src/gui/text/qfont.h1
-rw-r--r--src/gui/text/qfontengine.cpp79
-rw-r--r--src/gui/text/qfontengine_p.h17
-rw-r--r--src/gui/text/qrawfont.cpp4
-rw-r--r--src/gui/text/qtextdocument.cpp62
-rw-r--r--src/gui/text/qtextengine.cpp23
-rw-r--r--src/gui/text/qtextengine_p.h1
-rw-r--r--src/gui/text/qtextformat.cpp40
-rw-r--r--src/gui/text/qtextformat.h8
-rw-r--r--src/gui/text/qtexthtmlparser.cpp62
-rw-r--r--src/gui/text/qtextimagehandler.cpp26
-rw-r--r--src/gui/text/unix/qfontconfigdatabase.cpp102
-rw-r--r--src/gui/text/windows/qwindowsfontengine.cpp16
-rw-r--r--src/gui/text/windows/qwindowsfontengine_p.h4
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite.cpp16
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite_p.h4
-rw-r--r--src/gui/util/qdesktopservices.cpp42
-rw-r--r--src/gui/util/qgridlayoutengine.cpp4
-rw-r--r--src/network/CMakeLists.txt2
-rw-r--r--src/network/access/http2/http2protocol_p.h2
-rw-r--r--src/network/access/qabstractnetworkcache.cpp43
-rw-r--r--src/network/access/qabstractnetworkcache.h3
-rw-r--r--src/network/access/qabstractprotocolhandler_p.h4
-rw-r--r--src/network/access/qhttp2connection.cpp12
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp26
-rw-r--r--src/network/access/qhttpheaders.h3
-rw-r--r--src/network/access/qhttpheadershelper.cpp25
-rw-r--r--src/network/access/qhttpheadershelper_p.h30
-rw-r--r--src/network/access/qhttpmultipart.cpp51
-rw-r--r--src/network/access/qhttpmultipart.h4
-rw-r--r--src/network/access/qhttpmultipart_p.h7
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp90
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h27
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp175
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h5
-rw-r--r--src/network/access/qhttpnetworkreply.cpp16
-rw-r--r--src/network/access/qhttpnetworkreply_p.h16
-rw-r--r--src/network/access/qhttpprotocolhandler.cpp12
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp22
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp37
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h3
-rw-r--r--src/network/access/qnetworkaccesscachebackend.cpp28
-rw-r--r--src/network/access/qnetworkaccessdebugpipebackend.cpp4
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp37
-rw-r--r--src/network/access/qnetworkdiskcache.cpp58
-rw-r--r--src/network/access/qnetworkfile.cpp7
-rw-r--r--src/network/access/qnetworkfile_p.h2
-rw-r--r--src/network/access/qnetworkreply.cpp60
-rw-r--r--src/network/access/qnetworkreply.h4
-rw-r--r--src/network/access/qnetworkreplydataimpl.cpp7
-rw-r--r--src/network/access/qnetworkreplyfileimpl.cpp16
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp252
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp43
-rw-r--r--src/network/access/qnetworkreplywasmimpl.cpp177
-rw-r--r--src/network/access/qnetworkreplywasmimpl_p.h26
-rw-r--r--src/network/access/qnetworkrequest.cpp532
-rw-r--r--src/network/access/qnetworkrequest.h8
-rw-r--r--src/network/access/qnetworkrequest_p.h42
-rw-r--r--src/network/access/qnetworkrequestfactory.cpp12
-rw-r--r--src/network/access/qrestaccessmanager_p.h8
-rw-r--r--src/network/access/qrestreply.cpp280
-rw-r--r--src/network/access/qsocketabstraction_p.h91
-rw-r--r--src/network/compat/removed_api.cpp3
-rw-r--r--src/network/kernel/qdnslookup.cpp554
-rw-r--r--src/network/kernel/qdnslookup.h110
-rw-r--r--src/network/kernel/qdnslookup_p.h44
-rw-r--r--src/network/kernel/qdnslookup_unix.cpp166
-rw-r--r--src/network/kernel/qdnslookup_win.cpp90
-rw-r--r--src/network/kernel/qnetworkinformation.h1
-rw-r--r--src/network/kernel/qnetworkproxy.cpp55
-rw-r--r--src/network/kernel/qnetworkproxy.h4
-rw-r--r--src/network/kernel/qnetworkproxy_libproxy.cpp6
-rw-r--r--src/network/socket/qhttpsocketengine.cpp11
-rw-r--r--src/network/socket/qsocks5socketengine.cpp2
-rw-r--r--src/plugins/platforms/android/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp6
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.h1
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp86
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp10
-rw-r--r--src/plugins/platforms/android/androidjnimain.h1
-rw-r--r--src/plugins/platforms/android/androidwindowembedding.cpp17
-rw-r--r--src/plugins/platforms/android/qandroidplatformaccessibility.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp21
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.h2
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.cpp21
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.cpp15
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.h3
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.cpp17
-rw-r--r--src/plugins/platforms/cocoa/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm36
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaservices.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaservices.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm2
-rw-r--r--src/plugins/platforms/eglfs/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/ios/CMakeLists.txt19
-rw-r--r--src/plugins/platforms/ios/SwiftIntegration.cmake78
-rw-r--r--src/plugins/platforms/ios/module.modulemap4
-rw-r--r--src/plugins/platforms/ios/qiosapplication.swift82
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.h5
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm45
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.mm8
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h2
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm21
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h3
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm41
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h30
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm37
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h2
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm25
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm2
-rw-r--r--src/plugins/platforms/ios/qiostheme.h5
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm35
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h2
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm37
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm22
-rw-r--r--src/plugins/platforms/ios/quiwindow.mm9
-rw-r--r--src/plugins/platforms/linuxfb/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/minimal/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/minimalegl/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/offscreen/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/qnx/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractnavigator.cpp10
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractnavigator.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxbuffer.cpp24
-rw-r--r--src/plugins/platforms/qnx/qqnxbuffer.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp24
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.cpp22
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.cpp12
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.cpp12
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.cpp12
-rw-r--r--src/plugins/platforms/qnx/qqnxglobal.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp116
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp22
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp66
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h4
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp20
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp27
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.cpp19
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp20
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.cpp14
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp56
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h4
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp49
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.cpp14
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp24
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp56
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h3
-rw-r--r--src/plugins/platforms/vkkhrdisplay/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/vnc/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/wasm/qtloader.js12
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp12
-rw-r--r--src/plugins/platforms/windows/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/windows/qwindowsapplication.cpp5
-rw-r--r--src/plugins/platforms/windows/qwindowsapplication.h1
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp26
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp19
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h1
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp120
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h16
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp27
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp18
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h1
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp8
-rw-r--r--src/plugins/platforms/xcb/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase.cpp96
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp288
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style_p.h1
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistastyle.cpp2
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_win.cpp4
-rw-r--r--src/printsupport/kernel/qprintengine_pdf.cpp5
-rw-r--r--src/printsupport/platform/macos/qprintengine_mac.mm7
-rw-r--r--src/printsupport/platform/windows/qprintengine_win.cpp7
-rw-r--r--src/sql/kernel/qsqldatabase.cpp51
-rw-r--r--src/sql/kernel/qsqldatabase.h3
-rw-r--r--src/sql/kernel/qsqlindex.cpp18
-rw-r--r--src/sql/kernel/qsqlindex.h1
-rw-r--r--src/testlib/CMakeLists.txt4
-rw-r--r--src/testlib/doc/src/qttestlib-manual.qdoc2
-rw-r--r--src/testlib/qcomparisontesthelper_p.h14
-rw-r--r--src/testlib/qsignalspy.cpp179
-rw-r--r--src/testlib/qsignalspy.h187
-rw-r--r--src/testlib/qtest.h375
-rw-r--r--src/testlib/qtest_network.h9
-rw-r--r--src/testlib/qtest_widgets.h9
-rw-r--r--src/testlib/qtestcase.cpp87
-rw-r--r--src/testlib/qtestcase.h226
-rw-r--r--src/testlib/qtestcase.qdoc14
-rw-r--r--src/testlib/qtestlog.cpp5
-rw-r--r--src/testlib/qtestlog_p.h1
-rw-r--r--src/testlib/qtestresult.cpp9
-rw-r--r--src/testlib/qtestresult_p.h6
-rw-r--r--src/testlib/qtesttostring.h499
-rw-r--r--src/testlib/removed_api.cpp29
-rw-r--r--src/tools/androiddeployqt/main.cpp326
-rw-r--r--src/tools/moc/generator.cpp2
-rw-r--r--src/tools/moc/main.cpp69
-rw-r--r--src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp2
-rw-r--r--src/tools/qlalr/cppgenerator.cpp5
-rw-r--r--src/tools/rcc/rcc.cpp4
-rw-r--r--src/tools/rcc/rcc.h2
-rw-r--r--src/tools/uic/cpp/cppwriteinitialization.cpp14
-rw-r--r--src/tools/uic/python/pythonwriteimports.cpp8
-rw-r--r--src/tools/uic/uic.cpp4
-rw-r--r--src/tools/windeployqt/main.cpp35
-rw-r--r--src/tools/windeployqt/utils.h4
-rw-r--r--src/widgets/Qt6WidgetsMacros.cmake290
-rw-r--r--src/widgets/accessible/itemviews_p.h2
-rw-r--r--src/widgets/accessible/qaccessiblewidgetfactory.cpp1
-rw-r--r--src/widgets/dialogs/qdialog.h1
-rw-r--r--src/widgets/doc/snippets/cmake-macros/examples.cmake27
-rw-r--r--src/widgets/doc/snippets/cmake-macros/examples.cpp26
-rw-r--r--src/widgets/doc/src/cmake-macros.qdoc133
-rw-r--r--src/widgets/kernel/qapplication.cpp6
-rw-r--r--src/widgets/kernel/qgesturemanager.cpp3
-rw-r--r--src/widgets/kernel/qwidget.cpp22
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp42
-rw-r--r--src/widgets/kernel/qwindowcontainer.cpp48
-rw-r--r--src/widgets/kernel/qwindowcontainer_p.h3
-rw-r--r--src/widgets/styles/qcommonstyle.cpp69
-rw-r--r--src/widgets/styles/qfusionstyle.cpp42
-rw-r--r--src/widgets/styles/qstyle_p.h26
-rw-r--r--src/widgets/styles/qstylehelper.cpp7
-rw-r--r--src/widgets/styles/qstylehelper_p.h2
-rw-r--r--src/widgets/styles/qstylesheetstyle_default.cpp3
-rw-r--r--src/widgets/util/qcompleter.cpp19
-rw-r--r--src/widgets/widgets/qcalendarwidget.cpp17
-rw-r--r--src/widgets/widgets/qcheckbox.cpp5
-rw-r--r--src/widgets/widgets/qdatetimeedit.cpp18
-rw-r--r--src/widgets/widgets/qdatetimeedit_p.h2
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.cpp58
-rw-r--r--src/widgets/widgets/qdialogbuttonbox_p.h5
-rw-r--r--src/widgets/widgets/qlineedit.cpp7
-rw-r--r--src/widgets/widgets/qmainwindowlayout.cpp16
-rw-r--r--tests/auto/CMakeLists.txt4
-rw-r--r--tests/auto/cmake/CMakeLists.txt36
-rw-r--r--tests/auto/cmake/test_qt_add_ui_1/CMakeLists.txt62
-rw-r--r--tests/auto/cmake/test_qt_add_ui_10/CMakeLists.txt62
-rw-r--r--tests/auto/cmake/test_qt_add_ui_2/CMakeLists.txt60
-rw-r--r--tests/auto/cmake/test_qt_add_ui_3/CMakeLists.txt199
-rw-r--r--tests/auto/cmake/test_qt_add_ui_4/CMakeLists.txt65
-rw-r--r--tests/auto/cmake/test_qt_add_ui_5/CMakeLists.txt164
-rw-r--r--tests/auto/cmake/test_qt_add_ui_6/CMakeLists.txt64
-rw-r--r--tests/auto/cmake/test_qt_add_ui_7/CMakeLists.txt62
-rw-r--r--tests/auto/cmake/test_qt_add_ui_8/CMakeLists.txt67
-rw-r--r--tests/auto/cmake/test_qt_add_ui_9/CMakeLists.txt66
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/CMakeLists.txt7
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/RunCMake.cmake157
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/main.cpp14
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/mainwindow.h26
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/main.cpp14
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.cpp28
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.h25
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/mainwindow.ui33
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/widget1.ui52
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.cpp25
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.h28
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui52
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.cpp25
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.h29
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/sub1/sub2/sub3/sub4/CMakeLists.txt39
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/widget1.ui45
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/CMakeLists.txt33
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/main.cpp14
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.cpp28
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.h25
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.ui33
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.cpp25
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.h28
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.ui52
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.cpp25
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.h29
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.ui45
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/functions.cmake223
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/main.cpp4
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/uic_test/CMakeLists.txt65
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.cpp17
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.ui45
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/uic_test/subdir/mainwindow.ui45
-rw-r--r--tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp2
-rw-r--r--tests/auto/corelib/global/qlogging/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/global/qlogging/tst_qlogging.cpp4
-rw-r--r--tests/auto/corelib/io/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/io/largefile/tst_largefile.cpp8
-rw-r--r--tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp4
-rw-r--r--tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp9
-rw-r--r--tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp10
-rwxr-xr-xtests/auto/corelib/io/qprocess/testBatFiles/simple.bat4
-rwxr-xr-xtests/auto/corelib/io/qprocess/testBatFiles/with space.bat4
-rw-r--r--tests/auto/corelib/io/qprocess/tst_qprocess.cpp20
-rwxr-xr-xtests/auto/corelib/io/qresourceengine/generateResources.sh2
-rw-r--r--tests/auto/corelib/io/qresourceengine/testqrc/test.qrc6
-rw-r--r--tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp86
-rw-r--r--tests/auto/corelib/io/qsavefile/tst_qsavefile.cpp47
-rw-r--r--tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp8
-rw-r--r--tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp2
-rw-r--r--tests/auto/corelib/io/qurl/tst_qurl.cpp34
-rw-r--r--tests/auto/corelib/io/qurlquery/tst_qurlquery.cpp7
-rw-r--r--tests/auto/corelib/itemmodels/CMakeLists.txt16
-rw-r--r--tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp13
-rw-r--r--tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp10
-rw-r--r--tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp11
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp8
-rw-r--r--tests/auto/corelib/kernel/qelapsedtimer/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp22
-rw-r--r--tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp15
-rw-r--r--tests/auto/corelib/kernel/qmetamethod/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp27
-rw-r--r--tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp8
-rw-r--r--tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp122
-rw-r--r--tests/auto/corelib/kernel/qmetatype/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h1
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp25
-rw-r--r--tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp8
-rw-r--r--tests/auto/corelib/mimetypes/qmimetype/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp31
-rw-r--r--tests/auto/corelib/platform/android/tst_android.cpp3
-rw-r--r--tests/auto/corelib/platform/windows/qcomobject/tst_qcomobject.cpp3
-rw-r--r--tests/auto/corelib/serialization/CMakeLists.txt4
-rw-r--r--tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp12
-rw-r--r--tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp12
-rw-r--r--tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp199
-rw-r--r--tests/auto/corelib/text/qlocale/CMakeLists.txt4
-rw-r--r--tests/auto/corelib/text/qlocale/test/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/text/qlocale/tst_qlocale.cpp52
-rw-r--r--tests/auto/corelib/text/qregularexpression/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp42
-rw-r--r--tests/auto/corelib/text/qstring/tst_qstring.cpp12
-rw-r--r--tests/auto/corelib/thread/CMakeLists.txt24
-rw-r--r--tests/auto/corelib/thread/qfuture/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp28
-rw-r--r--tests/auto/corelib/thread/qresultstore/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp33
-rw-r--r--tests/auto/corelib/thread/qthread/tst_qthread.cpp132
-rw-r--r--tests/auto/corelib/time/CMakeLists.txt8
-rw-r--r--tests/auto/corelib/time/qdate/tst_qdate.cpp4
-rw-r--r--tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp8
-rw-r--r--tests/auto/corelib/tools/qbitarray/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp179
-rw-r--r--tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp25
-rw-r--r--tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp4
-rw-r--r--tests/auto/corelib/tools/qline/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qline/tst_qline.cpp125
-rw-r--r--tests/auto/corelib/tools/qmargins/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qmargins/tst_qmargins.cpp99
-rw-r--r--tests/auto/corelib/tools/qpoint/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qpoint/tst_qpoint.cpp17
-rw-r--r--tests/auto/corelib/tools/qpointf/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qpointf/tst_qpointf.cpp56
-rw-r--r--tests/auto/corelib/tools/qrect/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qrect/tst_qrect.cpp92
-rw-r--r--tests/auto/corelib/tools/qsize/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qsize/tst_qsize.cpp37
-rw-r--r--tests/auto/corelib/tools/qsizef/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qsizef/tst_qsizef.cpp96
-rw-r--r--tests/auto/corelib/tools/qversionnumber/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp230
-rw-r--r--tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp2
-rw-r--r--tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp6
-rw-r--r--tests/auto/dbus/qdbustype/tst_qdbustype.cpp13
-rw-r--r--tests/auto/gui/image/CMakeLists.txt8
-rw-r--r--tests/auto/gui/image/qimage/tst_qimage.cpp2
-rw-r--r--tests/auto/gui/image/qmovie/tst_qmovie.cpp12
-rw-r--r--tests/auto/gui/image/qpixmap/tst_qpixmap.cpp2
-rw-r--r--tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp20
-rw-r--r--tests/auto/gui/kernel/qevent/tst_qevent.cpp59
-rw-r--r--tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp42
-rw-r--r--tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp6
-rw-r--r--tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp62
-rw-r--r--tests/auto/gui/painting/qpagelayout/tst_qpagelayout.cpp127
-rw-r--r--tests/auto/gui/text/CMakeLists.txt4
-rw-r--r--tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp4
-rw-r--r--tests/auto/gui/text/qcssparser/tst_qcssparser.cpp55
-rw-r--r--tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp4
-rw-r--r--tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp4
-rw-r--r--tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp137
-rw-r--r--tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp12
-rw-r--r--tests/auto/gui/text/qtextformat/tst_qtextformat.cpp6
-rw-r--r--tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp70
-rw-r--r--tests/auto/gui/text/qtextlist/tst_qtextlist.cpp2
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/data/example.md4
-rw-r--r--tests/auto/gui/text/qtexttable/tst_qtexttable.cpp6
-rw-r--r--tests/auto/gui/util/CMakeLists.txt12
-rw-r--r--tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp15
-rw-r--r--tests/auto/network/access/CMakeLists.txt12
-rw-r--r--tests/auto/network/access/http2/tst_http2.cpp86
-rw-r--r--tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp16
-rw-r--r--tests/auto/network/access/qhttpheadershelper/CMakeLists.txt15
-rw-r--r--tests/auto/network/access/qhttpheadershelper/tst_qhttpheadershelper.cpp76
-rw-r--r--tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp51
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp223
-rw-r--r--tests/auto/network/access/qnetworkreply_local/CMakeLists.txt9
-rw-r--r--tests/auto/network/access/qnetworkreply_local/minihttpserver.h246
-rw-r--r--tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp114
-rw-r--r--tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp158
-rw-r--r--tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp38
-rw-r--r--tests/auto/network/kernel/CMakeLists.txt10
-rw-r--r--tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp627
-rw-r--r--tests/auto/network/socket/CMakeLists.txt10
-rw-r--r--tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp3
-rw-r--r--tests/auto/other/CMakeLists.txt3
-rw-r--r--tests/auto/other/android_deployment_settings/CMakeLists.txt2
-rw-r--r--tests/auto/other/android_deployment_settings/tst_android_deployment_settings.cpp2
-rw-r--r--tests/auto/other/qaccessibility/tst_qaccessibility.cpp3
-rw-r--r--tests/auto/other/qfocusevent/tst_qfocusevent.cpp1
-rw-r--r--tests/auto/other/qvariant_common/tst_qvariant_common.h9
-rw-r--r--tests/auto/sql/kernel/qsqldatabase/tst_databases.h5
-rw-r--r--tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp29
-rw-r--r--tests/auto/testlib/selftests/expected_testlib.junitxml2
-rw-r--r--tests/auto/testlib/selftests/expected_testlib.lightxml2
-rw-r--r--tests/auto/testlib/selftests/expected_testlib.tap4
-rw-r--r--tests/auto/testlib/selftests/expected_testlib.teamcity2
-rw-r--r--tests/auto/testlib/selftests/expected_testlib.txt2
-rw-r--r--tests/auto/testlib/selftests/expected_testlib.xml2
-rw-r--r--tests/auto/testlib/selftests/extendedcompare/tst_extendedcompare.cpp10
-rw-r--r--tests/auto/tools/moc/os9-newlines.h2
-rw-r--r--tests/auto/tools/uic/baseline/icontheme.ui.h6
-rw-r--r--tests/auto/tools/uic/baseline/languagesdialog.ui.h8
-rw-r--r--tests/auto/tools/uic/baseline/pixmapfunction.ui.h8
-rw-r--r--tests/auto/wasm/fetchapi/tst_fetchapi.cpp2
-rw-r--r--tests/auto/wasm/selenium/run.bat2
-rw-r--r--tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp1
-rw-r--r--tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp4
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp5
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp5
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp20
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp13
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp2
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp15
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp5
-rw-r--r--tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp15
-rw-r--r--tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp1
-rw-r--r--tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp2
-rw-r--r--tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp6
-rw-r--r--tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp4
-rw-r--r--tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp1
-rw-r--r--tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp2
-rw-r--r--tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp6
-rw-r--r--tests/auto/widgets/kernel/qaction/tst_qaction.cpp3
-rw-r--r--tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp122
-rw-r--r--tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp2
-rw-r--r--tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp1
-rw-r--r--tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp2
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp128
-rw-r--r--tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp1
-rw-r--r--tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp62
-rw-r--r--tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp6
-rw-r--r--tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp39
-rw-r--r--tests/auto/widgets/util/qscroller/tst_qscroller.cpp4
-rw-r--r--tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp1
-rw-r--r--tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp3
-rw-r--r--tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp9
-rw-r--r--tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp8
-rw-r--r--tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp3
-rw-r--r--tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp1
-rw-r--r--tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp1
-rw-r--r--tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp7
-rw-r--r--tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp13
-rw-r--r--tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp4
-rw-r--r--tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp2
-rw-r--r--tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp20
-rw-r--r--tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp1
-rw-r--r--tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp3
-rw-r--r--tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp1
-rw-r--r--tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp1
-rw-r--r--tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp1
-rw-r--r--tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp1
-rw-r--r--tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp1
-rw-r--r--tests/baseline/shared/paintcommands.cpp4
-rw-r--r--tests/baseline/shared/paintcommands.h2
-rw-r--r--tests/benchmarks/corelib/CMakeLists.txt4
-rw-r--r--tests/benchmarks/corelib/itemmodels/CMakeLists.txt5
-rw-r--r--tests/benchmarks/corelib/thread/CMakeLists.txt4
-rw-r--r--tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp27
-rw-r--r--tests/benchmarks/gui/text/qtext/main.cpp8
-rw-r--r--tests/benchmarks/network/access/CMakeLists.txt6
-rw-r--r--tests/benchmarks/network/access/qdecompresshelper/main.cpp3
-rw-r--r--tests/benchmarks/network/socket/CMakeLists.txt10
-rw-r--r--tests/manual/dialogs/wizardpanel.cpp2
-rw-r--r--tests/manual/examples/widgets/richtext/textedit/example.html4
-rw-r--r--tests/manual/examples/widgets/richtext/textedit/example.md4
-rw-r--r--tests/manual/qdnslookup/main.cpp75
-rw-r--r--tests/manual/qopenglwidget/dockedopenglwidget/fshader.glsl2
-rw-r--r--tests/manual/qopenglwidget/dockedopenglwidget/vshader.glsl2
-rwxr-xr-xtests/manual/rhi/computebuffer/buildshaders.bat2
-rwxr-xr-xtests/manual/rhi/computeimage/buildshaders.bat2
-rw-r--r--tests/manual/rhi/cubemap/buildshaders.bat2
-rw-r--r--tests/manual/rhi/cubemap_render/buildshaders.bat2
-rw-r--r--tests/manual/rhi/displacement/buildshaders.bat2
-rw-r--r--tests/manual/rhi/float16texture_with_compute/buildshaders.bat2
-rwxr-xr-xtests/manual/rhi/geometryshader/buildshaders.bat2
-rw-r--r--tests/manual/rhi/hdr/buildshaders.bat2
-rw-r--r--tests/manual/rhi/instancing/buildshaders.bat2
-rw-r--r--tests/manual/rhi/mrt/buildshaders.bat2
-rw-r--r--tests/manual/rhi/multiview/buildshaders.bat2
-rw-r--r--tests/manual/rhi/noninstanced/buildshaders.bat2
-rwxr-xr-xtests/manual/rhi/polygonmode/buildshaders.bat2
-rw-r--r--tests/manual/rhi/shadowmap/buildshaders.bat2
-rw-r--r--tests/manual/rhi/shared/buildshaders.bat2
-rw-r--r--tests/manual/rhi/shared/imgui/buildshaders.bat2
-rw-r--r--tests/manual/rhi/stenciloutline/buildshaders.bat2
-rw-r--r--tests/manual/rhi/tessellation/buildshaders.bat2
-rw-r--r--tests/manual/rhi/tex1d/buildshaders.bat2
-rw-r--r--tests/manual/rhi/tex3d/buildshaders.bat2
-rw-r--r--tests/manual/wasm/qtloader_integration/test_body.js2
-rw-r--r--tests/shared/nativewindow.h4
-rwxr-xr-xtests/testserver/echo/echo.sh2
-rw-r--r--util/aglfn/main.cpp5
-rwxr-xr-xutil/edid/qedidvendortable.py4
-rw-r--r--util/gradientgen/gradientgen.cpp4
-rw-r--r--util/locale_database/cldr.py17
-rwxr-xr-xutil/locale_database/cldr2qlocalexml.py19
-rwxr-xr-xutil/locale_database/cldr2qtimezone.py215
-rw-r--r--util/locale_database/dateconverter.py22
-rw-r--r--util/locale_database/enumdata.py2
-rw-r--r--util/locale_database/ldml.py4
-rw-r--r--util/locale_database/qlocalexml.py82
-rwxr-xr-xutil/locale_database/qlocalexml2cpp.py48
-rw-r--r--util/locale_database/testlocales/localemodel.cpp884
-rw-r--r--util/locale_database/testlocales/localemodel.h22
-rw-r--r--util/locale_database/testlocales/localewidget.cpp20
-rw-r--r--util/locale_database/testlocales/testlocales.pro3
-rw-r--r--util/locale_database/zonedata.py233
-rw-r--r--util/unicode/main.cpp2
872 files changed, 20727 insertions, 7471 deletions
diff --git a/LICENSES/Unicode-DFS-2016.txt b/LICENSES/Unicode-DFS-2016.txt
new file mode 100644
index 0000000000..71fd6ac5e1
--- /dev/null
+++ b/LICENSES/Unicode-DFS-2016.txt
@@ -0,0 +1,22 @@
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
+
+Unicode Data Files do not include PDF online code charts under the directory http://www.unicode.org/Public/.
+
+Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
+
+NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 1991-2016 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either
+
+ (a) this copyright and permission notice appear with all copies of the Data Files or Software, or
+ (b) this copyright and permission notice appear in associated Documentation.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder.
diff --git a/LICENSES/blessing.txt b/LICENSES/blessing.txt
new file mode 100644
index 0000000000..7a1b711a6b
--- /dev/null
+++ b/LICENSES/blessing.txt
@@ -0,0 +1,5 @@
+The author disclaims copyright to this source code. In place of a legal notice, here is a blessing:
+
+May you do good and not evil.
+May you find forgiveness for yourself and forgive others.
+May you share freely, never taking more than you give.
diff --git a/cmake/FindWrapBrotli.cmake b/cmake/FindWrapBrotli.cmake
index e2d7b564f6..d254f4292e 100644
--- a/cmake/FindWrapBrotli.cmake
+++ b/cmake/FindWrapBrotli.cmake
@@ -20,6 +20,13 @@ if (unofficial-brotli_FOUND)
set(WrapBrotli_FOUND ON)
else()
+ get_cmake_property(__packages_not_found PACKAGES_NOT_FOUND)
+ if(__packages_not_found)
+ list(REMOVE_ITEM __packages_not_found unofficial-brotli)
+ set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND "${__packages_not_found}")
+ endif()
+ unset(__packages_not_found)
+
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_check_modules(libbrotlidec QUIET IMPORTED_TARGET "libbrotlidec")
diff --git a/cmake/FindWrapSystemHarfbuzz.cmake b/cmake/FindWrapSystemHarfbuzz.cmake
index 07b3405bc0..d989c93e44 100644
--- a/cmake/FindWrapSystemHarfbuzz.cmake
+++ b/cmake/FindWrapSystemHarfbuzz.cmake
@@ -28,6 +28,13 @@ if(harfbuzz_FOUND AND TARGET "${__harfbuzz_target_name}")
if(harfbuzz_VERSION)
set(WrapSystemHarfbuzz_VERSION "${harfbuzz_VERSION}")
endif()
+else()
+ get_cmake_property(__packages_not_found PACKAGES_NOT_FOUND)
+ if(__packages_not_found)
+ list(REMOVE_ITEM __packages_not_found harfbuzz)
+ set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND "${__packages_not_found}")
+ endif()
+ unset(__packages_not_found)
endif()
if(__harfbuzz_broken_config_file OR NOT __harfbuzz_found)
diff --git a/cmake/FindWrapSystemPCRE2.cmake b/cmake/FindWrapSystemPCRE2.cmake
index 61e0d2fb5b..ce00252c8c 100644
--- a/cmake/FindWrapSystemPCRE2.cmake
+++ b/cmake/FindWrapSystemPCRE2.cmake
@@ -16,6 +16,13 @@ if(PCRE2_FOUND AND TARGET "${__pcre2_target_name}")
if(PCRE2_VERSION)
set(WrapSystemPCRE2_VERSION "${PCRE2_VERSION}")
endif()
+else()
+ get_cmake_property(__packages_not_found PACKAGES_NOT_FOUND)
+ if(__packages_not_found)
+ list(REMOVE_ITEM __packages_not_found PCRE2)
+ set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND "${__packages_not_found}")
+ endif()
+ unset(__packages_not_found)
endif()
if(NOT __pcre2_found)
diff --git a/cmake/FindWrapSystemZLIB.cmake b/cmake/FindWrapSystemZLIB.cmake
index 5db43db626..f9a8f004ec 100644
--- a/cmake/FindWrapSystemZLIB.cmake
+++ b/cmake/FindWrapSystemZLIB.cmake
@@ -28,5 +28,13 @@ if(ZLIB_FOUND)
endif()
endif()
+if(ZLIB_VERSION)
+ set(WrapSystemZLIB_VERSION "${ZLIB_VERSION}")
+elseif(ZLIB_VERSION_STRING)
+ set(WrapSystemZLIB_VERSION "${ZLIB_VERSION_STRING}")
+endif()
+
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WrapSystemZLIB DEFAULT_MSG WrapSystemZLIB_FOUND)
+find_package_handle_standard_args(WrapSystemZLIB
+ REQUIRED_VARS WrapSystemZLIB_FOUND
+ VERSION_VAR WrapSystemZLIB_VERSION)
diff --git a/cmake/FindWrapZSTD.cmake b/cmake/FindWrapZSTD.cmake
index fb424236b8..7e5adcf276 100644
--- a/cmake/FindWrapZSTD.cmake
+++ b/cmake/FindWrapZSTD.cmake
@@ -39,6 +39,13 @@ if(TARGET zstd::libzstd_static OR TARGET zstd::libzstd_shared)
INTERFACE_LINK_LIBRARIES "zstd::libzstd${zstdtargetsuffix}")
endif()
else()
+ get_cmake_property(__packages_not_found PACKAGES_NOT_FOUND)
+ if(__packages_not_found)
+ list(REMOVE_ITEM __packages_not_found zstd)
+ set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND "${__packages_not_found}")
+ endif()
+ unset(__packages_not_found)
+
find_package(PkgConfig QUIET)
pkg_check_modules(PC_ZSTD QUIET "libzstd")
diff --git a/cmake/QtBuildRepoHelpers.cmake b/cmake/QtBuildRepoHelpers.cmake
index 9053c377af..8bd0615090 100644
--- a/cmake/QtBuildRepoHelpers.cmake
+++ b/cmake/QtBuildRepoHelpers.cmake
@@ -434,8 +434,11 @@ function(qt_internal_show_extra_ide_sources)
# licenses
set(licenses_target_name ${qt_repo_targets_name}_licenses)
file(GLOB licenses_files LIST_DIRECTORIES false LICENSES/*)
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/licenseRule.json")
+ list(APPEND licenses_files "${CMAKE_CURRENT_SOURCE_DIR}/licenseRule.json")
+ endif()
if(licenses_files)
- source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSES" FILES ${licenses_files})
+ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${licenses_files})
add_custom_target(${licenses_target_name} SOURCES ${licenses_files})
endif()
diff --git a/cmake/QtExecutableHelpers.cmake b/cmake/QtExecutableHelpers.cmake
index fb96ca4db2..7856e4111f 100644
--- a/cmake/QtExecutableHelpers.cmake
+++ b/cmake/QtExecutableHelpers.cmake
@@ -207,103 +207,6 @@ function(qt_internal_add_executable name)
ADDITIONAL_INSTALL_ARGS ${additional_install_args})
qt_internal_install_pdb_files(${name} "${arg_INSTALL_DIRECTORY}")
endif()
-
- # If linking against Gui, make sure to also build the default QPA plugin.
- # This makes the experience of an initial Qt configuration to build and run one single
- # test / executable nicer.
- get_target_property(linked_libs "${name}" LINK_LIBRARIES)
- if("Qt::Gui" IN_LIST linked_libs AND TARGET qpa_default_plugins)
- add_dependencies("${name}" qpa_default_plugins)
- endif()
-
- # For static plugins, we need to explicitly link to plugins we want to be
- # loaded with the executable. User projects get that automatically, but
- # for tools built as part of Qt, we can't use that mechanism because it
- # would pollute the targets we export as part of an install and lead to
- # circular dependencies. The logic here is a simpler equivalent of the
- # more dynamic logic in QtPlugins.cmake.in, but restricted to only
- # adding plugins that are provided by the same module as the module
- # libraries the executable links to.
- set(libs
- ${arg_LIBRARIES}
- ${arg_PUBLIC_LIBRARIES}
- ${extra_libraries}
- Qt::PlatformCommonInternal
- )
-
- set(deduped_libs "")
- foreach(lib IN LISTS libs)
- if(NOT TARGET "${lib}")
- continue()
- endif()
-
- # Normalize module by stripping any leading "Qt::", because properties are set on the
- # versioned target (either Gui when building the module, or Qt6::Gui when it's
- # imported).
- if(lib MATCHES "Qt::([-_A-Za-z0-9]+)")
- set(new_lib "${QT_CMAKE_EXPORT_NAMESPACE}::${CMAKE_MATCH_1}")
- if(TARGET "${new_lib}")
- set(lib "${new_lib}")
- endif()
- endif()
-
- # Unalias the target.
- get_target_property(aliased_target ${lib} ALIASED_TARGET)
- if(aliased_target)
- set(lib ${aliased_target})
- endif()
-
- list(APPEND deduped_libs "${lib}")
- endforeach()
-
- list(REMOVE_DUPLICATES deduped_libs)
-
- foreach(lib IN LISTS deduped_libs)
- string(MAKE_C_IDENTIFIER "${name}_plugin_imports_${lib}" out_file)
- string(APPEND out_file .cpp)
-
- # Initialize plugins that are built in the same repository as the Qt module 'lib'.
- set(class_names_regular
- "$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},_qt_initial_repo_plugin_class_names>>")
-
- # Initialize plugins that are built in the current Qt repository, but are associated
- # with a Qt module from a different repository (qtsvg's QSvgPlugin associated with
- # qtbase's QtGui).
- string(MAKE_C_IDENTIFIER "${PROJECT_NAME}" current_project_name)
- set(prop_prefix "_qt_repo_${current_project_name}")
- set(class_names_current_project
- "$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},${prop_prefix}_plugin_class_names>>")
-
- # Only add separator if first list is not empty, so we don't trigger the file generation
- # when all lists are empty.
- set(class_names_separator "$<$<NOT:$<STREQUAL:${class_names_regular},>>:;>" )
- set(class_names
- "${class_names_regular}${class_names_separator}${class_names_current_project}")
-
- set(out_file_path "${CMAKE_CURRENT_BINARY_DIR}/${out_file}")
-
- file(GENERATE OUTPUT "${out_file_path}" CONTENT
-"// This file is auto-generated. Do not edit.
-#include <QtPlugin>
-
-Q_IMPORT_PLUGIN($<JOIN:${class_names},)\nQ_IMPORT_PLUGIN(>)
-"
- CONDITION "$<NOT:$<STREQUAL:${class_names},>>"
- )
-
- # CMake versions earlier than 3.18.0 can't find the generated file for some reason,
- # failing at generation phase.
- # Explicitly marking the file as GENERATED fixes the issue.
- set_source_files_properties("${out_file_path}" PROPERTIES GENERATED TRUE)
-
- target_sources(${name} PRIVATE
- "$<$<NOT:$<STREQUAL:${class_names},>>:${out_file_path}>"
- )
- target_link_libraries(${name} PRIVATE
- "$<TARGET_PROPERTY:${lib},_qt_initial_repo_plugins>"
- "$<TARGET_PROPERTY:${lib},${prop_prefix}_plugins>")
- endforeach()
-
endfunction()
# This function compiles the target at configure time the very first time and creates the custom
diff --git a/cmake/QtHeadersClean.cmake b/cmake/QtHeadersClean.cmake
index f47ac1754c..938b6a7b41 100644
--- a/cmake/QtHeadersClean.cmake
+++ b/cmake/QtHeadersClean.cmake
@@ -112,6 +112,7 @@ function(qt_internal_add_headersclean_target module_target module_headers)
-Woverloaded-virtual -Wshadow -Wundef -Wfloat-equal
-Wnon-virtual-dtor -Wpointer-arith -Wformat-security
-Wchar-subscripts -Wold-style-cast
+ -Wredundant-decls # QTBUG-115583
-fno-operator-names)
if(QT_FEATURE_reduce_relocations AND UNIX)
diff --git a/cmake/QtPkgConfigHelpers.cmake b/cmake/QtPkgConfigHelpers.cmake
index dbe736c438..ea28516941 100644
--- a/cmake/QtPkgConfigHelpers.cmake
+++ b/cmake/QtPkgConfigHelpers.cmake
@@ -74,7 +74,7 @@ function(qt_internal_generate_pkg_config_file module)
foreach(dep IN LISTS loose_target_requires)
if(dep MATCHES "^Qt::")
string(REGEX REPLACE "Qt" "${QT_CMAKE_EXPORT_NAMESPACE}" dep ${dep})
- else()
+ elseif(NOT dep MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::")
# TODO: Figure out a way to get non-Qt requirements PkgConfig files.
continue()
endif()
diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake
index 9437d4236d..787788c9a9 100644
--- a/cmake/QtPluginHelpers.cmake
+++ b/cmake/QtPluginHelpers.cmake
@@ -227,69 +227,6 @@ function(qt_internal_add_plugin target)
set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
get_target_property(type "${plugin_target_versioned}" TYPE)
- if(type STREQUAL STATIC_LIBRARY)
- # Associate plugin with its Qt module when both are both built in the same repository.
- # Check that by comparing the PROJECT_NAME of each.
- # This covers auto-linking of the majority of plugins to executables and in-tree tests.
- # Linking of plugins in standalone tests (when the Qt module will be an imported target)
- # is handled instead by the complicated genex logic in QtModulePlugins.cmake.in.
- set(is_plugin_and_module_in_same_project FALSE)
- if(NOT is_imported_qt_module)
- get_target_property(module_source_dir ${qt_module_target} SOURCE_DIR)
- get_directory_property(module_project_name
- DIRECTORY ${module_source_dir}
- DEFINITION PROJECT_NAME
- )
- if(module_project_name STREQUAL PROJECT_NAME)
- set(is_plugin_and_module_in_same_project TRUE)
- endif()
-
- # When linking static plugins with the special logic in qt_internal_add_executable,
- # make sure to skip non-default plugins.
- if(is_plugin_and_module_in_same_project AND _default_plugin)
- set_property(TARGET ${qt_module_target} APPEND PROPERTY
- _qt_initial_repo_plugins
- "${target}")
- set_property(TARGET ${qt_module_target} APPEND PROPERTY
- _qt_initial_repo_plugin_class_names
- "$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
- )
- endif()
- endif()
-
- # Associate plugin with its Qt module when the plugin is built in the current repository
- # but the module is built in a different repository (qtsvg's QSvgPlugin associated with
- # qtbase's QtGui).
- # The association is done in a separate property, to ensure that reconfiguring in-tree tests
- # in qtbase doesn't accidentally cause linking to a plugin from a previously built qtsvg.
- # Needed for in-tree tests like in qtsvg, qtimageformats.
- # This is done for each Qt module regardless if it's an imported target or not, to handle
- # both per-repo and top-level builds (in per-repo build of qtsvg QtGui is imported, in a
- # top-level build Gui is not imported, but in both cases qtsvg tests need to link to
- # QSvgPlugin).
- #
- # TODO: Top-level in-tree tests and qdeclarative per-repo in-tree tests that depend on
- # static Qml plugins won't work due to the requirement of running qmlimportscanner
- # at configure time, but qmlimportscanner is not built at that point. Moving the
- # execution of qmlimportscanner to build time is non-trivial because qmlimportscanner
- # not only generates a cpp file to compile but also outputs a list of static plugins
- # that should be linked and there is no straightforward way to tell CMake to link
- # against a list of libraries that was discovered at build time (apart from
- # response files, which apparently might not work on all platforms).
- # qmake doesn't have this problem because each project is configured separately so
- # qmlimportscanner is always built by the time it needs to be run for a test.
- if(NOT is_plugin_and_module_in_same_project AND _default_plugin)
- string(MAKE_C_IDENTIFIER "${PROJECT_NAME}" current_project_name)
- set(prop_prefix "_qt_repo_${current_project_name}")
- set_property(TARGET ${qt_module_target} APPEND PROPERTY
- ${prop_prefix}_plugins "${target}")
- set_property(TARGET ${qt_module_target} APPEND PROPERTY
- ${prop_prefix}_plugin_class_names
- "$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
- )
- endif()
- endif()
-
qt_internal_add_autogen_sync_header_dependencies(${target} ${qt_module_target})
endif()
@@ -623,3 +560,48 @@ function(qt_internal_add_darwin_permission_plugin permission)
QT_PLUGIN_PRI_EXTRA_CONTENT ${extra_plugin_pri_content}
)
endfunction()
+
+# The function looks and links the static plugins that the target depends on. The function behaves
+# similar to qt_import_plugins, but should be used when building Qt executable or shared libraries.
+# It's expected that all dependencies are valid targets at the time when the function is called.
+# If not their plugins will be not collected for linking.
+function(qt_internal_import_plugins target)
+ set(plugin_targets "")
+ foreach(dep_target IN LISTS ARGN)
+ if(dep_target AND TARGET ${dep_target})
+ get_target_property(plugins ${dep_target} _qt_plugins)
+ if(plugins)
+ list(APPEND plugin_targets ${plugins})
+ else()
+ # Fallback should be remove in Qt 7.
+ get_target_property(target_type ${dep_target} TYPE)
+ if(NOT "${target_type}" STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(plugins ${dep_target} QT_PLUGINS)
+ if(plugins)
+ list(APPEND plugin_targets ${plugins})
+ endif()
+ endif()
+ endif()
+ endif()
+ endforeach()
+
+ set(non_imported_plugin_targets "")
+ foreach(plugin_target IN LISTS plugin_targets)
+ if(NOT TARGET ${plugin_target} OR "${plugin_target}" IN_LIST non_imported_plugin_targets)
+ continue()
+ endif()
+
+ get_target_property(is_imported ${plugin_target} IMPORTED)
+ if(NOT is_imported)
+ list(APPEND non_imported_plugin_targets "${plugin_target}")
+ endif()
+ endforeach()
+
+ if(plugin_targets)
+ __qt_internal_collect_plugin_init_libraries("${non_imported_plugin_targets}" init_libraries)
+ __qt_internal_collect_plugin_libraries("${non_imported_plugin_targets}" plugin_libraries)
+ if(plugin_libraries OR init_libraries)
+ target_link_libraries(${target} PRIVATE ${plugin_libraries} ${init_libraries})
+ endif()
+ endif()
+endfunction()
diff --git a/cmake/QtPostProcessHelpers.cmake b/cmake/QtPostProcessHelpers.cmake
index 0a207f6634..53ff7e1358 100644
--- a/cmake/QtPostProcessHelpers.cmake
+++ b/cmake/QtPostProcessHelpers.cmake
@@ -653,13 +653,19 @@ set(__qt_internal_initial_qt_cmake_build_type \"${CMAKE_BUILD_TYPE}\")
endif()
# Save the default qpa platform.
- # Used by qtwayland/src/plugins/platforms/qwayland-generic/CMakeLists.txt. Otherwise
- # the DEFAULT_IF condition is evaluated incorrectly.
if(DEFINED QT_QPA_DEFAULT_PLATFORM)
string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
"set(QT_QPA_DEFAULT_PLATFORM \"${QT_QPA_DEFAULT_PLATFORM}\" CACHE STRING \"\")\n")
endif()
+ # Save the list of default qpa platforms.
+ # Used by qtwayland/src/plugins/platforms/qwayland-generic/CMakeLists.txt. Otherwise
+ # the DEFAULT_IF condition is evaluated incorrectly.
+ if(DEFINED QT_QPA_PLATFORMS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_QPA_PLATFORMS \"${QT_QPA_PLATFORMS}\" CACHE STRING \"\")\n")
+ endif()
+
# Save minimum and policy-related CMake versions to ensure the same minimum is
# checked for when building other downstream repos (qtsvg, etc) and the policy settings
# will be consistent unless the downstream repos explicitly override them.
diff --git a/cmake/QtPriHelpers.cmake b/cmake/QtPriHelpers.cmake
index b5e77c1b68..f410dc9b2a 100644
--- a/cmake/QtPriHelpers.cmake
+++ b/cmake/QtPriHelpers.cmake
@@ -804,8 +804,6 @@ QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
list(APPEND extra_statements "QT_ARCHS = ${architectures}")
endif()
- list(APPEND extra_statements "QT_EDITION = Open Source")
-
if(WASM)
list(APPEND extra_statements
"QT_EMCC_VERSION = ${EMCC_VERSION}")
diff --git a/cmake/QtProcessConfigureArgs.cmake b/cmake/QtProcessConfigureArgs.cmake
index 53235ee9d9..df0dfe48de 100644
--- a/cmake/QtProcessConfigureArgs.cmake
+++ b/cmake/QtProcessConfigureArgs.cmake
@@ -90,7 +90,11 @@ unset(device_options)
unset(options_json_file)
set_property(GLOBAL PROPERTY UNHANDLED_ARGS "")
while(NOT "${configure_args}" STREQUAL "")
- list(POP_FRONT configure_args arg)
+ list(POP_FRONT configure_args raw_arg)
+
+ # Condense '--foo-bar' arguments into '-foo-bar'.
+ string(REGEX REPLACE "^--([^-])" "-\\1" arg "${raw_arg}")
+
if(arg STREQUAL "-cmake-generator")
list(POP_FRONT configure_args generator)
elseif(arg STREQUAL "-cmake-use-default-generator")
@@ -156,7 +160,7 @@ while(NOT "${configure_args}" STREQUAL "")
list(POP_FRONT configure_args version)
is_valid_qt_hex_version("${arg}" "${version}")
push("-DQT_DISABLE_DEPRECATED_UP_TO=${version}")
- elseif(arg STREQUAL "--")
+ elseif(raw_arg STREQUAL "--")
# Everything after this argument will be passed to CMake verbatim.
list(APPEND cmake_args "${configure_args}")
break()
@@ -939,6 +943,7 @@ translate_string_input(platform QT_QMAKE_TARGET_MKSPEC)
translate_string_input(xplatform QT_QMAKE_TARGET_MKSPEC)
guess_compiler_from_mkspec()
translate_string_input(qpa_default_platform QT_QPA_DEFAULT_PLATFORM)
+translate_list_input(qpa_platforms QT_QPA_PLATFORMS)
translate_path_input(android-sdk ANDROID_SDK_ROOT)
translate_path_input(android-ndk ANDROID_NDK_ROOT)
diff --git a/cmake/QtPublicWalkLibsHelpers.cmake b/cmake/QtPublicWalkLibsHelpers.cmake
index f79b70c710..959283aca1 100644
--- a/cmake/QtPublicWalkLibsHelpers.cmake
+++ b/cmake/QtPublicWalkLibsHelpers.cmake
@@ -184,13 +184,13 @@ function(__qt_internal_walk_libs
if(lib_target MATCHES "^::@")
continue()
elseif(TARGET ${lib_target})
- if ("${lib_target}" MATCHES "^Qt::(.*)")
- # If both, Qt::Foo and Foo targets exist, prefer the target name without
+ if(NOT "${lib_target}" MATCHES "^(Qt|${QT_CMAKE_EXPORT_NAMESPACE})::.+")
+ # If both, Qt::Foo and Foo targets exist, prefer the target name with versioned
# namespace. Which one is preferred doesn't really matter. This code exists to
# avoid ending up with both, Qt::Foo and Foo in our dependencies.
- set(namespaceless_lib_target "${CMAKE_MATCH_1}")
- if(TARGET "${namespaceless_lib_target}")
- set(lib_target ${namespaceless_lib_target})
+ set(versioned_qt_target "${QT_CMAKE_EXPORT_NAMESPACE}::${lib_target}")
+ if(TARGET "${versioned_qt_target}")
+ set(lib_target ${versioned_qt_target})
endif()
endif()
get_target_property(lib_target_type ${lib_target} TYPE)
@@ -255,8 +255,8 @@ function(__qt_internal_walk_libs
__qt_internal_promote_target_to_global(${lib_target_unaliased})
endif()
endif()
- elseif("${lib_target}" MATCHES "^Qt::(.*)")
- message(FATAL_ERROR "The ${CMAKE_MATCH_1} target is mentioned as a dependency for \
+ elseif("${lib_target}" MATCHES "^(Qt|${QT_CMAKE_EXPORT_NAMESPACE})::(.*)")
+ message(FATAL_ERROR "The ${CMAKE_MATCH_2} target is mentioned as a dependency for \
${target}, but not declared.")
else()
if(NOT operation MATCHES "^(collect|direct)_targets$")
diff --git a/cmake/QtPublicWasmToolchainHelpers.cmake b/cmake/QtPublicWasmToolchainHelpers.cmake
index 31f6b5aca5..a8994520e2 100644
--- a/cmake/QtPublicWasmToolchainHelpers.cmake
+++ b/cmake/QtPublicWasmToolchainHelpers.cmake
@@ -83,8 +83,6 @@ function(__qt_internal_get_qt_build_emsdk_version out_var)
file(READ "${WASM_BUILD_DIR}/src/corelib/global/qconfig.h" ver)
elseif(EXISTS "${WASM_BUILD_DIR}/include/QtCore/qconfig.h")
file(READ "${WASM_BUILD_DIR}/include/QtCore/qconfig.h" ver)
- else()
- message("qconfig.h not found, unable to determine Qt build Emscripten version")
endif()
if (ver)
string(REGEX MATCH "#define QT_EMCC_VERSION.\"[0-9]+\\.[0-9]+\\.[0-9]+\"" emOutput ${ver})
@@ -99,7 +97,7 @@ function(_qt_test_emscripten_version)
__qt_internal_query_emsdk_version("${emroot_path}" TRUE current_emsdk_ver)
__qt_internal_get_qt_build_emsdk_version(qt_build_emcc_version)
- if(NOT "${qt_build_emcc_version}" STREQUAL "${current_emsdk_ver}")
+ if(NOT "${qt_build_emcc_version}" STREQUAL "" AND NOT "${qt_build_emcc_version}" STREQUAL "${current_emsdk_ver}")
message("Qt Wasm built with Emscripten version: ${qt_build_emcc_version}")
message("You are using Emscripten version: ${current_emsdk_ver}")
message("The recommended version of Emscripten for this Qt is: ${_recommended_emver}")
diff --git a/cmake/QtTargetHelpers.cmake b/cmake/QtTargetHelpers.cmake
index e669047ff1..3740e85803 100644
--- a/cmake/QtTargetHelpers.cmake
+++ b/cmake/QtTargetHelpers.cmake
@@ -99,10 +99,13 @@ function(qt_internal_extend_target target)
get_target_property(target_type ${target} TYPE)
set(is_library FALSE)
set(is_interface_lib FALSE)
+ set(is_executable FALSE)
if(${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY")
set(is_library TRUE)
elseif(target_type STREQUAL "INTERFACE_LIBRARY")
set(is_interface_lib TRUE)
+ elseif(target_type STREQUAL "EXECUTABLE")
+ set(is_executable TRUE)
endif()
foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
@@ -273,6 +276,20 @@ function(qt_internal_extend_target target)
set_target_properties(${target} PROPERTIES
_qt_extra_linker_script_exports "${arg_EXTRA_LINKER_SCRIPT_EXPORTS}")
endif()
+
+ if(is_executable)
+ # If linking against Gui, make sure to also build the default QPA plugin.
+ # This makes the experience of an initial Qt configuration to build and run one single
+ # test / executable nicer.
+ set(linked_libs ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
+ if(linked_libs MATCHES "(^|;)(${QT_CMAKE_EXPORT_NAMESPACE}::|Qt::)?Gui($|;)" AND
+ TARGET qpa_default_plugins)
+ add_dependencies("${target}" qpa_default_plugins)
+ endif()
+
+ # For executables collect static plugins that these targets depend on.
+ qt_internal_import_plugins(${target} ${linked_libs})
+ endif()
endfunction()
# Given CMAKE_CONFIG and ALL_CMAKE_CONFIGS, determines if a directory suffix needs to be appended
diff --git a/cmake/QtTestHelpers.cmake b/cmake/QtTestHelpers.cmake
index 705de2f739..b6bba5ed12 100644
--- a/cmake/QtTestHelpers.cmake
+++ b/cmake/QtTestHelpers.cmake
@@ -566,12 +566,14 @@ function(qt_internal_add_test name)
LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest
)
- qt_internal_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID
+ qt_internal_extend_target("${name}"
+ CONDITION arg_QMLTEST AND NOT ANDROID AND NOT QT_FORCE_BUILTIN_TESTDATA
DEFINES
QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
)
- qt_internal_extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID
+ qt_internal_extend_target("${name}"
+ CONDITION arg_QMLTEST AND (ANDROID OR QT_FORCE_BUILTIN_TESTDATA)
DEFINES
QUICK_TEST_SOURCE_DIR=":/"
)
@@ -774,7 +776,7 @@ function(qt_internal_add_test name)
endif()
endif()
- if(ANDROID OR IOS OR WASM OR INTEGRITY OR arg_BUILTIN_TESTDATA)
+ if(ANDROID OR IOS OR WASM OR INTEGRITY OR arg_BUILTIN_TESTDATA OR QT_FORCE_BUILTIN_TESTDATA)
set(builtin_testdata TRUE)
endif()
diff --git a/cmake/configure-cmake-mapping.md b/cmake/configure-cmake-mapping.md
index d504bd8d4b..bc52065903 100644
--- a/cmake/configure-cmake-mapping.md
+++ b/cmake/configure-cmake-mapping.md
@@ -97,7 +97,7 @@ The following table describes the mapping of configure options to CMake argument
| -skip <repo>,...,<repo_n> | -DBUILD_<repo>=OFF | |
| -skip-tests <repo>,...,<repo_n> | -DQT_BUILD_TESTS_PROJECT_<repo>=OFF | |
| -skip-examples <repo>,...,<repo_n> | -DQT_BUILD_EXAMPLES_PROJECT_<repo>=OFF | |
-| -submodules <repo>,...,<repo_n> | -DQT_BUILD_SUBMODULES=<repo>;...;<repo> | |
+| -submodules <repo>,...,<repo_n> | -DQT_BUILD_SUBMODULES=<repo>;...;<repo> | |
| -make <part> | -DQT_BUILD_TESTS=ON | A way to turn on tools explicitly is missing. If tests/examples |
| | -DQT_BUILD_EXAMPLES=ON | are enabled, you can disable their building as part of the |
| | | 'all' target by also passing -DQT_BUILD_TESTS_BY_DEFAULT=OFF or |
@@ -145,7 +145,8 @@ The following table describes the mapping of configure options to CMake argument
| -opengl <api> | -DINPUT_opengl=<api> | |
| -opengles3 | -DFEATURE_opengles3=ON | |
| -egl | -DFEATURE_egl=ON | |
-| -qpa <name> | -DQT_QPA_DEFAULT_PLATFORM=<name> | |
+| -qpa <name>;...;<name_n> | -DQT_QPA_PLATFORMS=<name>;...;<name_n> | |
+| -default-qpa <name> | -DQT_QPA_DEFAULT_PLATFORM=<name> | |
| -xcb-xlib | -DFEATURE_xcb_xlib=ON | |
| -direct2d | -DFEATURE_direct2d=ON | |
| -directfb | -DFEATURE_directfb=ON | |
diff --git a/cmake/visionos/Info.plist.app.in b/cmake/visionos/Info.plist.app.in
index 7aa4698649..984b7aa10b 100644
--- a/cmake/visionos/Info.plist.app.in
+++ b/cmake/visionos/Info.plist.app.in
@@ -38,5 +38,13 @@
<array>
<string>XROS</string>
</array>
+
+ <key>UIApplicationSceneManifest</key>
+ <dict>
+ <key>UIApplicationSupportsMultipleScenes</key>
+ <true/>
+ <key>UISceneConfigurations</key>
+ <dict/>
+ </dict>
</dict>
</plist>
diff --git a/config_help.txt b/config_help.txt
index 13fc516da5..263195d7fd 100644
--- a/config_help.txt
+++ b/config_help.txt
@@ -290,8 +290,10 @@ Gui, printing, widget options:
-opengles3 ........... Enable OpenGL ES 3.x support instead of ES 2.x [auto]
-egl ................. Enable EGL support [auto]
- -qpa <name> .......... Select default QPA backend(s) (e.g., xcb, cocoa, windows)
- A prioritized list separated by semi-colons.
+ -qpa <qpa1>[;<qpa2>] . Select supported QPA backend(s) (e.g., xcb, cocoa,
+ windows). A list separated by semi-colons.
+ -default-qpa <name> .. Select the default QPA backend (e.g., xcb, cocoa,
+ windows).
-xcb-xlib............. Enable Xcb-Xlib support [auto]
Platform backends:
diff --git a/configure.cmake b/configure.cmake
index 4cf9ad6741..b91260015f 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -203,8 +203,16 @@ if(NOT QT_CONFIGURE_RUNNING)
qt_evaluate_feature(use_gold_linker)
qt_evaluate_feature(use_lld_linker)
qt_evaluate_feature(use_mold_linker)
+
+ qt_run_linker_version_script_support()
endif()
+qt_feature("version_tagging"
+ PUBLIC
+ AUTODETECT TRUE
+ CONDITION TEST_ld_version_script OR APPLE OR WIN32
+)
+qt_feature_definition("version_tagging" "QT_NO_VERSION_TAGGING" NEGATE)
#### Tests
@@ -626,7 +634,7 @@ qt_feature("force_asserts" PUBLIC
)
qt_feature("framework" PUBLIC
LABEL "Build Apple Frameworks"
- AUTODETECT BUILD_SHARED_LIBS
+ AUTODETECT ON
CONDITION APPLE
)
qt_feature_definition("framework" "QT_MAC_FRAMEWORK_BUILD")
@@ -1018,6 +1026,11 @@ qt_feature("qreal"
)
qt_feature_definition("qreal" "QT_COORD_TYPE" VALUE "${QT_COORD_TYPE}")
qt_feature_definition("qreal" "QT_COORD_TYPE_STRING" VALUE "\"${QT_COORD_TYPE}\"")
+if(QT_COORD_TYPE STREQUAL "double")
+ qt_feature_definition("qreal" "QT_COORD_TYPE_IS_DOUBLE" VALUE "1")
+elseif(QT_COORD_TYPE STREQUAL "float")
+ qt_feature_definition("qreal" "QT_COORD_TYPE_IS_FLOAT" VALUE "1")
+endif()
qt_feature("gui" PRIVATE
LABEL "Qt Gui"
)
diff --git a/doc/README b/doc/README
deleted file mode 100644
index ed8410db71..0000000000
--- a/doc/README
+++ /dev/null
@@ -1,109 +0,0 @@
-Qt 5 Documentation
-==================
-
-New in Qt 5.0, each module has its own documentation package. The documentation
-resides in the module sources as well as the configuration files needed to build
-the module documentation. The main Qt 5.0 Reference Documentation resides in the
-qtdoc repository.
-
-There are two ways to build Qt documentation:
-* run "make docs" in qt5/ or in the repositories
-* run the QDoc tool for each module
-
-
-Running "make docs"
-===================
-
-To build the documentation using Makefiles, qtbase needs to be compiled and
-installed.
-
-Running qmake will create make targets to build the documentation:
-* html_docs - builds only the HTML documentation
-* qch_docs - packages the HTML documentation into QCH files for Qt Creator and
- Qt Assistant.
-* docs - runs html_docs and qch_docs
-
-Note: qch_docs needs qhelpgenerator to package the documentation. qhelpgenerator
-is in the qttools repository.
-
-These make targets use qmake's QT_INSTALL_DOCS variable as the output directory.
-Running "qmake -query" will list the directory set to QT_INSTALL_DOCS.
-
-To create all of the modules' documentation, run "make docs" in the
-qt5 directory:
- $> make docs # builds the bundled modules' documentation
-
-It is also possible to build only a small subset of the documentation by using
-make:
- $> cd qtbase
- $> make docs # builds the documentation for modules in qtbase
-
- $> cd qtbase/src/sql
- $> make docs # builds only the Qt SQL documentation
-
-
-Running QDoc
-============
-
-QDoc is the tool for generating Qt documentation and is located in qtbase.
-The simplest way to compile QDoc is to compile qtbase or only the tools in
-qtbase.
-
- $> cd qtbase/src
- $> make sub-tools # compiles QDoc
-
-Each module has a QDoc configuration file (.qdocconf). To build a module's
-documentation, run the "qdoc" binary and pass the qdocconf file as a parameter.
-A mandatory "outputdir" must be specified.
-
- $> qdoc doc/config/qtdoc.qdocconf -outputdir html
-
- Note that QDoc will delete the contents of the "html" output directory.
-
-Packaging the Documentation
-===========================
-
-To package the documentation, the HTML files must be compiled
-into a QCH file (.qch).
-
-Required binaries:
- * assistant - found in qttools
- * qhelpgenerator - found in qttools
-
-To compile the qch file for each module, first enter the output directory that
-contains the .qhp file and generate the QCH file.
-
- $> cd qtbase/doc/qtdoc #the default path for QT_INSTALL_DOCS for qtdoc
- $> qhelpgenerator qtdoc.qhp #creates the QCH file called qtdoc.qch
-
-The QCH file can then be loaded in Qt Assistant or Qt Creator. For Qt Assistant,
-the QCH file can be registered to automatically load it.
-
- $> assistant -register qtdoc.qch #to automatically load the documentation
-
-
-Global Files
-============
-
-The qtbase/doc/global directory contains various files used by the modules to
-build the documentation. These include macros, stylesheets, and images for
-displaying documentation.
-
-To include these files in a qdocconf, add the following to a qdocconf file:
-
- include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
-
-
-Documentation Structure
-=======================
-For a typical module, the documentation will reside in the source directory.
-The examples and the example documentation are in the "examples" directory.
-
- qtbase/src/sql/doc/src #Qt SQL's documentation
- qtbase/examples/sql #Qt SQL's examples
-
-More Information
-================
-
-For more information about Qt 5's documentation, refer to the Qt Project wiki:
-http://wiki.qt.io/Qt5DocumentationProject
diff --git a/doc/global/externalsites/external-resources.qdoc b/doc/global/externalsites/external-resources.qdoc
index 272c73b3b0..0dcea08a53 100644
--- a/doc/global/externalsites/external-resources.qdoc
+++ b/doc/global/externalsites/external-resources.qdoc
@@ -33,6 +33,10 @@
\title Android: Tagged Pointers
*/
/*!
+ \externalpage https://developer.android.com/build/configure-app-module
+ \title Android: Configure the app module
+*/
+/*!
\externalpage https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl
\title iOS: canOpenURL:
*/
diff --git a/doc/global/externalsites/rfc.qdoc b/doc/global/externalsites/rfc.qdoc
index b6646f453c..ceab869bfd 100644
--- a/doc/global/externalsites/rfc.qdoc
+++ b/doc/global/externalsites/rfc.qdoc
@@ -125,6 +125,11 @@
*/
/*!
+ \externalpage https://datatracker.ietf.org/doc/html/rfc6698
+ \title RFC 6698
+*/
+
+/*!
\externalpage https://datatracker.ietf.org/doc/html/rfc7049
\title RFC 7049
*/
@@ -150,6 +155,11 @@
*/
/*!
+ \externalpage https://datatracker.ietf.org/doc/html/rfc7858
+ \title RFC 7858
+*/
+
+/*!
\externalpage https://datatracker.ietf.org/doc/html/rfc8018#section-5.1
\title RFC 8018, section 5.1
*/
diff --git a/doc/global/macros.qdocconf b/doc/global/macros.qdocconf
index 93c6fa0ab0..450ded322a 100644
--- a/doc/global/macros.qdocconf
+++ b/doc/global/macros.qdocconf
@@ -56,20 +56,28 @@ macro.examplecategory = "\\meta category {\1}\n\\ingroup category \1"
# Macros for product names, sorted in alphabetic order
+macro.B2Q = "Boot to Qt"
+macro.B2QSS = "Boot to Qt Software Stack"
+macro.B2QST = "Boot to Qt Startup Screen"
+macro.IFW = "Qt Installer Framework"
macro.QA = "Qt Assistant"
macro.QB = "Qt Bridge"
macro.QBF = "Qt Bridge for Figma"
macro.QBPS = "Qt Bridge for Adobe Photoshop"
macro.QBSK = "Qt Bridge for Sketch"
macro.QBXD = "Qt Bridge for Adobe XD"
+macro.QC = "Qt Creator"
macro.QD = "Qt Widgets Designer"
macro.QDS = "Qt Design Studio"
macro.QDV = "Qt Design Viewer"
+macro.QfP = "Qt for Python"
macro.QL = "Qt Linguist"
macro.QMCU = "Qt for MCUs"
+macro.QMLP = "QML Profiler"
macro.QMLLS = "QML Language Server"
macro.QMT = "Qt Maintenance Tool"
macro.QOI = "Qt Online Installer"
+macro.QQEM = "Qt Quick Effect Maker"
macro.QQV = "Qt QML Viewer"
macro.QtAA = "Qt for Android Automotive"
macro.QUL = "Qt Quick Ultralite"
diff --git a/examples/corelib/platform/androidnotifier/androidnotifier.pro b/examples/corelib/platform/androidnotifier/androidnotifier.pro
index 6ac4c69eb3..7e5b845e10 100644
--- a/examples/corelib/platform/androidnotifier/androidnotifier.pro
+++ b/examples/corelib/platform/androidnotifier/androidnotifier.pro
@@ -1,5 +1,4 @@
-QT += core gui
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+QT += core gui widgets
QT += core-private # For Notification permission request
SOURCES += \
diff --git a/examples/widgets/doc/src/simpletreemodel.qdoc b/examples/widgets/doc/src/simpletreemodel.qdoc
index aa12a9585f..d8e5a6faa8 100644
--- a/examples/widgets/doc/src/simpletreemodel.qdoc
+++ b/examples/widgets/doc/src/simpletreemodel.qdoc
@@ -295,14 +295,14 @@
We begin with a text file in the following format:
\code
- Getting Started How to familiarize yourself with Qt Designer
- Launching Designer Running the Qt Designer application
- The User Interface How to interact with Qt Designer
+ Getting Started How to familiarize yourself with Qt Widgets Designer
+ Launching Designer Running the Qt Widgets Designer application
+ The User Interface How to interact with Qt Widgets Designer
\endcode
\dots
\code
Connection Editing Mode Connecting widgets together with signals and slots
- Connecting Objects Making connections in Qt Designer
+ Connecting Objects Making connections in Qt Widgets Designer
Editing Connections Changing existing connections
\endcode
diff --git a/examples/widgets/gallery/main.cpp b/examples/widgets/gallery/main.cpp
index cfac821209..2677b3708c 100644
--- a/examples/widgets/gallery/main.cpp
+++ b/examples/widgets/gallery/main.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
+#include <QStyleHints>
#include "widgetgallery.h"
diff --git a/examples/widgets/gallery/widgetgallery.cpp b/examples/widgets/gallery/widgetgallery.cpp
index 2de46419d9..d38dcbd5e8 100644
--- a/examples/widgets/gallery/widgetgallery.cpp
+++ b/examples/widgets/gallery/widgetgallery.cpp
@@ -26,6 +26,7 @@
#include <QSpinBox>
#include <QStandardItemModel>
#include <QStyle>
+#include <QStyleHints>
#include <QStyleFactory>
#include <QTextBrowser>
#include <QTreeView>
@@ -135,6 +136,21 @@ WidgetGallery::WidgetGallery(QWidget *parent)
auto styleLabel = createWidget1<QLabel>(tr("&Style:"), "styleLabel");
styleLabel->setBuddy(styleComboBox);
+ auto colorSchemeComboBox = createWidget<QComboBox>("colorSchemeComboBox");
+ colorSchemeComboBox->addItem(tr("Auto"));
+ colorSchemeComboBox->addItem(tr("Light"));
+ colorSchemeComboBox->addItem(tr("Dark"));
+ // override the color scheme to dark
+ qApp->styleHints()->setColorScheme(Qt::ColorScheme::Dark);
+ colorSchemeComboBox->setCurrentIndex(2);
+
+ auto colorSchemeLabel = createWidget1<QLabel>(tr("&Color Scheme:"), "colorSchemeLabel");
+ colorSchemeLabel->setBuddy(colorSchemeComboBox);
+
+ connect(colorSchemeComboBox, &QComboBox::currentIndexChanged, this, [](int index){
+ QGuiApplication::styleHints()->setColorScheme(static_cast<Qt::ColorScheme>(index));
+ });
+
auto helpLabel = createWidget1<QLabel>(tr("Press F1 over a widget to see Documentation"), "helpLabel");
auto disableWidgetsCheckBox = createWidget1<QCheckBox>(tr("&Disable widgets"), "disableWidgetsCheckBox");
@@ -156,8 +172,12 @@ WidgetGallery::WidgetGallery(QWidget *parent)
simpleInputWidgetsGroupBox, &QWidget::setDisabled);
auto topLayout = new QHBoxLayout;
- topLayout->addWidget(styleLabel);
- topLayout->addWidget(styleComboBox);
+ auto appearanceLayout = new QGridLayout;
+ appearanceLayout->addWidget(styleLabel, 0, 0);
+ appearanceLayout->addWidget(styleComboBox, 0, 1);
+ appearanceLayout->addWidget(colorSchemeLabel, 1, 0);
+ appearanceLayout->addWidget(colorSchemeComboBox, 1, 1);
+ topLayout->addLayout(appearanceLayout);
topLayout->addStretch(1);
topLayout->addWidget(helpLabel);
topLayout->addStretch(1);
diff --git a/examples/widgets/itemviews/editabletreemodel/default.txt b/examples/widgets/itemviews/editabletreemodel/default.txt
index 2b2fb579ae..c3ea35257c 100644
--- a/examples/widgets/itemviews/editabletreemodel/default.txt
+++ b/examples/widgets/itemviews/editabletreemodel/default.txt
@@ -1,6 +1,6 @@
-Getting Started How to familiarize yourself with Qt Designer
- Launching Designer Running the Qt Designer application
- The User Interface How to interact with Qt Designer
+Getting Started How to familiarize yourself with Qt Widgets Designer
+ Launching Designer Running the Qt Widgets Designer application
+ The User Interface How to interact with Qt Widgets Designer
Designing a Component Creating a GUI for your application
Creating a Dialog How to create a dialog
@@ -16,7 +16,7 @@ Using a Component in Your Application Generating code from forms
A Dialog Without Auto-Connect How to connect widgets without a naming scheme
A Dialog With Auto-Connect Using automatic connections
-Form Editing Mode How to edit a form in Qt Designer
+Form Editing Mode How to edit a form in Qt Widgets Designer
Managing Forms Loading and saving forms
Editing a Form Basic editing techniques
The Property Editor Changing widget properties
@@ -36,5 +36,5 @@ Using Containers How to group widgets together
Toolbox Widgets QToolBox
Connection Editing Mode Connecting widgets together with signals and slots
- Connecting Objects Making connections in Qt Designer
+ Connecting Objects Making connections in Qt Widgets Designer
Editing Connections Changing existing connections
diff --git a/examples/widgets/itemviews/simpletreemodel/default.txt b/examples/widgets/itemviews/simpletreemodel/default.txt
index 2b2fb579ae..c3ea35257c 100644
--- a/examples/widgets/itemviews/simpletreemodel/default.txt
+++ b/examples/widgets/itemviews/simpletreemodel/default.txt
@@ -1,6 +1,6 @@
-Getting Started How to familiarize yourself with Qt Designer
- Launching Designer Running the Qt Designer application
- The User Interface How to interact with Qt Designer
+Getting Started How to familiarize yourself with Qt Widgets Designer
+ Launching Designer Running the Qt Widgets Designer application
+ The User Interface How to interact with Qt Widgets Designer
Designing a Component Creating a GUI for your application
Creating a Dialog How to create a dialog
@@ -16,7 +16,7 @@ Using a Component in Your Application Generating code from forms
A Dialog Without Auto-Connect How to connect widgets without a naming scheme
A Dialog With Auto-Connect Using automatic connections
-Form Editing Mode How to edit a form in Qt Designer
+Form Editing Mode How to edit a form in Qt Widgets Designer
Managing Forms Loading and saving forms
Editing a Form Basic editing techniques
The Property Editor Changing widget properties
@@ -36,5 +36,5 @@ Using Containers How to group widgets together
Toolbox Widgets QToolBox
Connection Editing Mode Connecting widgets together with signals and slots
- Connecting Objects Making connections in Qt Designer
+ Connecting Objects Making connections in Qt Widgets Designer
Editing Connections Changing existing connections
diff --git a/licenseRule.json b/licenseRule.json
index 3a34a4830c..4683dc7b23 100644
--- a/licenseRule.json
+++ b/licenseRule.json
@@ -22,7 +22,7 @@
"file type" : "examples and snippets",
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
},
- "tests/auto/cmake/test_plugin_shared_static_flavor.cmake" : {
+ "tests/auto/cmake/test_plugin_shared_static_flavor\\.cmake" : {
"comment" : "Exception. This is a test file.",
"file type" : "test",
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
@@ -45,7 +45,7 @@
"file type" : "examples and snippets",
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
},
- "tests/auto/tools/uic/baseline/config.ui.py" : {
+ "tests/auto/tools/uic/baseline/config\\.ui\\.py" : {
"comment" : "This is a test file",
"file type" : "test",
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
@@ -61,7 +61,7 @@
"file type" : "documentation",
"spdx" : ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
},
- "tests/auto/corelib/mimetypes/qmimedatabase/test.txt" : {
+ "tests/auto/corelib/mimetypes/qmimedatabase/test\\.txt" : {
"comment" : "Exception. This is a test file",
"file type" : "test",
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
@@ -94,12 +94,12 @@
"file type" : "module and plugin",
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
},
- "src/dbus/dbus_minimal_p.h" : {
+ "src/dbus/dbus_minimal_p\\.h" : {
"comment" : "Exception",
"file type" : "module and plugin",
"spdx" : ["AFL-2.1 OR GPL-2.0-or-later"]
},
- "src/entrypoint/qtentrypoint_win.cpp" : {
+ "src/entrypoint/qtentrypoint_win\\.cpp" : {
"comment" : "Exception: https://doc.qt.io/qt-6/qtentrypoint.html",
"file type" : "module and plugin",
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
@@ -109,6 +109,16 @@
"file type" : "module and plugin",
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
},
+ "src/corelib/(time|text)/q.*_data_p\\.h" : {
+ "comment" : "generated from Unicode CLDR data",
+ "file type" : "module and plugin",
+ "spdx" : ["Unicode-3.0"]
+ },
+ "src/corelib/text/qunicodetables.*" : {
+ "comment" : "Contains data extracted from UCD, under Unicode-DFS-2016",
+ "file type" : "module and plugin",
+ "spdx" : ["Unicode-DFS-2016"]
+ },
"src/tools/" : {
"comment" : "Default",
"file type" : "tools and utils",
@@ -119,12 +129,12 @@
"file type" : "test",
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
},
- "cmake/qbatchedtestrunner.in.cpp" : {
+ "cmake/qbatchedtestrunner\\.in\\.cpp" : {
"comment" : "Compiled into internal tests if QT_BUILD_TESTS_BATCHED is enabled.",
"file type" : "test",
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
},
- "tests/auto/testlib/selftests/catch_p_p.h" : {
+ "tests/auto/testlib/selftests/catch_p_p\\.h" : {
"comment" : "Exception",
"file type" : "test",
"spdx" : ["BSL-1.0"]
@@ -134,17 +144,17 @@
"file type" : "examples and snippets",
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
},
- "config.tests/" : {
+ "config\\.tests/" : {
"comment" : "Default",
"file type" : "build system",
"spdx" : ["BSD-3-Clause"]
},
- "config.tests/no_direct_extern_access/" : {
+ "config\\.tests/no_direct_extern_access/" : {
"comment" : "Exception",
"file type" : "build system",
"spdx" : ["MIT"]
},
- "src/corelib/Qt6CoreResourceInit.in.cpp" : {
+ "src/corelib/Qt6CoreResourceInit\\.in\\.cpp" : {
"comment" : "Helper file statically compiled into user executables",
"file type" : "module and plugin",
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
@@ -169,7 +179,7 @@
"file type" : "util",
"spdx" : ["LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only"]
},
- "util/glgen/qopenglextensions.(h|cpp).header" : {
+ "util/glgen/qopenglextensions\\.(h|cpp)\\.header" : {
"comment" : "Exception, for file generation",
"file type" : "util",
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
diff --git a/qt_cmdline.cmake b/qt_cmdline.cmake
index ce7919709e..0347f86eef 100644
--- a/qt_cmdline.cmake
+++ b/qt_cmdline.cmake
@@ -11,8 +11,6 @@ qt_commandline_subconfig(src/printsupport)
qt_commandline_subconfig(src/plugins/sqldrivers)
qt_commandline_subconfig(src/testlib)
qt_commandline_subconfig(src/tools)
-# no-prefix needs to be placed before prefix
-qt_commandline_option(no-prefix TYPE void)
qt_commandline_option(prefix TYPE string)
qt_commandline_option(extprefix TYPE string)
qt_commandline_option(archdatadir TYPE string)
@@ -54,7 +52,6 @@ qt_commandline_option(dbus-linked TYPE void NAME dbus VALUE linked)
qt_commandline_option(dbus-runtime TYPE void NAME dbus VALUE runtime)
qt_commandline_option(debug TYPE void)
qt_commandline_option(debug-and-release TYPE boolean NAME debug_and_release)
-qt_commandline_option(developer-build TYPE void)
qt_commandline_option(device TYPE string)
qt_commandline_option(device-option TYPE addString)
qt_commandline_option(f16c TYPE boolean)
diff --git a/src/3rdparty/harfbuzz-ng/CMakeLists.txt b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
index 96e21941b2..1fd404ba74 100644
--- a/src/3rdparty/harfbuzz-ng/CMakeLists.txt
+++ b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
@@ -56,6 +56,7 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-subset-cff1.cc
src/hb-subset-cff2.cc
src/hb-subset-input.cc
+ src/hb-subset-instancer-iup.cc src/hb-subset-instancer-iup.hh
src/hb-subset-instancer-solver.cc
src/hb-subset-plan.cc
src/hb-subset-plan-member-list.hh
diff --git a/src/3rdparty/harfbuzz-ng/README.md b/src/3rdparty/harfbuzz-ng/README.md
index 33165091a8..da4de65cf0 100644
--- a/src/3rdparty/harfbuzz-ng/README.md
+++ b/src/3rdparty/harfbuzz-ng/README.md
@@ -2,7 +2,7 @@
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
-[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=harfbuzz/harfbuzz&amp;utm_campaign=Badge_Grade)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
@@ -72,9 +72,9 @@ For a comparison of old vs new HarfBuzz memory consumption see [this][10].
## Name
-HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”,
-transliterated using the Latin script. It sports a second meaning, but that
-ain’t translatable.
+HarfBuzz (حرف‌باز) is the literal Persian translation of “[OpenType][1]”,
+transliterated using the Latin script. It also means "talkative" or
+"glib" (also a nod to the GNOME project where HarfBuzz originates from).
> Background: Originally there was this font format called TrueType. People and
> companies started calling their type engines all things ending in Type:
diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json
index f45251defe..8b862c418a 100644
--- a/src/3rdparty/harfbuzz-ng/qt_attribution.json
+++ b/src/3rdparty/harfbuzz-ng/qt_attribution.json
@@ -7,8 +7,8 @@
"Description": "HarfBuzz is an OpenType text shaping engine.",
"Homepage": "http://harfbuzz.org",
- "Version": "8.3.0",
- "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/8.3.0",
+ "Version": "8.4.0",
+ "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/8.4.0",
"License": "MIT License",
"LicenseId": "MIT",
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
index b632a1d9eb..623775a771 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
@@ -68,7 +68,7 @@ public:
hb_font_t *font;
unsigned int palette_index;
hb_color_t foreground;
- VarStoreInstancer &instancer;
+ ItemVarStoreInstancer &instancer;
hb_map_t current_glyphs;
hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
@@ -80,7 +80,7 @@ public:
hb_font_t *font_,
unsigned int palette_,
hb_color_t foreground_,
- VarStoreInstancer &instancer_) :
+ ItemVarStoreInstancer &instancer_) :
base (base_),
funcs (funcs_),
data (data_),
@@ -245,7 +245,7 @@ struct Variable
{ value.closurev1 (c); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
@@ -270,7 +270,7 @@ struct Variable
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, varIdxBase, instancer);
}
@@ -305,7 +305,7 @@ struct NoVariable
{ value.closurev1 (c); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
return_trace (value.subset (c, instancer, varIdxBase));
@@ -325,7 +325,7 @@ struct NoVariable
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
}
@@ -348,7 +348,7 @@ struct ColorStop
{ c->add_palette_index (paletteIndex); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -374,7 +374,7 @@ struct ColorStop
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *out,
uint32_t varIdx,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
out->offset = stopOffset.to_float(instancer (varIdx, 0));
out->color = c->get_color (paletteIndex,
@@ -410,7 +410,7 @@ struct ColorLine
}
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
@@ -439,7 +439,7 @@ struct ColorLine
unsigned int start,
unsigned int *count,
hb_color_stop_t *color_stops,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
unsigned int len = stops.len;
@@ -543,7 +543,7 @@ struct Affine2x3
}
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -588,7 +588,7 @@ struct PaintColrLayers
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer HB_UNUSED) const
+ const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -620,7 +620,7 @@ struct PaintSolid
{ c->add_palette_index (paletteIndex); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -669,7 +669,7 @@ struct PaintLinearGradient
{ (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -736,7 +736,7 @@ struct PaintRadialGradient
{ (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -803,7 +803,7 @@ struct PaintSweepGradient
{ (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -863,7 +863,7 @@ struct PaintGlyph
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -906,7 +906,7 @@ struct PaintColrGlyph
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer HB_UNUSED) const
+ const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -936,7 +936,7 @@ struct PaintTransform
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -975,7 +975,7 @@ struct PaintTranslate
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1024,7 +1024,7 @@ struct PaintScale
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1073,7 +1073,7 @@ struct PaintScaleAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1132,7 +1132,7 @@ struct PaintScaleUniform
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1176,7 +1176,7 @@ struct PaintScaleUniformAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1232,7 +1232,7 @@ struct PaintRotate
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1276,7 +1276,7 @@ struct PaintRotateAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1332,7 +1332,7 @@ struct PaintSkew
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1381,7 +1381,7 @@ struct PaintSkewAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1440,7 +1440,7 @@ struct PaintComposite
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -1491,7 +1491,7 @@ struct ClipBoxFormat1
return_trace (c->check_struct (this));
}
- void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
+ void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
clip_box.xMin = xMin;
clip_box.yMin = yMin;
@@ -1500,7 +1500,7 @@ struct ClipBoxFormat1
}
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1533,7 +1533,7 @@ struct ClipBoxFormat1
struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
{
- void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
+ void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
{
value.get_clip_box(clip_box, instancer);
if (instancer)
@@ -1549,7 +1549,7 @@ struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
struct ClipBox
{
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
switch (u.format) {
@@ -1572,7 +1572,7 @@ struct ClipBox
}
bool get_extents (hb_glyph_extents_t *extents,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
ClipBoxData clip_box;
switch (u.format) {
@@ -1608,7 +1608,7 @@ struct ClipRecord
bool subset (hb_subset_context_t *c,
const void *base,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
@@ -1625,7 +1625,7 @@ struct ClipRecord
bool get_extents (hb_glyph_extents_t *extents,
const void *base,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
return (base+clipBox).get_extents (extents, instancer);
}
@@ -1642,7 +1642,7 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList
{
unsigned serialize_clip_records (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
const hb_set_t& gids,
const hb_map_t& gid_offset_map) const
{
@@ -1695,7 +1695,7 @@ struct ClipList
}
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
@@ -1735,7 +1735,7 @@ struct ClipList
bool
get_extents (hb_codepoint_t gid,
hb_glyph_extents_t *extents,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
auto *rec = clips.as_array ().bsearch (gid);
if (rec)
@@ -1855,7 +1855,7 @@ struct BaseGlyphPaintRecord
bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
const void* src_base, hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SERIALIZE (this);
auto *out = s->embed (this);
@@ -1884,7 +1884,7 @@ struct BaseGlyphPaintRecord
struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
{
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
@@ -1916,7 +1916,7 @@ struct LayerList : Array32OfOffset32To<Paint>
{ return this+(*this)[i]; }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
@@ -2206,7 +2206,7 @@ struct COLR
auto snap = c->serializer->snapshot ();
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
- VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
+ ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
varIdxMap ? &(this+varIdxMap) : nullptr,
c->plan->normalized_coords.as_array ());
@@ -2250,7 +2250,7 @@ struct COLR
if (version != 1)
return false;
- VarStoreInstancer instancer (&(this+varStore),
+ ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
@@ -2301,7 +2301,7 @@ struct COLR
bool get_clip (hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
- const VarStoreInstancer instancer) const
+ const ItemVarStoreInstancer instancer) const
{
return (this+clipList).get_extents (glyph,
extents,
@@ -2312,7 +2312,7 @@ struct COLR
bool
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
{
- VarStoreInstancer instancer (&(this+varStore),
+ ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
@@ -2327,7 +2327,7 @@ struct COLR
{
// COLRv1 glyph
- VarStoreInstancer instancer (&(this+varStore),
+ ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
@@ -2413,7 +2413,7 @@ struct COLR
Offset32To<LayerList> layerList;
Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL)
Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL)
- Offset32To<VariationStore> varStore;
+ Offset32To<ItemVariationStore> varStore;
public:
DEFINE_SIZE_MIN (14);
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
index 14a9b5e5cd..317b96c714 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
@@ -189,7 +189,7 @@ struct CaretValueFormat3
friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
@@ -251,7 +251,7 @@ struct CaretValue
hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
@@ -316,7 +316,7 @@ struct LigGlyph
unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -372,7 +372,7 @@ struct LigCaretList
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -609,7 +609,7 @@ struct GDEFVersion1_2
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
@@ -663,21 +663,16 @@ struct GDEFVersion1_2
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- out->version.major = version.major;
- out->version.minor = version.minor;
- bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
- bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
- bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
-
- bool subset_markglyphsetsdef = false;
+ // Push var store first (if it's needed) so that it's last in the
+ // serialization order. Some font consumers assume that varstore runs to
+ // the end of the GDEF table.
+ // See: https://github.com/harfbuzz/harfbuzz/issues/4636
auto snapshot_version0 = c->serializer->snapshot ();
- if (version.to_int () >= 0x00010002u)
- {
- if (unlikely (!c->serializer->embed (markGlyphSetsDef))) return_trace (false);
- subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
- }
+ if (unlikely (version.to_int () >= 0x00010002u && !c->serializer->embed (markGlyphSetsDef)))
+ return_trace (false);
bool subset_varstore = false;
+ unsigned varstore_index = (unsigned) -1;
auto snapshot_version2 = c->serializer->snapshot ();
if (version.to_int () >= 0x00010003u)
{
@@ -690,35 +685,58 @@ struct GDEFVersion1_2
{
item_variations_t item_vars;
if (item_vars.instantiate (this+varStore, c->plan, true, true,
- c->plan->gdef_varstore_inner_maps.as_array ()))
+ c->plan->gdef_varstore_inner_maps.as_array ())) {
subset_varstore = out->varStore.serialize_serialize (c->serializer,
item_vars.has_long_word (),
c->plan->axis_tags,
item_vars.get_region_list (),
item_vars.get_vardata_encodings ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
remap_varidx_after_instantiation (item_vars.get_varidx_map (),
c->plan->layout_variation_idx_delta_map);
}
}
else
+ {
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
+ }
+
+ out->version.major = version.major;
+ out->version.minor = version.minor;
+
+ if (!subset_varstore && version.to_int () >= 0x00010002u) {
+ c->serializer->revert (snapshot_version2);
}
+ bool subset_markglyphsetsdef = false;
+ if (version.to_int () >= 0x00010002u)
+ {
+ subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+ }
if (subset_varstore)
{
out->version.minor = 3;
c->plan->has_gdef_varstore = true;
} else if (subset_markglyphsetsdef) {
- out->version.minor = 2;
- c->serializer->revert (snapshot_version2);
+ out->version.minor = 2;
} else {
out->version.minor = 0;
c->serializer->revert (snapshot_version0);
}
+ bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+ bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+ bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+ if (subset_varstore && varstore_index != (unsigned) -1) {
+ c->serializer->repack_last(varstore_index);
+ }
+
return_trace (subset_glyphclassdef || subset_attachlist ||
subset_ligcaretlist || subset_markattachclassdef ||
(out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
@@ -884,14 +902,14 @@ struct GDEF
default: return false;
}
}
- const VariationStore &get_var_store () const
+ const ItemVariationStore &get_var_store () const
{
switch (u.version.major) {
- case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+ case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(ItemVariationStore);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore;
#endif
- default: return Null(VariationStore);
+ default: return Null(ItemVariationStore);
}
}
@@ -1011,9 +1029,9 @@ struct GDEF
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
if (!has_var_store ()) return;
- const VariationStore &var_store = get_var_store ();
+ const ItemVariationStore &var_store = get_var_store ();
float *store_cache = var_store.create_cache ();
-
+
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
for (unsigned idx : layout_variation_indices->iter ())
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
index dd02da887d..9c805b39a1 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -324,17 +324,8 @@ struct PairPosFormat2_4 : ValueBase
}
}
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting (glyph_map)
- ;
-
- out->coverage.serialize_serialize (c->serializer, it);
- return_trace (out->class1Count && out->class2Count && bool (it));
+ bool ret = out->coverage.serialize_subset(c, coverage, this);
+ return_trace (out->class1Count && out->class2Count && ret);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
index 17f57db1f5..9442cc1cc5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
@@ -116,7 +116,7 @@ struct ValueFormat : HBUINT16
if (!use_x_device && !use_y_device) return ret;
- const VariationStore &store = c->var_store;
+ const ItemVariationStore &store = c->var_store;
auto *cache = c->var_store_cache;
/* pixel -> fractional pixel */
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
index 60858a5a58..5c0ecd5133 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
@@ -240,7 +240,8 @@ struct CompositeGlyphRecord
}
if (is_anchored ()) tx = ty = 0;
- trans.init ((float) tx, (float) ty);
+ /* set is_end_point flag to true, used by IUP delta optimization */
+ trans.init ((float) tx, (float) ty, true);
{
const F2DOT14 *points = (const F2DOT14 *) p;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
index 5ea611948f..69a0b625c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
@@ -103,6 +103,9 @@ struct Glyph
}
}
+ bool is_composite () const
+ { return type == COMPOSITE; }
+
bool get_all_points_without_var (const hb_face_t *face,
contour_point_vector_t &points /* OUT */) const
{
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
index d0a5a132f0..f157bf0020 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
@@ -38,7 +38,7 @@ _write_loca (IteratorIn&& it,
unsigned padded_size = *it++;
offset += padded_size;
- DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size);
+ DEBUG_MSG (SUBSET, nullptr, "loca entry gid %" PRIu32 " offset %u padded-size %u", gid, offset, padded_size);
value = offset >> right_shift;
*dest++ = value;
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
index 9cf845a82d..da6378820b 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
@@ -134,20 +134,23 @@ struct ClassDef : public OT::ClassDef
struct class_def_size_estimator_t
{
+ // TODO(garretrieger): update to support beyond64k coverage/classdef tables.
+ constexpr static unsigned class_def_format1_base_size = 6;
+ constexpr static unsigned class_def_format2_base_size = 4;
+ constexpr static unsigned coverage_base_size = 4;
+ constexpr static unsigned bytes_per_range = 6;
+ constexpr static unsigned bytes_per_glyph = 2;
+
template<typename It>
class_def_size_estimator_t (It glyph_and_class)
- : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class ()
+ : num_ranges_per_class (), glyphs_per_class ()
{
- unsigned last_gid = (unsigned) -1;
+ reset();
for (auto p : + glyph_and_class)
{
unsigned gid = p.first;
unsigned klass = p.second;
- if (last_gid != (unsigned) -1 && gid != last_gid + 1)
- gids_consecutive = false;
- last_gid = gid;
-
hb_set_t* glyphs;
if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
glyphs->add (gid);
@@ -177,28 +180,54 @@ struct class_def_size_estimator_t
}
}
- // Incremental increase in the Coverage and ClassDef table size
- // (worst case) if all glyphs associated with 'klass' were added.
- unsigned incremental_coverage_size (unsigned klass) const
+ void reset() {
+ class_def_1_size = class_def_format1_base_size;
+ class_def_2_size = class_def_format2_base_size;
+ included_glyphs.clear();
+ included_classes.clear();
+ }
+
+ // Compute the size of coverage for all glyphs added via 'add_class_def_size'.
+ unsigned coverage_size () const
{
- // Coverage takes 2 bytes per glyph worst case,
- return 2 * glyphs_per_class.get (klass).get_population ();
+ unsigned format1_size = coverage_base_size + bytes_per_glyph * included_glyphs.get_population();
+ unsigned format2_size = coverage_base_size + bytes_per_range * num_glyph_ranges();
+ return hb_min(format1_size, format2_size);
}
- // Incremental increase in the Coverage and ClassDef table size
- // (worst case) if all glyphs associated with 'klass' were added.
- unsigned incremental_class_def_size (unsigned klass) const
+ // Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added.
+ unsigned add_class_def_size (unsigned klass)
{
- // ClassDef takes 6 bytes per range
- unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass);
- if (gids_consecutive)
- {
- // ClassDef1 takes 2 bytes per glyph, but only can be used
- // when gids are consecutive.
- return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size);
+ if (!included_classes.has(klass)) {
+ hb_set_t* glyphs = nullptr;
+ if (glyphs_per_class.has(klass, &glyphs)) {
+ included_glyphs.union_(*glyphs);
+ }
+
+ class_def_1_size = class_def_format1_base_size;
+ if (!included_glyphs.is_empty()) {
+ unsigned min_glyph = included_glyphs.get_min();
+ unsigned max_glyph = included_glyphs.get_max();
+ class_def_1_size += bytes_per_glyph * (max_glyph - min_glyph + 1);
+ }
+
+ class_def_2_size += bytes_per_range * num_ranges_per_class.get (klass);
+
+ included_classes.add(klass);
}
- return class_def_2_size;
+ return hb_min (class_def_1_size, class_def_2_size);
+ }
+
+ unsigned num_glyph_ranges() const {
+ hb_codepoint_t start = HB_SET_VALUE_INVALID;
+ hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+ unsigned count = 0;
+ while (included_glyphs.next_range (&start, &end)) {
+ count++;
+ }
+ return count;
}
bool in_error ()
@@ -214,9 +243,12 @@ struct class_def_size_estimator_t
}
private:
- bool gids_consecutive;
hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
+ hb_set_t included_classes;
+ hb_set_t included_glyphs;
+ unsigned class_def_1_size;
+ unsigned class_def_2_size;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
index 26ad00bdd9..2a9d8346c0 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
@@ -195,6 +195,15 @@ struct graph_t
return incoming_edges_;
}
+ unsigned incoming_edges_from_parent (unsigned parent_index) const {
+ if (single_parent != (unsigned) -1) {
+ return single_parent == parent_index ? 1 : 0;
+ }
+
+ unsigned* count;
+ return parents.has(parent_index, &count) ? *count : 0;
+ }
+
void reset_parents ()
{
incoming_edges_ = 0;
@@ -334,6 +343,16 @@ struct graph_t
return true;
}
+ bool give_max_priority ()
+ {
+ bool result = false;
+ while (!has_max_priority()) {
+ result = true;
+ priority++;
+ }
+ return result;
+ }
+
bool has_max_priority () const {
return priority >= 3;
}
@@ -1023,6 +1042,11 @@ struct graph_t
* Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parent_idx, this
+ * will do nothing and return the original child_idx.
*/
unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
{
@@ -1036,18 +1060,20 @@ struct graph_t
* Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parent_idx,
+ * duplication isn't possible and this will return -1.
*/
unsigned duplicate (unsigned parent_idx, unsigned child_idx)
{
update_parents ();
- unsigned links_to_child = 0;
- for (const auto& l : vertices_[parent_idx].obj.all_links ())
- {
- if (l.objidx == child_idx) links_to_child++;
- }
+ const auto& child = vertices_[child_idx];
+ unsigned links_to_child = child.incoming_edges_from_parent(parent_idx);
- if (vertices_[child_idx].incoming_edges () <= links_to_child)
+ if (child.incoming_edges () <= links_to_child)
{
// Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent.
@@ -1060,7 +1086,7 @@ struct graph_t
parent_idx, child_idx);
unsigned clone_idx = duplicate (child_idx);
- if (clone_idx == (unsigned) -1) return false;
+ if (clone_idx == (unsigned) -1) return -1;
// duplicate shifts the root node idx, so if parent_idx was root update it.
if (parent_idx == clone_idx) parent_idx++;
@@ -1076,6 +1102,62 @@ struct graph_t
return clone_idx;
}
+ /*
+ * Creates a copy of child and re-assigns the links from
+ * parents to the clone. The copy is a shallow copy, objects
+ * linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parents,
+ * duplication isn't possible or duplication fails and this will
+ * return -1.
+ */
+ unsigned duplicate (const hb_set_t* parents, unsigned child_idx)
+ {
+ if (parents->is_empty()) {
+ return -1;
+ }
+
+ update_parents ();
+
+ const auto& child = vertices_[child_idx];
+ unsigned links_to_child = 0;
+ unsigned last_parent = parents->get_max();
+ unsigned first_parent = parents->get_min();
+ for (unsigned parent_idx : *parents) {
+ links_to_child += child.incoming_edges_from_parent(parent_idx);
+ }
+
+ if (child.incoming_edges () <= links_to_child)
+ {
+ // Can't duplicate this node, doing so would orphan the original one as all remaining links
+ // to child are from parent.
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
+ return -1;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
+
+ unsigned clone_idx = duplicate (child_idx);
+ if (clone_idx == (unsigned) -1) return false;
+
+ for (unsigned parent_idx : *parents) {
+ // duplicate shifts the root node idx, so if parent_idx was root update it.
+ if (parent_idx == clone_idx) parent_idx++;
+ auto& parent = vertices_[parent_idx];
+ for (auto& l : parent.obj.all_links_writer ())
+ {
+ if (l.objidx != child_idx)
+ continue;
+
+ reassign_link (l, parent_idx, clone_idx);
+ }
+ }
+
+ return clone_idx;
+ }
+
/*
* Adds a new node to the graph, not connected to anything.
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
index f7f74b18c9..fd46861de4 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
@@ -247,8 +247,8 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
for (unsigned i = 0; i < class1_count; i++)
{
unsigned accumulated_delta = class1_record_size;
- coverage_size += estimator.incremental_coverage_size (i);
- class_def_1_size += estimator.incremental_class_def_size (i);
+ class_def_1_size = estimator.add_class_def_size (i);
+ coverage_size = estimator.coverage_size ();
max_coverage_size = hb_max (max_coverage_size, coverage_size);
max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
@@ -280,8 +280,10 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
split_points.push (i);
// split does not include i, so add the size for i when we reset the size counters.
accumulated = base_size + accumulated_delta;
- coverage_size = 4 + estimator.incremental_coverage_size (i);
- class_def_1_size = 4 + estimator.incremental_class_def_size (i);
+
+ estimator.reset();
+ class_def_1_size = estimator.add_class_def_size(i);
+ coverage_size = estimator.coverage_size();
visited.clear (); // node sharing isn't allowed between splits.
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
index 266be5e2d4..2da9348111 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
+++ b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
@@ -26,27 +26,119 @@
#include "gsubgpos-context.hh"
#include "classdef-graph.hh"
+#include "hb-iter.hh"
+#include "hb-serialize.hh"
typedef hb_codepoint_pair_t gid_and_class_t;
typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
+template<typename It>
+static unsigned actual_class_def_size(It glyph_and_class) {
+ char buffer[100];
+ hb_serialize_context_t serializer(buffer, 100);
+ OT::ClassDef_serialize (&serializer, glyph_and_class);
+ serializer.end_serialize ();
+ assert(!serializer.in_error());
-static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
- unsigned cov_expected, unsigned class_def_expected)
+ hb_blob_t* blob = serializer.copy_blob();
+ unsigned size = hb_blob_get_length(blob);
+ hb_blob_destroy(blob);
+ return size;
+}
+
+static unsigned actual_class_def_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
+ auto filtered_it =
+ + consecutive_map.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ for (unsigned klass : classes) {
+ if (c == klass) {
+ return true;
+ }
+ }
+ return false;
+ }, hb_second);
+ return actual_class_def_size(+ filtered_it);
+}
+
+template<typename It>
+static unsigned actual_coverage_size(It glyphs) {
+ char buffer[100];
+ hb_serialize_context_t serializer(buffer, 100);
+ OT::Layout::Common::Coverage_serialize (&serializer, glyphs);
+ serializer.end_serialize ();
+ assert(!serializer.in_error());
+
+ hb_blob_t* blob = serializer.copy_blob();
+ unsigned size = hb_blob_get_length(blob);
+ hb_blob_destroy(blob);
+ return size;
+}
+
+static unsigned actual_coverage_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
+ auto filtered_it =
+ + consecutive_map.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ for (unsigned klass : classes) {
+ if (c == klass) {
+ return true;
+ }
+ }
+ return false;
+ }, hb_second);
+ return actual_coverage_size(+ filtered_it | hb_map_retains_sorting(hb_first));
+}
+
+static bool check_coverage_size(graph::class_def_size_estimator_t& estimator,
+ const gid_and_class_list_t& map,
+ hb_vector_t<unsigned> klasses)
+{
+ unsigned result = estimator.coverage_size();
+ unsigned expected = actual_coverage_size(map, klasses);
+ if (result != expected) {
+ printf ("FAIL: estimated coverage expected size %u but was %u\n", expected, result);
+ return false;
+ }
+ return true;
+}
+
+static bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator,
+ const gid_and_class_list_t& map,
+ unsigned klass, hb_vector_t<unsigned> klasses)
+{
+ unsigned result = estimator.add_class_def_size(klass);
+ unsigned expected = actual_class_def_size(map, klasses);
+ if (result != expected) {
+ printf ("FAIL: estimated class def expected size %u but was %u\n", expected, result);
+ return false;
+ }
+
+ return check_coverage_size(estimator, map, klasses);
+}
+
+static bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass)
{
graph::class_def_size_estimator_t estimator (list.iter ());
- unsigned result = estimator.incremental_coverage_size (klass);
- if (result != cov_expected)
+ unsigned result = estimator.add_class_def_size (klass);
+ auto filtered_it =
+ + list.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ return c == klass;
+ }, hb_second);
+
+ unsigned expected = actual_class_def_size(filtered_it);
+ if (result != expected)
{
- printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
+ printf ("FAIL: class def expected size %u but was %u\n", expected, result);
return false;
}
- result = estimator.incremental_class_def_size (klass);
- if (result != class_def_expected)
+ auto cov_it = + filtered_it | hb_map_retains_sorting(hb_first);
+ result = estimator.coverage_size ();
+ expected = actual_coverage_size(cov_it);
+ if (result != expected)
{
- printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
+ printf ("FAIL: coverage expected size %u but was %u\n", expected, result);
return false;
}
@@ -57,43 +149,45 @@ static void test_class_and_coverage_size_estimates ()
{
gid_and_class_list_t empty = {
};
- assert (incremental_size_is (empty, 0, 0, 0));
- assert (incremental_size_is (empty, 1, 0, 0));
+ assert (check_add_class_def_size (empty, 0));
+ assert (check_add_class_def_size (empty, 1));
gid_and_class_list_t class_zero = {
{5, 0},
};
- assert (incremental_size_is (class_zero, 0, 2, 0));
+ assert (check_add_class_def_size (class_zero, 0));
gid_and_class_list_t consecutive = {
{4, 0},
{5, 0},
+
{6, 1},
{7, 1},
+
{8, 2},
{9, 2},
{10, 2},
{11, 2},
};
- assert (incremental_size_is (consecutive, 0, 4, 0));
- assert (incremental_size_is (consecutive, 1, 4, 4));
- assert (incremental_size_is (consecutive, 2, 8, 6));
+ assert (check_add_class_def_size (consecutive, 0));
+ assert (check_add_class_def_size (consecutive, 1));
+ assert (check_add_class_def_size (consecutive, 2));
gid_and_class_list_t non_consecutive = {
{4, 0},
- {5, 0},
+ {6, 0},
- {6, 1},
- {7, 1},
+ {8, 1},
+ {10, 1},
{9, 2},
{10, 2},
{11, 2},
- {12, 2},
+ {13, 2},
};
- assert (incremental_size_is (non_consecutive, 0, 4, 0));
- assert (incremental_size_is (non_consecutive, 1, 4, 6));
- assert (incremental_size_is (non_consecutive, 2, 8, 6));
+ assert (check_add_class_def_size (non_consecutive, 0));
+ assert (check_add_class_def_size (non_consecutive, 1));
+ assert (check_add_class_def_size (non_consecutive, 2));
gid_and_class_list_t multiple_ranges = {
{4, 0},
@@ -108,12 +202,95 @@ static void test_class_and_coverage_size_estimates ()
{12, 1},
{13, 1},
};
- assert (incremental_size_is (multiple_ranges, 0, 4, 0));
- assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
+ assert (check_add_class_def_size (multiple_ranges, 0));
+ assert (check_add_class_def_size (multiple_ranges, 1));
+}
+
+static void test_running_class_and_coverage_size_estimates () {
+ // #### With consecutive gids: switches formats ###
+ gid_and_class_list_t consecutive_map = {
+ // range 1-4 (f1: 8 bytes), (f2: 6 bytes)
+ {1, 1},
+ {2, 1},
+ {3, 1},
+ {4, 1},
+
+ // (f1: 2 bytes), (f2: 6 bytes)
+ {5, 2},
+
+ // (f1: 14 bytes), (f2: 6 bytes)
+ {6, 3},
+ {7, 3},
+ {8, 3},
+ {9, 3},
+ {10, 3},
+ {11, 3},
+ {12, 3},
+ };
+
+ graph::class_def_size_estimator_t estimator1(consecutive_map.iter());
+ assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1}));
+ assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2}));
+ assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works
+ assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3}));
+
+ estimator1.reset();
+ assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2}));
+ assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3}));
+
+ // #### With non-consecutive gids: always uses format 2 ###
+ gid_and_class_list_t non_consecutive_map = {
+ // range 1-4 (f1: 8 bytes), (f2: 6 bytes)
+ {1, 1},
+ {2, 1},
+ {3, 1},
+ {4, 1},
+
+ // (f1: 2 bytes), (f2: 12 bytes)
+ {6, 2},
+ {8, 2},
+
+ // (f1: 14 bytes), (f2: 6 bytes)
+ {9, 3},
+ {10, 3},
+ {11, 3},
+ {12, 3},
+ {13, 3},
+ {14, 3},
+ {15, 3},
+ };
+
+ graph::class_def_size_estimator_t estimator2(non_consecutive_map.iter());
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1}));
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2}));
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3}));
+
+ estimator2.reset();
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2}));
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3}));
+}
+
+static void test_running_class_size_estimates_with_locally_consecutive_glyphs () {
+ gid_and_class_list_t map = {
+ {1, 1},
+ {6, 2},
+ {7, 3},
+ };
+
+ graph::class_def_size_estimator_t estimator(map.iter());
+ assert(check_add_class_def_size(estimator, map, 1, {1}));
+ assert(check_add_class_def_size(estimator, map, 2, {1, 2}));
+ assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3}));
+
+ estimator.reset();
+ assert(check_add_class_def_size(estimator, map, 2, {2}));
+ assert(check_add_class_def_size(estimator, map, 3, {2, 3}));
}
int
main (int argc, char **argv)
{
test_class_and_coverage_size_estimates ();
+ test_running_class_and_coverage_size_estimates ();
+ test_running_class_size_estimates_with_locally_consecutive_glyphs ();
}
diff --git a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
index c0e23b3eb8..f80c004cbb 100644
--- a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
+++ b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
@@ -54,6 +54,7 @@
#include "hb-subset-cff1.cc"
#include "hb-subset-cff2.cc"
#include "hb-subset-input.cc"
+#include "hb-subset-instancer-iup.cc"
#include "hb-subset-instancer-solver.cc"
#include "hb-subset-plan.cc"
#include "hb-subset-repacker.cc"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
index 06c9334b37..8436551324 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
@@ -552,6 +552,7 @@ struct LigatureSubtable
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
+ buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE;
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
index ea97057165..efa6074a42 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
@@ -671,7 +671,7 @@ struct hb_pair_t
return 0;
}
- friend void swap (hb_pair_t& a, hb_pair_t& b)
+ friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept
{
hb_swap (a.first, b.first);
hb_swap (a.second, b.second);
@@ -1053,6 +1053,18 @@ _hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
return val.cmp (key, ds...);
}
+template <typename K, typename V>
+static int
+_hb_cmp_operator (const void *pkey, const void *pval)
+{
+ const K& key = * (const K*) pkey;
+ const V& val = * (const V*) pval;
+
+ if (key < val) return -1;
+ if (key > val) return 1;
+ return 0;
+}
+
template <typename V, typename K, typename ...Ts>
static inline bool
hb_bsearch_impl (unsigned *pos, /* Out */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
index 2626251807..d5d1326d9f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
@@ -39,10 +39,10 @@ struct hb_bit_set_invertible_t
hb_bit_set_invertible_t () = default;
hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default;
- hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); }
+ hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) noexcept : hb_bit_set_invertible_t () { hb_swap (*this, other); }
hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default;
- hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; }
- friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b)
+ hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) noexcept { hb_swap (*this, other); return *this; }
+ friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) noexcept
{
if (likely (!a.s.successful || !b.s.successful))
return;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
index 1dbcce5cbd..5f4c6f0afe 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
@@ -38,10 +38,10 @@ struct hb_bit_set_t
~hb_bit_set_t () = default;
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
- hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
+ hb_bit_set_t ( hb_bit_set_t&& other) noexcept : hb_bit_set_t () { hb_swap (*this, other); }
hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
- hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
- friend void swap (hb_bit_set_t &a, hb_bit_set_t &b)
+ hb_bit_set_t& operator= (hb_bit_set_t&& other) noexcept { hb_swap (*this, other); return *this; }
+ friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) noexcept
{
if (likely (!a.successful || !b.successful))
return;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
index 265effba03..873d9b257a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
@@ -598,6 +598,11 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
* Creates a new blob containing the data from the
* specified binary font file.
*
+ * The filename is passed directly to the system on all platforms,
+ * except on Windows, where the filename is interpreted as UTF-8.
+ * Only if the filename is not valid UTF-8, it will be interpreted
+ * according to the system codepage.
+ *
* Returns: An #hb_blob_t pointer with the content of the file,
* or hb_blob_get_empty() if failed.
*
@@ -617,6 +622,11 @@ hb_blob_create_from_file (const char *file_name)
* Creates a new blob containing the data from the
* specified binary font file.
*
+ * The filename is passed directly to the system on all platforms,
+ * except on Windows, where the filename is interpreted as UTF-8.
+ * Only if the filename is not valid UTF-8, it will be interpreted
+ * according to the system codepage.
+ *
* Returns: An #hb_blob_t pointer with the content of the file,
* or `NULL` if failed.
*
@@ -672,10 +682,19 @@ fail_without_close:
if (unlikely (!file)) return nullptr;
HANDLE fd;
+ int conversion;
unsigned int size = strlen (file_name) + 1;
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
if (unlikely (!wchar_file_name)) goto fail_without_close;
- mbstowcs (wchar_file_name, file_name, size);
+
+ /* Assume file name is given in UTF-8 encoding */
+ conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size);
+ if (conversion <= 0)
+ {
+ /* Conversion failed due to invalid UTF-8 characters,
+ Repeat conversion based on system code page */
+ mbstowcs(wchar_file_name, file_name, size);
+ }
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
{
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
index 15a53919de..671d6eda8c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
@@ -149,7 +149,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
}
assert (text_start < text_end);
- if (0)
+ if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
hb_buffer_clear_contents (fragment);
@@ -288,7 +288,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
}
assert (text_start < text_end);
- if (0)
+ if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
#if 0
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
index 934c6c2129..d621a7cc55 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
@@ -309,6 +309,7 @@ hb_buffer_t::clear ()
deallocate_var_all ();
serial = 0;
+ random_state = 1;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
}
@@ -1359,6 +1360,49 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
return buffer->not_found;
}
+/**
+ * hb_buffer_set_random_state:
+ * @buffer: An #hb_buffer_t
+ * @state: the new random state
+ *
+ * Sets the random state of the buffer. The state changes
+ * every time a glyph uses randomness (eg. the `rand`
+ * OpenType feature). This function together with
+ * hb_buffer_get_random_state() allow for transferring
+ * the current random state to a subsequent buffer, to
+ * get better randomness distribution.
+ *
+ * Defaults to 1 and when buffer contents are cleared.
+ * A value of 0 disables randomness during shaping.
+ *
+ * Since: 8.4.0
+ **/
+void
+hb_buffer_set_random_state (hb_buffer_t *buffer,
+ unsigned state)
+{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
+ buffer->random_state = state;
+}
+
+/**
+ * hb_buffer_get_random_state:
+ * @buffer: An #hb_buffer_t
+ *
+ * See hb_buffer_set_random_state().
+ *
+ * Return value:
+ * The @buffer random state
+ *
+ * Since: 8.4.0
+ **/
+unsigned
+hb_buffer_get_random_state (const hb_buffer_t *buffer)
+{
+ return buffer->random_state;
+}
/**
* hb_buffer_clear_contents:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
index 3573127ff0..f75fe96b21 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
@@ -487,6 +487,12 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
HB_EXTERN hb_codepoint_t
hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
+HB_EXTERN void
+hb_buffer_set_random_state (hb_buffer_t *buffer,
+ unsigned state);
+
+HB_EXTERN unsigned
+hb_buffer_get_random_state (const hb_buffer_t *buffer);
/*
* Content API.
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
index f04ad58f11..0a198722d6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
@@ -116,6 +116,7 @@ struct hb_buffer_t
uint8_t allocated_var_bits;
uint8_t serial;
+ uint32_t random_state;
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
index 53226b227e..a08b10b5ff 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
@@ -54,8 +54,8 @@ struct top_dict_values_t : dict_values_t<OPSTR>
}
void fini () { dict_values_t<OPSTR>::fini (); }
- unsigned int charStringsOffset;
- unsigned int FDArrayOffset;
+ int charStringsOffset;
+ int FDArrayOffset;
};
struct dict_opset_t : opset_t<number_t>
@@ -157,11 +157,11 @@ struct top_dict_opset_t : dict_opset_t
{
switch (op) {
case OpCode_CharStrings:
- dictval.charStringsOffset = env.argStack.pop_uint ();
+ dictval.charStringsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDArray:
- dictval.FDArrayOffset = env.argStack.pop_uint ();
+ dictval.FDArrayOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FontMatrix:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
index 915b10cf39..55b1d3bf8d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
@@ -168,7 +168,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
protected:
const int *coords;
unsigned int num_coords;
- const CFF2VariationStore *varStore;
+ const CFF2ItemVariationStore *varStore;
unsigned int region_count;
unsigned int ivs;
hb_vector_t<float> scalars;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
index 0c13c7d171..4b8bae4422 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
@@ -996,7 +996,7 @@ hb_feature_to_string (hb_feature_t *feature,
if (feature->value > 1)
{
s[len++] = '=';
- len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+ len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value));
}
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.h b/src/3rdparty/harfbuzz-ng/src/hb-common.h
index a9fe666b39..533de91562 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.h
@@ -47,14 +47,10 @@
# endif /* !__cplusplus */
#endif
-#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
- defined (_sgi) || defined (__sun) || defined (sun) || \
- defined (__digital__) || defined (__HP_cc)
-# include <inttypes.h>
-#elif defined (_AIX)
+#if defined (_AIX)
# include <sys/inttypes.h>
#elif defined (_MSC_VER) && _MSC_VER < 1600
-/* VS 2010 (_MSC_VER 1600) has stdint.h */
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
@@ -63,10 +59,11 @@ typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
-#elif defined (__KERNEL__)
-# include <linux/types.h>
-#else
+#elif defined (_MSC_VER) && _MSC_VER < 1800
+/* VS 2013 (_MSC_VER 1800) has inttypes.h */
# include <stdint.h>
+#else
+# include <inttypes.h>
#endif
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh b/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
index 531ef1b7c8..a640e192de 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
@@ -56,15 +56,15 @@ struct shared_ptr
explicit shared_ptr (T *p = nullptr) : p (p) {}
shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {}
- shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; }
+ shared_ptr (shared_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; }
- shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ shared_ptr& operator = (shared_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~shared_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; }
- void swap (shared_ptr &o) { std::swap (p, o.p); }
- friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); }
+ void swap (shared_ptr &o) noexcept { std::swap (p, o.p); }
+ friend void swap (shared_ptr &a, shared_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; }
T& operator * () const { return *get (); }
@@ -98,16 +98,16 @@ struct unique_ptr
explicit unique_ptr (T *p = nullptr) : p (p) {}
unique_ptr (const unique_ptr &o) = delete;
- unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; }
+ unique_ptr (unique_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
unique_ptr& operator = (const unique_ptr &o) = delete;
- unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ unique_ptr& operator = (unique_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~unique_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; }
T* release () { T* v = p; p = nullptr; return v; }
- void swap (unique_ptr &o) { std::swap (p, o.p); }
- friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); }
+ void swap (unique_ptr &o) noexcept { std::swap (p, o.p); }
+ friend void swap (unique_ptr &a, unique_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; }
T& operator * () const { return *get (); }
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
index 42764a244b..6c90265d0b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
@@ -173,7 +173,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
t_DWriteCreateFactory p_DWriteCreateFactory;
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
@@ -181,7 +181,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
p_DWriteCreateFactory = (t_DWriteCreateFactory)
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-features.h b/src/3rdparty/harfbuzz-ng/src/hb-features.h
new file mode 100644
index 0000000000..9199864195
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-features.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2022 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_FEATURES_H
+#define HB_FEATURES_H
+
+HB_BEGIN_DECLS
+
+/**
+ * SECTION: hb-features
+ * @title: hb-features
+ * @short_description: Feature detection
+ * @include: hb-features.h
+ *
+ * Macros for detecting optional HarfBuzz features at build time.
+ **/
+
+/**
+ * HB_HAS_CAIRO:
+ *
+ * Defined if Harfbuzz has been built with cairo support.
+ */
+#
+
+/**
+ * HB_HAS_CORETEXT:
+ *
+ * Defined if Harfbuzz has been built with CoreText support.
+ */
+#undef HB_HAS_CORETEXT
+
+/**
+ * HB_HAS_DIRECTWRITE:
+ *
+ * Defined if Harfbuzz has been built with DirectWrite support.
+ */
+#undef HB_HAS_DIRECTWRITE
+
+/**
+ * HB_HAS_FREETYPE:
+ *
+ * Defined if Harfbuzz has been built with Freetype support.
+ */
+#define HB_HAS_FREETYPE 1
+
+/**
+ * HB_HAS_GDI:
+ *
+ * Defined if Harfbuzz has been built with GDI support.
+ */
+#undef HB_HAS_GDI
+
+/**
+ * HB_HAS_GLIB:
+ *
+ * Defined if Harfbuzz has been built with GLib support.
+ */
+#define HB_HAS_GLIB 1
+
+/**
+ * HB_HAS_GOBJECT:
+ *
+ * Defined if Harfbuzz has been built with GObject support.
+ */
+#undef HB_HAS_GOBJECT
+
+/**
+ * HB_HAS_GRAPHITE:
+ *
+ * Defined if Harfbuzz has been built with Graphite support.
+ */
+#undef HB_HAS_GRAPHITE
+
+/**
+ * HB_HAS_ICU:
+ *
+ * Defined if Harfbuzz has been built with ICU support.
+ */
+#undef HB_HAS_ICU
+
+/**
+ * HB_HAS_UNISCRIBE:
+ *
+ * Defined if Harfbuzz has been built with Uniscribe support.
+ */
+#undef HB_HAS_UNISCRIBE
+
+/**
+ * HB_HAS_WASM:
+ *
+ * Defined if Harfbuzz has been built with WebAssembly support.
+ */
+#undef HB_HAS_WASM
+
+
+HB_END_DECLS
+
+#endif /* HB_FEATURES_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.hh b/src/3rdparty/harfbuzz-ng/src/hb-font.hh
index f503575c34..4c8190b0dd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font.hh
@@ -651,7 +651,7 @@ struct hb_font_t
{
if (get_glyph_name (glyph, s, size)) return;
- if (size && snprintf (s, size, "gid%u", glyph) < 0)
+ if (size && snprintf (s, size, "gid%" PRIu32, glyph) < 0)
*s = '\0';
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
index 955a9081e0..3de4a6d5d4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
@@ -224,7 +224,7 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
*
* Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
*
- * For more information, see
+ * For more information, see
* <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
*
* This function works with #hb_font_t objects created by
@@ -252,7 +252,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
*
* Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
*
- * For more information, see
+ * For more information, see
* <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
*
* This function works with #hb_font_t objects created by
@@ -1118,10 +1118,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
* This variant of the function does not provide any life-cycle management.
*
* Most client programs should use hb_ft_face_create_referenced()
- * (or, perhaps, hb_ft_face_create_cached()) instead.
+ * (or, perhaps, hb_ft_face_create_cached()) instead.
*
* If you know you have valid reasons not to use hb_ft_face_create_referenced(),
- * then it is the client program's responsibility to destroy @ft_face
+ * then it is the client program's responsibility to destroy @ft_face
* after the #hb_face_t face object has been destroyed.
*
* Return value: (transfer full): the new #hb_face_t face object
@@ -1215,7 +1215,7 @@ hb_ft_face_finalize (void *arg)
hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face)
{
- if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
+ if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
{
if (ft_face->generic.finalizer)
ft_face->generic.finalizer (ft_face);
@@ -1241,13 +1241,13 @@ hb_ft_face_create_cached (FT_Face ft_face)
* This variant of the function does not provide any life-cycle management.
*
* Most client programs should use hb_ft_font_create_referenced()
- * instead.
+ * instead.
*
* If you know you have valid reasons not to use hb_ft_font_create_referenced(),
- * then it is the client program's responsibility to destroy @ft_face
+ * then it is the client program's responsibility to destroy @ft_face
* after the #hb_font_t font object has been destroyed.
*
- * HarfBuzz will use the @destroy callback on the #hb_font_t font object
+ * HarfBuzz will use the @destroy callback on the #hb_font_t font object
* if it is supplied when you use this function. However, even if @destroy
* is provided, it is the client program's responsibility to destroy @ft_face,
* and it is the client program's responsibility to ensure that @ft_face is
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-icu.cc b/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
index e46401f7a6..3707ec30f8 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
@@ -93,15 +93,16 @@ hb_icu_script_to_script (UScriptCode script)
UScriptCode
hb_icu_script_from_script (hb_script_t script)
{
+ UScriptCode out = USCRIPT_INVALID_CODE;
+
if (unlikely (script == HB_SCRIPT_INVALID))
- return USCRIPT_INVALID_CODE;
+ return out;
- unsigned int numScriptCode = 1 + u_getIntPropertyMaxValue (UCHAR_SCRIPT);
- for (unsigned int i = 0; i < numScriptCode; i++)
- if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script))
- return (UScriptCode) i;
+ UErrorCode icu_err = U_ZERO_ERROR;
+ const unsigned char buf[5] = {HB_UNTAG (script), 0};
+ uscript_getCode ((const char *) buf, &out, 1, &icu_err);
- return USCRIPT_UNKNOWN;
+ return out;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
index 25c1e71e13..7efc893eae 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
@@ -106,7 +106,7 @@
#endif
#ifndef HB_COLRV1_MAX_EDGE_COUNT
-#define HB_COLRV1_MAX_EDGE_COUNT 65536
+#define HB_COLRV1_MAX_EDGE_COUNT 2048
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-map.hh
index 45a02b830c..6521b1a41d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-map.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-map.hh
@@ -70,9 +70,9 @@ struct hb_hashmap_t
alloc (o.population); hb_copy (o, *this);
}
- hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
+ hb_hashmap_t (hb_hashmap_t&& o) noexcept : hb_hashmap_t () { hb_swap (*this, o); }
hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
- hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; }
+ hb_hashmap_t& operator= (hb_hashmap_t&& o) noexcept { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
{
@@ -137,26 +137,23 @@ struct hb_hashmap_t
};
hb_object_header_t header;
- unsigned int successful : 1; /* Allocations successful */
- unsigned int population : 31; /* Not including tombstones. */
+ bool successful; /* Allocations successful */
+ unsigned short max_chain_length;
+ unsigned int population; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */
unsigned int mask;
unsigned int prime;
- unsigned int max_chain_length;
item_t *items;
- friend void swap (hb_hashmap_t& a, hb_hashmap_t& b)
+ friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) noexcept
{
if (unlikely (!a.successful || !b.successful))
return;
- unsigned tmp = a.population;
- a.population = b.population;
- b.population = tmp;
- //hb_swap (a.population, b.population);
+ hb_swap (a.max_chain_length, b.max_chain_length);
+ hb_swap (a.population, b.population);
hb_swap (a.occupancy, b.occupancy);
hb_swap (a.mask, b.mask);
hb_swap (a.prime, b.prime);
- hb_swap (a.max_chain_length, b.max_chain_length);
hb_swap (a.items, b.items);
}
void init ()
@@ -164,10 +161,10 @@ struct hb_hashmap_t
hb_object_init (this);
successful = true;
+ max_chain_length = 0;
population = occupancy = 0;
mask = 0;
prime = 0;
- max_chain_length = 0;
items = nullptr;
}
void fini ()
@@ -558,7 +555,7 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
~hb_map_t () = default;
hb_map_t () : hashmap () {}
hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {}
- hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {}
+ hb_map_t (hb_map_t &&o) noexcept : hashmap (std::move ((hashmap &) o)) {}
hb_map_t& operator= (const hb_map_t&) = default;
hb_map_t& operator= (hb_map_t&&) = default;
hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-object.hh b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
index e2c2c3394c..5cffe1666b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-object.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
@@ -325,7 +325,7 @@ retry:
hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (unlikely (!user_data))
{
- user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
+ user_data = (hb_user_data_array_t *) hb_calloc (1, sizeof (hb_user_data_array_t));
if (unlikely (!user_data))
return false;
user_data->init ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
index 6967bca3d4..9c11f14344 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
@@ -985,6 +985,13 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
return_trace (ret);
}
+ SortedArrayOf* copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ SortedArrayOf* out = reinterpret_cast<SortedArrayOf *> (ArrayOf<Type, LenType>::copy (c));
+ return_trace (out);
+ }
+
template <typename T>
Type &bsearch (const T &x, Type &not_found = Crap (Type))
{ return *as_array ().bsearch (x, &not_found); }
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
index 4fdba197ac..c7c3264c08 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
@@ -41,10 +41,21 @@ using namespace OT;
using objidx_t = hb_serialize_context_t::objidx_t;
using whence_t = hb_serialize_context_t::whence_t;
-/* utility macro */
-template<typename Type>
-static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
-{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
+/* CFF offsets can technically be negative */
+template<typename Type, typename ...Ts>
+static inline const Type& StructAtOffsetOrNull (const void *P, int offset, hb_sanitize_context_t &sc, Ts&&... ds)
+{
+ if (!offset) return Null (Type);
+
+ const char *p = (const char *) P + offset;
+ if (!sc.check_point (p)) return Null (Type);
+
+ const Type &obj = *reinterpret_cast<const Type *> (p);
+ if (!obj.sanitize (&sc, std::forward<Ts> (ds)...)) return Null (Type);
+
+ return obj;
+}
+
struct code_pair_t
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
index c869e90554..1bbd463841 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
@@ -763,9 +763,9 @@ struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t>
unsigned int ros_supplement;
unsigned int cidCount;
- unsigned int EncodingOffset;
- unsigned int CharsetOffset;
- unsigned int FDSelectOffset;
+ int EncodingOffset;
+ int CharsetOffset;
+ int FDSelectOffset;
table_info_t privateDictInfo;
};
@@ -821,24 +821,24 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
break;
case OpCode_Encoding:
- dictval.EncodingOffset = env.argStack.pop_uint ();
+ dictval.EncodingOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.EncodingOffset == 0)) return;
break;
case OpCode_charset:
- dictval.CharsetOffset = env.argStack.pop_uint ();
+ dictval.CharsetOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.CharsetOffset == 0)) return;
break;
case OpCode_FDSelect:
- dictval.FDSelectOffset = env.argStack.pop_uint ();
+ dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_Private:
- dictval.privateDictInfo.offset = env.argStack.pop_uint ();
+ dictval.privateDictInfo.offset = env.argStack.pop_int ();
dictval.privateDictInfo.size = env.argStack.pop_uint ();
env.clear_args ();
break;
@@ -913,7 +913,7 @@ struct cff1_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
- unsigned int subrsOffset;
+ int subrsOffset;
const CFF1Subrs *localSubrs;
};
@@ -948,7 +948,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -990,7 +990,7 @@ struct cff1_private_dict_opset_subset_t : dict_opset_t
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -1090,8 +1090,8 @@ struct cff1
goto fail;
hb_barrier ();
- topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
- if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
+ topDictIndex = &StructAtOffsetOrNull<CFF1TopDictIndex> (nameIndex, nameIndex->get_size (), sc);
+ if (topDictIndex == &Null (CFF1TopDictIndex) || (topDictIndex->count == 0))
goto fail;
hb_barrier ();
@@ -1108,20 +1108,18 @@ struct cff1
charset = &Null (Charset);
else
{
- charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
- if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries))) goto fail;
- hb_barrier ();
+ charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset, sc, &num_charset_entries);
+ if (unlikely (charset == &Null (Charset))) goto fail;
}
fdCount = 1;
if (is_CID ())
{
- fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
- fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
- if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
- (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
+ fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset, sc);
+ fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset, sc, fdArray->count);
+ if (unlikely (fdArray == &Null (CFF1FDArray) ||
+ fdSelect == &Null (CFF1FDSelect)))
goto fail;
- hb_barrier ();
fdCount = fdArray->count;
}
@@ -1140,27 +1138,19 @@ struct cff1
{
if (!is_predef_encoding ())
{
- encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
- if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) goto fail;
- hb_barrier ();
+ encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset, sc);
+ if (unlikely (encoding == &Null (Encoding))) goto fail;
}
}
- stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
- if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
+ stringIndex = &StructAtOffsetOrNull<CFF1StringIndex> (topDictIndex, topDictIndex->get_size (), sc);
+ if (stringIndex == &Null (CFF1StringIndex))
goto fail;
- hb_barrier ();
- globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
- if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
+ globalSubrs = &StructAtOffsetOrNull<CFF1Subrs> (stringIndex, stringIndex->get_size (), sc);
+ charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset, sc);
+ if (charStrings == &Null (CFF1CharStrings))
goto fail;
- hb_barrier ();
-
- charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
-
- if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
- goto fail;
- hb_barrier ();
num_glyphs = charStrings->count;
if (num_glyphs != sc.get_num_glyphs ())
@@ -1188,19 +1178,13 @@ struct cff1
font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail;
PRIVDICTVAL *priv = &privateDicts[i];
- const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- hb_barrier ();
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
num_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
priv->init ();
if (unlikely (!priv_interp.interpret (*priv))) goto fail;
- priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
- if (priv->localSubrs != &Null (CFF1Subrs) &&
- unlikely (!priv->localSubrs->sanitize (&sc)))
- goto fail;
- hb_barrier ();
+ priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
}
}
else /* non-CID */
@@ -1208,18 +1192,13 @@ struct cff1
cff1_top_dict_values_t *font = &topDict;
PRIVDICTVAL *priv = &privateDicts[0];
- const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- hb_barrier ();
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
num_interp_env_t env (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
priv->init ();
if (unlikely (!priv_interp.interpret (*priv))) goto fail;
- priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
- if (priv->localSubrs != &Null (CFF1Subrs) &&
- unlikely (!priv->localSubrs->sanitize (&sc)))
- goto fail;
+ priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
hb_barrier ();
}
@@ -1437,7 +1416,7 @@ struct cff1
hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire ();
if (unlikely (!names))
{
- names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1);
+ names = (hb_sorted_vector_t<gname_t> *) hb_calloc (1, sizeof (hb_sorted_vector_t<gname_t>));
if (likely (names))
{
names->init ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
index 652748b737..4b3bdc9315 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
@@ -111,7 +111,7 @@ struct CFF2FDSelect
DEFINE_SIZE_MIN (2);
};
-struct CFF2VariationStore
+struct CFF2ItemVariationStore
{
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -122,11 +122,11 @@ struct CFF2VariationStore
varStore.sanitize (c));
}
- bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore)
+ bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore)
{
TRACE_SERIALIZE (this);
unsigned int size_ = varStore->get_size ();
- CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
+ CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_);
if (unlikely (!dest)) return_trace (false);
hb_memcpy (dest, varStore, size_);
return_trace (true);
@@ -135,9 +135,9 @@ struct CFF2VariationStore
unsigned int get_size () const { return HBUINT16::static_size + size; }
HBUINT16 size;
- VariationStore varStore;
+ ItemVariationStore varStore;
- DEFINE_SIZE_MIN (2 + VariationStore::min_size);
+ DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size);
};
struct cff2_top_dict_values_t : top_dict_values_t<>
@@ -150,8 +150,8 @@ struct cff2_top_dict_values_t : top_dict_values_t<>
}
void fini () { top_dict_values_t<>::fini (); }
- unsigned int vstoreOffset;
- unsigned int FDSelectOffset;
+ int vstoreOffset;
+ int FDSelectOffset;
};
struct cff2_top_dict_opset_t : top_dict_opset_t<>
@@ -169,11 +169,11 @@ struct cff2_top_dict_opset_t : top_dict_opset_t<>
break;
case OpCode_vstore:
- dictval.vstoreOffset = env.argStack.pop_uint ();
+ dictval.vstoreOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDSelect:
- dictval.FDSelectOffset = env.argStack.pop_uint ();
+ dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -241,7 +241,7 @@ struct cff2_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
- unsigned int subrsOffset;
+ int subrsOffset;
const CFF2Subrs *localSubrs;
unsigned int ivs;
};
@@ -295,7 +295,7 @@ struct cff2_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_vsindexdict:
@@ -344,7 +344,7 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t
return;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -426,18 +426,15 @@ struct cff2
if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
- globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
- varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
- charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
- fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
- fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
-
- if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
- (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
- (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
- (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
- !hb_barrier () ||
- (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
+ globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
+ varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
+ charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
+ fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
+ fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc, fdArray->count);
+
+ if (charStrings == &Null (CFF2CharStrings) ||
+ globalSubrs == &Null (CFF2Subrs) ||
+ fdArray == &Null (CFF2FDArray))
goto fail;
num_glyphs = charStrings->count;
@@ -462,19 +459,13 @@ struct cff2
font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail;
- const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- hb_barrier ();
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
cff2_priv_dict_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
privateDicts[i].init ();
if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
- privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
- if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
- unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
- goto fail;
- hb_barrier ();
+ privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
}
return;
@@ -509,7 +500,7 @@ struct cff2
hb_blob_t *blob = nullptr;
cff2_top_dict_values_t topDict;
const CFF2Subrs *globalSubrs = nullptr;
- const CFF2VariationStore *varStore = nullptr;
+ const CFF2ItemVariationStore *varStore = nullptr;
const CFF2CharStrings *charStrings = nullptr;
const CFF2FDArray *fdArray = nullptr;
const CFF2FDSelect *fdSelect = nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
index e2e2581855..64d2b13880 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
@@ -41,6 +41,30 @@
namespace OT {
+static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
+{
+ uint16_t mapping[] = {
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
+ 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
+ };
+ uint16_t *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
+ _hb_cmp_operator<uint16_t, uint16_t>);
+ return c ? (c - mapping) + 0x7F : 0;
+}
struct CmapSubtableFormat0
{
@@ -1465,8 +1489,11 @@ struct EncodingRecord
int ret;
ret = platformID.cmp (other.platformID);
if (ret) return ret;
- ret = encodingID.cmp (other.encodingID);
- if (ret) return ret;
+ if (other.encodingID != 0xFFFF)
+ {
+ ret = encodingID.cmp (other.encodingID);
+ if (ret) return ret;
+ }
return 0;
}
@@ -1814,9 +1841,13 @@ struct cmap
c->plan));
}
- const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
+ const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
+ bool *mac = nullptr,
+ bool *macroman = nullptr) const
{
if (symbol) *symbol = false;
+ if (mac) *mac = false;
+ if (macroman) *macroman = false;
const CmapSubtable *subtable;
@@ -1841,6 +1872,20 @@ struct cmap
if ((subtable = this->find_subtable (0, 1))) return subtable;
if ((subtable = this->find_subtable (0, 0))) return subtable;
+ /* MacRoman subtable. */
+ if ((subtable = this->find_subtable (1, 0)))
+ {
+ if (mac) *mac = true;
+ if (macroman) *macroman = true;
+ return subtable;
+ }
+ /* Any other Mac subtable; we just map ASCII for these. */
+ if ((subtable = this->find_subtable (1, 0xFFFF)))
+ {
+ if (mac) *mac = true;
+ return subtable;
+ }
+
/* Meh. */
return &Null (CmapSubtable);
}
@@ -1852,8 +1897,8 @@ struct cmap
accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
- bool symbol;
- this->subtable = table->find_best_subtable (&symbol);
+ bool symbol, mac, macroman;
+ this->subtable = table->find_best_subtable (&symbol, &mac, &macroman);
this->subtable_uvs = &Null (CmapSubtableFormat14);
{
const CmapSubtable *st = table->find_subtable (0, 5);
@@ -1862,6 +1907,7 @@ struct cmap
}
this->get_glyph_data = subtable;
+#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
if (unlikely (symbol))
{
switch ((unsigned) face->table.OS2->get_font_page ()) {
@@ -1881,7 +1927,16 @@ struct cmap
break;
}
}
+ else if (unlikely (macroman))
+ {
+ this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
+ }
+ else if (unlikely (mac))
+ {
+ this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
+ }
else
+#endif
{
switch (subtable->u.format) {
/* Accelerate format 4 and format 12. */
@@ -1924,7 +1979,7 @@ struct cmap
hb_codepoint_t *glyph,
cache_t *cache = nullptr) const
{
- if (unlikely (!this->get_glyph_funcZ)) return 0;
+ if (unlikely (!this->get_glyph_funcZ)) return false;
return _cached_get (unicode, glyph, cache);
}
@@ -2006,6 +2061,28 @@ struct cmap
return false;
}
+ template <typename Type>
+ HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
+ }
+
+ template <typename Type>
+ HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+ {
+ if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
+ return true;
+
+ const Type *typed_obj = (const Type *) obj;
+ unsigned c = unicode_to_macroman (codepoint);
+ return c && typed_obj->get_glyph (c, glyph);
+ }
+
private:
hb_nonnull_ptr_t<const CmapSubtable> subtable;
hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
@@ -2035,28 +2112,6 @@ struct cmap
return &(this+result.subtable);
}
- const EncodingRecord *find_encodingrec (unsigned int platform_id,
- unsigned int encoding_id) const
- {
- EncodingRecord key;
- key.platformID = platform_id;
- key.encodingID = encoding_id;
-
- return encodingRecord.as_array ().bsearch (key);
- }
-
- bool find_subtable (unsigned format) const
- {
- auto it =
- + hb_iter (encodingRecord)
- | hb_map (&EncodingRecord::subtable)
- | hb_map (hb_add (this))
- | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
- ;
-
- return it.len ();
- }
-
public:
bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
index b3677c6a4c..1da869d697 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
@@ -208,12 +208,12 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::HVAR &HVAR = *hmtx.var_table;
- const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
- OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
+ const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
+ OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
bool use_cache = font->num_coords;
#else
- OT::VariationStore::cache_t *varStore_cache = nullptr;
+ OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
bool use_cache = false;
#endif
@@ -277,7 +277,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
}
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
- OT::VariationStore::destroy_cache (varStore_cache);
+ OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif
if (font->x_strength && !font->embolden_in_place)
@@ -313,10 +313,10 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
{
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::VVAR &VVAR = *vmtx.var_table;
- const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
- OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
+ const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore;
+ OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
#else
- OT::VariationStore::cache_t *varStore_cache = nullptr;
+ OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
#endif
for (unsigned int i = 0; i < count; i++)
@@ -327,7 +327,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
}
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
- OT::VariationStore::destroy_cache (varStore_cache);
+ OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif
}
else
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
index 89640b43f1..48bd536121 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
@@ -145,6 +145,29 @@ struct hmtxvmtx
table->minTrailingBearing = min_rsb;
table->maxExtent = max_extent;
}
+
+ if (T::is_horizontal)
+ {
+ const auto &OS2 = *c->plan->source->table.OS2;
+ if (OS2.has_data () &&
+ table->ascender == OS2.sTypoAscender &&
+ table->descender == OS2.sTypoDescender &&
+ table->lineGap == OS2.sTypoLineGap)
+ {
+ table->ascender = static_cast<int> (roundf (OS2.sTypoAscender +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ table->descender = static_cast<int> (roundf (OS2.sTypoDescender +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ table->lineGap = static_cast<int> (roundf (OS2.sTypoLineGap +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ }
+ }
}
#endif
@@ -374,7 +397,7 @@ struct hmtxvmtx
unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph,
hb_font_t *font,
- VariationStore::cache_t *store_cache = nullptr) const
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
unsigned int advance = get_advance_without_var_unscaled (glyph);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
index a23b6377d1..0278399069 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
@@ -46,6 +46,12 @@ struct BaseCoordFormat1
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ return_trace ((bool) c->serializer->embed (*this));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -67,6 +73,17 @@ struct BaseCoordFormat2
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->referenceGlyph,
+ c->plan->glyph_map->get (referenceGlyph),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -86,7 +103,7 @@ struct BaseCoordFormat2
struct BaseCoordFormat3
{
hb_position_t get_coord (hb_font_t *font,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
hb_direction_t direction) const
{
const Device &device = this+deviceTable;
@@ -96,6 +113,23 @@ struct BaseCoordFormat3
: font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ unsigned varidx = (this+deviceTable).get_variation_index ();
+ varidx_set.add (varidx);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable,
+ this, 0,
+ hb_serialize_context_t::Head,
+ &c->plan->base_variation_idx_map));
+ }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -120,7 +154,7 @@ struct BaseCoord
bool has_data () const { return u.format; }
hb_position_t get_coord (hb_font_t *font,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
hb_direction_t direction) const
{
switch (u.format) {
@@ -131,6 +165,27 @@ struct BaseCoord
}
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ switch (u.format) {
+ case 3: u.format3.collect_variation_indices (varidx_set);
+ default:return;
+ }
+ }
+
+ template <typename context_t, typename ...Ts>
+ typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+ {
+ if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+ TRACE_DISPATCH (this, u.format);
+ switch (u.format) {
+ case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+ case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -161,12 +216,37 @@ struct FeatMinMaxRecord
bool has_data () const { return tag; }
+ hb_tag_t get_feature_tag () const { return tag; }
+
void get_min_max (const BaseCoord **min, const BaseCoord **max) const
{
if (likely (min)) *min = &(this+minCoord);
if (likely (max)) *max = &(this+maxCoord);
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ const void *base,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ if (!plan->layout_features.has (tag))
+ return;
+
+ (base+minCoord).collect_variation_indices (varidx_set);
+ (base+maxCoord).collect_variation_indices (varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ if (!(out->minCoord.serialize_subset (c, minCoord, base)))
+ return_trace (false);
+
+ return_trace (out->maxCoord.serialize_subset (c, maxCoord, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@@ -206,6 +286,39 @@ struct MinMax
}
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+minCoord).collect_variation_indices (varidx_set);
+ (this+maxCoord).collect_variation_indices (varidx_set);
+ for (const FeatMinMaxRecord& record : featMinMaxRecords)
+ record.collect_variation_indices (plan, this, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ if (!(out->minCoord.serialize_subset (c, minCoord, this)) ||
+ !(out->maxCoord.serialize_subset (c, maxCoord, this)))
+ return_trace (false);
+
+ unsigned len = 0;
+ for (const FeatMinMaxRecord& _ : featMinMaxRecords)
+ {
+ hb_tag_t feature_tag = _.get_feature_tag ();
+ if (!c->plan->layout_features.has (feature_tag))
+ continue;
+
+ if (!_.subset (c, this)) return false;
+ len++;
+ }
+ return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -240,6 +353,26 @@ struct BaseValues
return this+baseCoords[baseline_tag_index];
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ for (const auto& _ : baseCoords)
+ (this+_).collect_variation_indices (varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ out->defaultIndex = defaultIndex;
+
+ for (const auto& _ : baseCoords)
+ if (!subset_offset_array (c, out->baseCoords, this) (_))
+ return_trace (false);
+
+ return_trace (bool (out->baseCoords));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -270,6 +403,20 @@ struct BaseLangSysRecord
const MinMax &get_min_max () const { return this+minMax; }
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ { (this+minMax).collect_variation_indices (plan, varidx_set); }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->minMax.serialize_subset (c, minMax, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@@ -300,6 +447,35 @@ struct BaseScript
bool has_values () const { return baseValues; }
bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+baseValues).collect_variation_indices (varidx_set);
+ (this+defaultMinMax).collect_variation_indices (plan, varidx_set);
+
+ for (const BaseLangSysRecord& _ : baseLangSysRecords)
+ _.collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this))
+ return_trace (false);
+
+ if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this))
+ return_trace (false);
+
+ for (const auto& _ : baseLangSysRecords)
+ if (!_.subset (c, this)) return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -332,9 +508,31 @@ struct BaseScriptRecord
bool has_data () const { return baseScriptTag; }
+ hb_tag_t get_script_tag () const { return baseScriptTag; }
+
const BaseScript &get_base_script (const BaseScriptList *list) const
{ return list+baseScript; }
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ const void* list,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ if (!plan->layout_scripts.has (baseScriptTag))
+ return;
+
+ (list+baseScript).collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->baseScript.serialize_subset (c, baseScript, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@@ -361,6 +559,33 @@ struct BaseScriptList
return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ for (const BaseScriptRecord& _ : baseScriptRecords)
+ _.collect_variation_indices (plan, this, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ unsigned len = 0;
+ for (const BaseScriptRecord& _ : baseScriptRecords)
+ {
+ hb_tag_t script_tag = _.get_script_tag ();
+ if (!c->plan->layout_scripts.has (script_tag))
+ continue;
+
+ if (!_.subset (c, this)) return false;
+ len++;
+ }
+ return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -422,6 +647,20 @@ struct Axis
return true;
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ { (this+baseScriptList).collect_variation_indices (plan, varidx_set); }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ out->baseTagList.serialize_copy (c->serializer, baseTagList, this);
+ return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -453,8 +692,41 @@ struct BASE
const Axis &get_axis (hb_direction_t direction) const
{ return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
- const VariationStore &get_var_store () const
- { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
+ bool has_var_store () const
+ { return version.to_int () >= 0x00010001u && varStore != 0; }
+
+ const ItemVariationStore &get_var_store () const
+ { return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; }
+
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+hAxis).collect_variation_indices (plan, varidx_set);
+ (this+vAxis).collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ out->version = version;
+ if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this))
+ return_trace (false);
+
+ if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this))
+ return_trace (false);
+
+ if (has_var_store ())
+ {
+ if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
+ return_trace (false);
+ return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
+ }
+
+ return_trace (true);
+ }
bool get_baseline (hb_font_t *font,
hb_tag_t baseline_tag,
@@ -487,7 +759,7 @@ struct BASE
&min_coord, &max_coord))
return false;
- const VariationStore &var_store = get_var_store ();
+ const ItemVariationStore &var_store = get_var_store ();
if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
return true;
@@ -510,7 +782,7 @@ struct BASE
* of BASE table (may be NULL) */
Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning
* of BASE table (may be NULL) */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of BASE
* header (may be NULL). Introduced
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
index 6b359cceb7..aba427368c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
@@ -188,7 +188,7 @@ struct hb_subset_layout_context_t :
unsigned lookup_index_count;
};
-struct VariationStore;
+struct ItemVariationStore;
struct hb_collect_variation_indices_context_t :
hb_dispatch_context_t<hb_collect_variation_indices_context_t>
{
@@ -3036,7 +3036,7 @@ struct VarData
DEFINE_SIZE_ARRAY (6, regionIndices);
};
-struct VariationStore
+struct ItemVariationStore
{
friend struct item_variations_t;
using cache_t = VarRegionList::cache_t;
@@ -3141,7 +3141,7 @@ struct VariationStore
}
bool serialize (hb_serialize_context_t *c,
- const VariationStore *src,
+ const ItemVariationStore *src,
const hb_array_t <const hb_inc_bimap_t> &inner_maps)
{
TRACE_SERIALIZE (this);
@@ -3197,7 +3197,7 @@ struct VariationStore
return_trace (true);
}
- VariationStore *copy (hb_serialize_context_t *c) const
+ ItemVariationStore *copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
@@ -3227,7 +3227,7 @@ struct VariationStore
return_trace (false);
#endif
- VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
+ ItemVariationStore *varstore_prime = c->serializer->start_embed<ItemVariationStore> ();
if (unlikely (!varstore_prime)) return_trace (false);
varstore_prime->serialize (c->serializer, this, inner_maps);
@@ -4030,13 +4030,13 @@ struct VariationDevice
private:
hb_position_t get_x_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_x (get_delta (font, store, store_cache)); }
hb_position_t get_y_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_y (get_delta (font, store, store_cache)); }
VariationDevice* copy (hb_serialize_context_t *c,
@@ -4070,10 +4070,10 @@ struct VariationDevice
private:
float get_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
- return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache);
+ return store.get_delta (varIdx, font->coords, font->num_coords, (ItemVariationStore::cache_t *) store_cache);
}
protected:
@@ -4097,8 +4097,8 @@ struct DeviceHeader
struct Device
{
hb_position_t get_x_delta (hb_font_t *font,
- const VariationStore &store=Null (VariationStore),
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store=Null (ItemVariationStore),
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
@@ -4115,8 +4115,8 @@ struct Device
}
}
hb_position_t get_y_delta (hb_font_t *font,
- const VariationStore &store=Null (VariationStore),
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store=Null (ItemVariationStore),
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
index 499ad673e4..c65ea32b8a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
@@ -708,8 +708,8 @@ struct hb_ot_apply_context_t :
recurse_func_t recurse_func = nullptr;
const GDEF &gdef;
const GDEF::accelerator_t &gdef_accel;
- const VariationStore &var_store;
- VariationStore::cache_t *var_store_cache;
+ const ItemVariationStore &var_store;
+ ItemVariationStore::cache_t *var_store_cache;
hb_set_digest_t digest;
hb_direction_t direction;
@@ -723,7 +723,6 @@ struct hb_ot_apply_context_t :
bool auto_zwj = true;
bool per_syllable = false;
bool random = false;
- uint32_t random_state = 1;
unsigned new_syllables = (unsigned) -1;
signed last_base = -1; // GPOS uses
@@ -766,7 +765,7 @@ struct hb_ot_apply_context_t :
~hb_ot_apply_context_t ()
{
#ifndef HB_NO_VAR
- VariationStore::destroy_cache (var_store_cache);
+ ItemVariationStore::destroy_cache (var_store_cache);
#endif
}
@@ -788,8 +787,8 @@ struct hb_ot_apply_context_t :
uint32_t random_number ()
{
/* http://www.cplusplus.com/reference/random/minstd_rand/ */
- random_state = random_state * 48271 % 2147483647;
- return random_state;
+ buffer->random_state = buffer->random_state * 48271 % 2147483647;
+ return buffer->random_state;
}
bool match_properties_mark (hb_codepoint_t glyph,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
index 2eb8535db5..a4c13abadf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
@@ -2127,7 +2127,7 @@ hb_ot_layout_get_font_extents (hb_font_t *font,
hb_tag_t language_tag,
hb_font_extents_t *extents)
{
- hb_position_t min, max;
+ hb_position_t min = 0, max = 0;
if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE,
&min, &max))
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
index 32e497aef6..5839059fde 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
@@ -344,27 +344,20 @@ struct MathKern
const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
int sign = font->y_scale < 0 ? -1 : +1;
- /* The description of the MathKern table is a ambiguous, but interpreting
- * "between the two heights found at those indexes" for 0 < i < len as
- *
- * correctionHeight[i-1] < correction_height <= correctionHeight[i]
- *
- * makes the result consistent with the limit cases and we can just use the
- * binary search algorithm of std::upper_bound:
+ /* According to OpenType spec (v1.9), except for the boundary cases, the index
+ * chosen for kern value should be i such that
+ * correctionHeight[i-1] <= correction_height < correctionHeight[i]
+ * We can use the binary search algorithm of std::upper_bound(). Or, we can
+ * use the internal hb_bsearch_impl.
*/
- unsigned int i = 0;
- unsigned int count = heightCount;
- while (count > 0)
- {
- unsigned int half = count / 2;
- hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
- if (sign * height < sign * correction_height)
- {
- i += half + 1;
- count -= half + 1;
- } else
- count = half;
- }
+ unsigned int pos;
+ auto cmp = +[](const void* key, const void* p,
+ int sign, hb_font_t* font, const MathKern* mathKern) -> int {
+ return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern);
+ };
+ unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight,
+ heightCount, MathValueRecord::static_size,
+ cmp, sign, font, this) ? pos + 1 : pos;
return kernValue[i].get_x_value (font, this);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
index 8c2e696f56..43b58d9bbf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
@@ -223,7 +223,7 @@ struct OS2
}
}
- return num ? (unsigned) roundf (total_width / num) : 0;
+ return num ? (unsigned) roundf ((double) total_width / (double) num) : 0;
}
bool subset (hb_subset_context_t *c) const
@@ -284,12 +284,12 @@ struct OS2
os2_prime->usWidthClass = width_class;
}
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
- return_trace (true);
-
os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
+ return_trace (true);
+
_update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
return_trace (true);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
index 90f596ae79..148830022e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
@@ -155,7 +155,7 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
#endif
bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
if (false)
- ;
+ {}
#ifndef HB_NO_AAT_SHAPE
/* Prefer GPOS over kerx if GSUB is present;
* https://github.com/harfbuzz/harfbuzz/issues/3008 */
@@ -167,15 +167,16 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
{
+ if (false) {}
#ifndef HB_NO_AAT_SHAPE
- if (has_kerx)
+ else if (has_kerx)
plan.apply_kerx = true;
- else
#endif
#ifndef HB_NO_OT_KERN
- if (hb_ot_layout_has_kerning (face))
+ else if (hb_ot_layout_has_kerning (face))
plan.apply_kern = true;
#endif
+ else {}
}
plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
index 72dcc84df5..d70746ed2b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
@@ -560,9 +560,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%u,%u,%u)",
step == MEASURE ? "measuring" : "cutting", context, start, end);
- DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %d", start - context, w_total);
- DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
- DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
+ DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %" PRId32, start - context, w_total);
+ DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%" PRId32, n_fixed, w_fixed);
+ DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32, n_repeating, w_repeating);
/* Number of additional times to repeat each repeating tile. */
int n_copies = 0;
@@ -602,7 +602,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
repeat += n_copies;
- DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %u; j=%u",
+ DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %" PRIu32 "; j=%u",
repeat, info[k - 1].codepoint, j);
pos[k - 1].x_advance = 0;
for (unsigned int n = 0; n < repeat; n++)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
index 58b3cd74df..e88c82a13c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
@@ -349,7 +349,7 @@ struct AxisValueFormat4
struct AxisValue
{
- bool get_value (unsigned int axis_index) const
+ float get_value (unsigned int axis_index) const
{
switch (u.format)
{
@@ -357,7 +357,7 @@ struct AxisValue
case 2: return u.format2.get_value ();
case 3: return u.format3.get_value ();
case 4: return u.format4.get_axis_record (axis_index).get_value ();
- default:return 0;
+ default:return 0.f;
}
}
@@ -485,7 +485,7 @@ struct STAT
hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
for (unsigned int i = 0; i < axis_values.length; i++)
{
- const AxisValue& axis_value = this+axis_values[i];
+ const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
if (axis_value.get_axis_index () == axis_index)
{
if (value)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
index 032a7c866c..db92f4664a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
@@ -6,8 +6,8 @@
*
* on files with these headers:
*
- * <meta name="updated_at" content="2022-09-30 11:47 PM" />
- * File-Date: 2023-08-02
+ * <meta name="updated_at" content="2023-09-30 01:21 AM" />
+ * File-Date: 2024-03-07
*/
#ifndef HB_OT_TAG_TABLE_HH
@@ -31,7 +31,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */
{HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */
{HB_TAG('b','m',' ',' '), HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */
- {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bengali */
+ {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bangla */
{HB_TAG('b','o',' ',' '), HB_TAG('T','I','B',' ')}, /* Tibetan */
{HB_TAG('b','r',' ',' '), HB_TAG('B','R','E',' ')}, /* Breton */
{HB_TAG('b','s',' ',' '), HB_TAG('B','O','S',' ')}, /* Bosnian */
@@ -64,7 +64,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */
{HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */
{HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */
- {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */
+ {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
{HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */
{HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
{HB_TAG('g','u',' ',' '), HB_TAG('G','U','J',' ')}, /* Gujarati */
@@ -132,7 +132,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */
{HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */
{HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
- {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */
+ {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) -> Romanian (Moldova) */
{HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */
{HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */
{HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
@@ -153,7 +153,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('o','c',' ',' '), HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
{HB_TAG('o','j',' ',' '), HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */
{HB_TAG('o','m',' ',' '), HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
- {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */
+ {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia [macrolanguage] */
{HB_TAG('o','s',' ',' '), HB_TAG('O','S','S',' ')}, /* Ossetian */
{HB_TAG('p','a',' ',' '), HB_TAG('P','A','N',' ')}, /* Punjabi */
{HB_TAG('p','i',' ',' '), HB_TAG('P','A','L',' ')}, /* Pali */
@@ -166,7 +166,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('r','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Romanian */
{HB_TAG('r','u',' ',' '), HB_TAG('R','U','S',' ')}, /* Russian */
{HB_TAG('r','w',' ',' '), HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
- {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit */
+ {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit [macrolanguage] */
{HB_TAG('s','c',' ',' '), HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
{HB_TAG('s','d',' ',' '), HB_TAG('S','N','D',' ')}, /* Sindhi */
{HB_TAG('s','e',' ',' '), HB_TAG('N','S','M',' ')}, /* Northern Sami */
@@ -465,6 +465,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('c','l','d',' '), HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */
{HB_TAG('c','l','e',' '), HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */
{HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */
+ {HB_TAG('c','l','s',' '), HB_TAG('S','A','N',' ')}, /* Classical Sanskrit -> Sanskrit */
{HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */
{HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */
{HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */
@@ -637,7 +638,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('g','a','a',' '), HB_TAG('G','A','D',' ')}, /* Ga */
{HB_TAG('g','a','c',' '), HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */
{HB_TAG('g','a','d',' '), HB_TAG_NONE }, /* Gaddang != Ga */
- {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */
+ {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic */
/*{HB_TAG('g','a','g',' '), HB_TAG('G','A','G',' ')},*/ /* Gagauz */
{HB_TAG('g','a','l',' '), HB_TAG_NONE }, /* Galolen != Galician */
{HB_TAG('g','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */
@@ -1160,7 +1161,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('o','r','o',' '), HB_TAG_NONE }, /* Orokolo != Oromo */
{HB_TAG('o','r','r',' '), HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */
{HB_TAG('o','r','s',' '), HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */
- {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */
+ {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia */
{HB_TAG('o','t','w',' '), HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */
{HB_TAG('o','u','a',' '), HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */
{HB_TAG('p','a','a',' '), HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */
@@ -1395,7 +1396,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('s','n','k',' '), HB_TAG('S','N','K',' ')},*/ /* Soninke */
{HB_TAG('s','o','g',' '), HB_TAG_NONE }, /* Sogdian != Sodo Gurage */
/*{HB_TAG('s','o','p',' '), HB_TAG('S','O','P',' ')},*/ /* Songe */
- {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */
+ {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia */
{HB_TAG('s','p','y',' '), HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */
{HB_TAG('s','r','b',' '), HB_TAG_NONE }, /* Sora != Serbian */
{HB_TAG('s','r','c',' '), HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */
@@ -1533,6 +1534,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */
{HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */
/*{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')},*/ /* Võro */
+ {HB_TAG('v','s','n',' '), HB_TAG('S','A','N',' ')}, /* Vedic Sanskrit -> Sanskrit */
{HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */
/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */
{HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */
@@ -2643,7 +2645,7 @@ out:
/* Romanian; Moldova */
unsigned int i;
hb_tag_t possible_tags[] = {
- HB_TAG('M','O','L',' '), /* Moldavian */
+ HB_TAG('M','O','L',' '), /* Romanian (Moldova) */
HB_TAG('R','O','M',' '), /* Romanian */
};
for (i = 0; i < 2 && i < *count; i++)
@@ -2920,7 +2922,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("mn", -1); /* Mongolian [macrolanguage] */
case HB_TAG('M','N','K',' '): /* Maninka */
return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */
- case HB_TAG('M','O','L',' '): /* Moldavian */
+ case HB_TAG('M','O','L',' '): /* Romanian (Moldova) */
return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */
case HB_TAG('M','O','N','T'): /* Thailand Mon */
return hb_language_from_string ("mnw-TH", -1); /* Mon; Thailand */
@@ -2958,6 +2960,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("ro", -1); /* Romanian */
case HB_TAG('R','O','Y',' '): /* Romany */
return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */
+ case HB_TAG('S','A','N',' '): /* Sanskrit */
+ return hb_language_from_string ("sa", -1); /* Sanskrit [macrolanguage] */
case HB_TAG('S','Q','I',' '): /* Albanian */
return hb_language_from_string ("sq", -1); /* Albanian [macrolanguage] */
case HB_TAG('S','R','B',' '): /* Serbian */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
index 53b6b38f66..0c63756b14 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
@@ -547,7 +547,7 @@ hb_ot_tag_to_language (hb_tag_t tag)
buf[3] = '-';
str += 4;
}
- snprintf (str, 16, "x-hbot-%08x", tag);
+ snprintf (str, 16, "x-hbot-%08" PRIx32, tag);
return hb_language_from_string (&*buf, -1);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
index b2e5d87a3c..9149959d79 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
@@ -57,7 +57,7 @@ struct avarV2Tail
protected:
Offset32To<DeltaSetIndexMap> varIdxMap; /* Offset from the beginning of 'avar' table. */
- Offset32To<VariationStore> varStore; /* Offset from the beginning of 'avar' table. */
+ Offset32To<ItemVariationStore> varStore; /* Offset from the beginning of 'avar' table. */
public:
DEFINE_SIZE_STATIC (8);
@@ -230,7 +230,7 @@ struct SegmentMaps : Array16Of<AxisValueMap>
* duplicates here */
if (mapping.must_include ())
continue;
- value_mappings.push (std::move (mapping));
+ value_mappings.push (mapping);
}
AxisValueMap m;
@@ -343,7 +343,7 @@ struct avar
for (unsigned i = 0; i < coords_length; i++)
coords[i] = out[i];
- OT::VariationStore::destroy_cache (var_store_cache);
+ OT::ItemVariationStore::destroy_cache (var_store_cache);
#endif
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
index eff6df380f..379e164059 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
@@ -28,6 +28,7 @@
#include "hb-ot-layout-common.hh"
#include "hb-priority-queue.hh"
+#include "hb-subset-instancer-iup.hh"
namespace OT {
@@ -221,9 +222,9 @@ struct DeltaSetIndexMap
};
-struct VarStoreInstancer
+struct ItemVarStoreInstancer
{
- VarStoreInstancer (const VariationStore *varStore,
+ ItemVarStoreInstancer (const ItemVariationStore *varStore,
const DeltaSetIndexMap *varIdxMap,
hb_array_t<int> coords) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
@@ -235,7 +236,7 @@ struct VarStoreInstancer
float operator() (uint32_t varIdx, unsigned short offset = 0) const
{ return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
- const VariationStore *varStore;
+ const ItemVariationStore *varStore;
const DeltaSetIndexMap *varIdxMap;
hb_array_t<int> coords;
};
@@ -460,7 +461,7 @@ struct tuple_delta_t
tuple_delta_t () = default;
tuple_delta_t (const tuple_delta_t& o) = default;
- friend void swap (tuple_delta_t& a, tuple_delta_t& b)
+ friend void swap (tuple_delta_t& a, tuple_delta_t& b) noexcept
{
hb_swap (a.axis_tuples, b.axis_tuples);
hb_swap (a.indices, b.indices);
@@ -471,10 +472,10 @@ struct tuple_delta_t
hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
}
- tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
+ tuple_delta_t (tuple_delta_t&& o) noexcept : tuple_delta_t ()
{ hb_swap (*this, o); }
- tuple_delta_t& operator = (tuple_delta_t&& o)
+ tuple_delta_t& operator = (tuple_delta_t&& o) noexcept
{
hb_swap (*this, o);
return *this;
@@ -609,7 +610,9 @@ struct tuple_delta_t
const hb_map_t& axes_old_index_tag_map,
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map)
{
- if (!compiled_deltas) return false;
+ /* compiled_deltas could be empty after iup delta optimization, we can skip
+ * compiling this tuple and return true */
+ if (!compiled_deltas) return true;
unsigned cur_axis_count = axes_index_map.get_population ();
/* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
@@ -723,22 +726,28 @@ struct tuple_delta_t
}
bool compile_deltas ()
+ { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
+
+ bool compile_deltas (const hb_vector_t<bool> &point_indices,
+ const hb_vector_t<float> &x_deltas,
+ const hb_vector_t<float> &y_deltas,
+ hb_vector_t<char> &compiled_deltas /* OUT */)
{
hb_vector_t<int> rounded_deltas;
- if (unlikely (!rounded_deltas.alloc (indices.length)))
+ if (unlikely (!rounded_deltas.alloc (point_indices.length)))
return false;
- for (unsigned i = 0; i < indices.length; i++)
+ for (unsigned i = 0; i < point_indices.length; i++)
{
- if (!indices[i]) continue;
- int rounded_delta = (int) roundf (deltas_x[i]);
+ if (!point_indices[i]) continue;
+ int rounded_delta = (int) roundf (x_deltas.arrayZ[i]);
rounded_deltas.push (rounded_delta);
}
- if (!rounded_deltas) return false;
+ if (!rounded_deltas) return true;
/* allocate enough memories 3 * num_deltas */
unsigned alloc_len = 3 * rounded_deltas.length;
- if (deltas_y)
+ if (y_deltas)
alloc_len *= 2;
if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
@@ -746,14 +755,14 @@ struct tuple_delta_t
unsigned i = 0;
unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
- if (deltas_y)
+ if (y_deltas)
{
- /* reuse the rounded_deltas vector, check that deltas_y have the same num of deltas as deltas_x */
+ /* reuse the rounded_deltas vector, check that y_deltas have the same num of deltas as x_deltas */
unsigned j = 0;
- for (unsigned idx = 0; idx < indices.length; idx++)
+ for (unsigned idx = 0; idx < point_indices.length; idx++)
{
- if (!indices[idx]) continue;
- int rounded_delta = (int) roundf (deltas_y[idx]);
+ if (!point_indices[idx]) continue;
+ int rounded_delta = (int) roundf (y_deltas.arrayZ[idx]);
if (j >= rounded_deltas.length) return false;
@@ -761,7 +770,7 @@ struct tuple_delta_t
}
if (j != rounded_deltas.length) return false;
- /* reset i because we reuse rounded_deltas for deltas_y */
+ /* reset i because we reuse rounded_deltas for y_deltas */
i = 0;
encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
}
@@ -1020,6 +1029,171 @@ struct tuple_delta_t
return true;
}
+ bool optimize (const contour_point_vector_t& contour_points,
+ bool is_composite,
+ float tolerance = 0.5f)
+ {
+ unsigned count = contour_points.length;
+ if (deltas_x.length != count ||
+ deltas_y.length != count)
+ return false;
+
+ hb_vector_t<bool> opt_indices;
+ hb_vector_t<int> rounded_x_deltas, rounded_y_deltas;
+
+ if (unlikely (!rounded_x_deltas.alloc (count) ||
+ !rounded_y_deltas.alloc (count)))
+ return false;
+
+ for (unsigned i = 0; i < count; i++)
+ {
+ int rounded_x_delta = (int) roundf (deltas_x.arrayZ[i]);
+ int rounded_y_delta = (int) roundf (deltas_y.arrayZ[i]);
+ rounded_x_deltas.push (rounded_x_delta);
+ rounded_y_deltas.push (rounded_y_delta);
+ }
+
+ if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, tolerance))
+ return false;
+
+ unsigned ref_count = 0;
+ for (bool ref_flag : opt_indices)
+ ref_count += ref_flag;
+
+ if (ref_count == count) return true;
+
+ hb_vector_t<float> opt_deltas_x, opt_deltas_y;
+ bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
+ if (is_comp_glyph_wo_deltas)
+ {
+ if (unlikely (!opt_deltas_x.resize (count) ||
+ !opt_deltas_y.resize (count)))
+ return false;
+
+ opt_indices.arrayZ[0] = true;
+ for (unsigned i = 1; i < count; i++)
+ opt_indices.arrayZ[i] = false;
+ }
+
+ hb_vector_t<char> opt_point_data;
+ if (!compile_point_set (opt_indices, opt_point_data))
+ return false;
+ hb_vector_t<char> opt_deltas_data;
+ if (!compile_deltas (opt_indices,
+ is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x,
+ is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y,
+ opt_deltas_data))
+ return false;
+
+ hb_vector_t<char> point_data;
+ if (!compile_point_set (indices, point_data))
+ return false;
+ hb_vector_t<char> deltas_data;
+ if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data))
+ return false;
+
+ if (opt_point_data.length + opt_deltas_data.length < point_data.length + deltas_data.length)
+ {
+ indices.fini ();
+ indices = std::move (opt_indices);
+
+ if (is_comp_glyph_wo_deltas)
+ {
+ deltas_x.fini ();
+ deltas_x = std::move (opt_deltas_x);
+
+ deltas_y.fini ();
+ deltas_y = std::move (opt_deltas_y);
+ }
+ }
+ return !indices.in_error () && !deltas_x.in_error () && !deltas_y.in_error ();
+ }
+
+ static bool compile_point_set (const hb_vector_t<bool> &point_indices,
+ hb_vector_t<char>& compiled_points /* OUT */)
+ {
+ unsigned num_points = 0;
+ for (bool i : point_indices)
+ if (i) num_points++;
+
+ /* when iup optimization is enabled, num of referenced points could be 0 */
+ if (!num_points) return true;
+
+ unsigned indices_length = point_indices.length;
+ /* If the points set consists of all points in the glyph, it's encoded with a
+ * single zero byte */
+ if (num_points == indices_length)
+ return compiled_points.resize (1);
+
+ /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
+ unsigned num_bytes = 2 + 3 *num_points;
+ if (unlikely (!compiled_points.resize (num_bytes, false)))
+ return false;
+
+ unsigned pos = 0;
+ /* binary data starts with the total number of reference points */
+ if (num_points < 0x80)
+ compiled_points.arrayZ[pos++] = num_points;
+ else
+ {
+ compiled_points.arrayZ[pos++] = ((num_points >> 8) | 0x80);
+ compiled_points.arrayZ[pos++] = num_points & 0xFF;
+ }
+
+ const unsigned max_run_length = 0x7F;
+ unsigned i = 0;
+ unsigned last_value = 0;
+ unsigned num_encoded = 0;
+ while (i < indices_length && num_encoded < num_points)
+ {
+ unsigned run_length = 0;
+ unsigned header_pos = pos;
+ compiled_points.arrayZ[pos++] = 0;
+
+ bool use_byte_encoding = false;
+ bool new_run = true;
+ while (i < indices_length && num_encoded < num_points &&
+ run_length <= max_run_length)
+ {
+ // find out next referenced point index
+ while (i < indices_length && !point_indices[i])
+ i++;
+
+ if (i >= indices_length) break;
+
+ unsigned cur_value = i;
+ unsigned delta = cur_value - last_value;
+
+ if (new_run)
+ {
+ use_byte_encoding = (delta <= 0xFF);
+ new_run = false;
+ }
+
+ if (use_byte_encoding && delta > 0xFF)
+ break;
+
+ if (use_byte_encoding)
+ compiled_points.arrayZ[pos++] = delta;
+ else
+ {
+ compiled_points.arrayZ[pos++] = delta >> 8;
+ compiled_points.arrayZ[pos++] = delta & 0xFF;
+ }
+ i++;
+ last_value = cur_value;
+ run_length++;
+ num_encoded++;
+ }
+
+ if (use_byte_encoding)
+ compiled_points.arrayZ[header_pos] = run_length - 1;
+ else
+ compiled_points.arrayZ[header_pos] = (run_length - 1) | 0x80;
+ }
+ return compiled_points.resize (pos, false);
+ }
+
static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta)
{
if (prev_val == next_val)
@@ -1071,41 +1245,41 @@ struct TupleVariationData
private:
/* referenced point set->compiled point data map */
- hb_hashmap_t<const hb_vector_t<bool>*, hb_bytes_t> point_data_map;
+ hb_hashmap_t<const hb_vector_t<bool>*, hb_vector_t<char>> point_data_map;
/* referenced point set-> count map, used in finding shared points */
hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
/* empty for non-gvar tuples.
- * shared_points_bytes is just a copy of some value in the point_data_map,
+ * shared_points_bytes is a pointer to some value in the point_data_map,
* which will be freed during map destruction. Save it for serialization, so
* no need to do find_shared_points () again */
- hb_bytes_t shared_points_bytes;
+ hb_vector_t<char> *shared_points_bytes = nullptr;
/* total compiled byte size as TupleVariationData format, initialized to its
* min_size: 4 */
unsigned compiled_byte_size = 4;
+ /* for gvar iup delta optimization: whether this is a composite glyph */
+ bool is_composite = false;
+
public:
tuple_variations_t () = default;
tuple_variations_t (const tuple_variations_t&) = delete;
tuple_variations_t& operator=(const tuple_variations_t&) = delete;
tuple_variations_t (tuple_variations_t&&) = default;
tuple_variations_t& operator=(tuple_variations_t&&) = default;
- ~tuple_variations_t () { fini (); }
- void fini ()
- {
- for (auto _ : point_data_map.values ())
- _.fini ();
-
- point_set_count_map.fini ();
- tuple_vars.fini ();
- }
+ ~tuple_variations_t () = default;
explicit operator bool () const { return bool (tuple_vars); }
unsigned get_var_count () const
{
- unsigned count = tuple_vars.length;
- if (shared_points_bytes.length)
+ unsigned count = 0;
+ /* when iup delta opt is enabled, compiled_deltas could be empty and we
+ * should skip this tuple */
+ for (auto& tuple: tuple_vars)
+ if (tuple.compiled_deltas) count++;
+
+ if (shared_points_bytes && shared_points_bytes->length)
count |= TupleVarCount::SharedPointNumbers;
return count;
}
@@ -1119,26 +1293,27 @@ struct TupleVariationData
bool is_gvar,
const hb_map_t *axes_old_index_tag_map,
const hb_vector_t<unsigned> &shared_indices,
- const hb_array_t<const F2DOT14> shared_tuples)
+ const hb_array_t<const F2DOT14> shared_tuples,
+ bool is_composite_glyph)
{
do
{
const HBUINT8 *p = iterator.get_serialized_data ();
unsigned int length = iterator.current_tuple->get_data_size ();
if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
- { fini (); return false; }
+ return false;
hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples)
|| axis_tuples.is_empty ())
- { fini (); return false; }
+ return false;
hb_vector_t<unsigned> private_indices;
bool has_private_points = iterator.current_tuple->has_private_points ();
const HBUINT8 *end = p + length;
if (has_private_points &&
!TupleVariationData::unpack_points (p, private_indices, end))
- { fini (); return false; }
+ return false;
const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
bool apply_to_all = (indices.length == 0);
@@ -1148,24 +1323,24 @@ struct TupleVariationData
if (unlikely (!deltas_x.resize (num_deltas, false) ||
!TupleVariationData::unpack_deltas (p, deltas_x, end)))
- { fini (); return false; }
+ return false;
hb_vector_t<int> deltas_y;
if (is_gvar)
{
if (unlikely (!deltas_y.resize (num_deltas, false) ||
!TupleVariationData::unpack_deltas (p, deltas_y, end)))
- { fini (); return false; }
+ return false;
}
tuple_delta_t var;
var.axis_tuples = std::move (axis_tuples);
if (unlikely (!var.indices.resize (point_count) ||
!var.deltas_x.resize (point_count, false)))
- { fini (); return false; }
+ return false;
if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false)))
- { fini (); return false; }
+ return false;
for (unsigned i = 0; i < num_deltas; i++)
{
@@ -1178,6 +1353,8 @@ struct TupleVariationData
}
tuple_vars.push (std::move (var));
} while (iterator.move_to_next ());
+
+ is_composite = is_composite_glyph;
return true;
}
@@ -1261,7 +1438,7 @@ struct TupleVariationData
unsigned new_len = new_vars.length + out.length;
if (unlikely (!new_vars.alloc (new_len, false)))
- { fini (); return false;}
+ return false;
for (unsigned i = 0; i < out.length; i++)
new_vars.push (std::move (out[i]));
@@ -1272,8 +1449,9 @@ struct TupleVariationData
return true;
}
- /* merge tuple variations with overlapping tents */
- void merge_tuple_variations ()
+ /* merge tuple variations with overlapping tents, if iup delta optimization
+ * is enabled, add default deltas to contour_points */
+ bool merge_tuple_variations (contour_point_vector_t* contour_points = nullptr)
{
hb_vector_t<tuple_delta_t> new_vars;
hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
@@ -1281,7 +1459,15 @@ struct TupleVariationData
for (const tuple_delta_t& var : tuple_vars)
{
/* if all axes are pinned, drop the tuple variation */
- if (var.axis_tuples.is_empty ()) continue;
+ if (var.axis_tuples.is_empty ())
+ {
+ /* if iup_delta_optimize is enabled, add deltas to contour coords */
+ if (contour_points && !contour_points->add_deltas (var.deltas_x,
+ var.deltas_y,
+ var.indices))
+ return false;
+ continue;
+ }
unsigned *idx;
if (m.has (&(var.axis_tuples), &idx))
@@ -1291,98 +1477,14 @@ struct TupleVariationData
else
{
new_vars.push (var);
- m.set (&(var.axis_tuples), i);
+ if (!m.set (&(var.axis_tuples), i))
+ return false;
i++;
}
}
tuple_vars.fini ();
tuple_vars = std::move (new_vars);
- }
-
- hb_bytes_t compile_point_set (const hb_vector_t<bool> &point_indices)
- {
- unsigned num_points = 0;
- for (bool i : point_indices)
- if (i) num_points++;
-
- unsigned indices_length = point_indices.length;
- /* If the points set consists of all points in the glyph, it's encoded with a
- * single zero byte */
- if (num_points == indices_length)
- {
- char *p = (char *) hb_calloc (1, sizeof (char));
- if (unlikely (!p)) return hb_bytes_t ();
-
- return hb_bytes_t (p, 1);
- }
-
- /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
- unsigned num_bytes = 2 + 3 *num_points;
- char *p = (char *) hb_calloc (num_bytes, sizeof (char));
- if (unlikely (!p)) return hb_bytes_t ();
-
- unsigned pos = 0;
- /* binary data starts with the total number of reference points */
- if (num_points < 0x80)
- p[pos++] = num_points;
- else
- {
- p[pos++] = ((num_points >> 8) | 0x80);
- p[pos++] = num_points & 0xFF;
- }
-
- const unsigned max_run_length = 0x7F;
- unsigned i = 0;
- unsigned last_value = 0;
- unsigned num_encoded = 0;
- while (i < indices_length && num_encoded < num_points)
- {
- unsigned run_length = 0;
- unsigned header_pos = pos;
- p[pos++] = 0;
-
- bool use_byte_encoding = false;
- bool new_run = true;
- while (i < indices_length && num_encoded < num_points &&
- run_length <= max_run_length)
- {
- // find out next referenced point index
- while (i < indices_length && !point_indices[i])
- i++;
-
- if (i >= indices_length) break;
-
- unsigned cur_value = i;
- unsigned delta = cur_value - last_value;
-
- if (new_run)
- {
- use_byte_encoding = (delta <= 0xFF);
- new_run = false;
- }
-
- if (use_byte_encoding && delta > 0xFF)
- break;
-
- if (use_byte_encoding)
- p[pos++] = delta;
- else
- {
- p[pos++] = delta >> 8;
- p[pos++] = delta & 0xFF;
- }
- i++;
- last_value = cur_value;
- run_length++;
- num_encoded++;
- }
-
- if (use_byte_encoding)
- p[header_pos] = run_length - 1;
- else
- p[header_pos] = (run_length - 1) | 0x80;
- }
- return hb_bytes_t (p, pos);
+ return true;
}
/* compile all point set and store byte data in a point_set->hb_bytes_t hashmap,
@@ -1402,11 +1504,11 @@ struct TupleVariationData
continue;
}
- hb_bytes_t compiled_data = compile_point_set (*points_set);
- if (unlikely (compiled_data == hb_bytes_t ()))
+ hb_vector_t<char> compiled_point_data;
+ if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data))
return false;
- if (!point_data_map.set (points_set, compiled_data) ||
+ if (!point_data_map.set (points_set, std::move (compiled_point_data)) ||
!point_set_count_map.set (points_set, 1))
return false;
}
@@ -1414,31 +1516,33 @@ struct TupleVariationData
}
/* find shared points set which saves most bytes */
- hb_bytes_t find_shared_points ()
+ void find_shared_points ()
{
unsigned max_saved_bytes = 0;
- hb_bytes_t res{};
- for (const auto& _ : point_data_map.iter ())
+ for (const auto& _ : point_data_map.iter_ref ())
{
const hb_vector_t<bool>* points_set = _.first;
unsigned data_length = _.second.length;
+ if (!data_length) continue;
unsigned *count;
if (unlikely (!point_set_count_map.has (points_set, &count) ||
*count <= 1))
- return hb_bytes_t ();
+ {
+ shared_points_bytes = nullptr;
+ return;
+ }
unsigned saved_bytes = data_length * ((*count) -1);
if (saved_bytes > max_saved_bytes)
{
max_saved_bytes = saved_bytes;
- res = _.second;
+ shared_points_bytes = &(_.second);
}
}
- return res;
}
- bool calc_inferred_deltas (contour_point_vector_t& contour_points)
+ bool calc_inferred_deltas (const contour_point_vector_t& contour_points)
{
for (tuple_delta_t& var : tuple_vars)
if (!var.calc_inferred_deltas (contour_points))
@@ -1447,10 +1551,21 @@ struct TupleVariationData
return true;
}
+ bool iup_optimize (const contour_point_vector_t& contour_points)
+ {
+ for (tuple_delta_t& var : tuple_vars)
+ {
+ if (!var.optimize (contour_points, is_composite))
+ return false;
+ }
+ return true;
+ }
+
public:
bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
- contour_point_vector_t* contour_points = nullptr)
+ contour_point_vector_t* contour_points = nullptr,
+ bool optimize = false)
{
if (!tuple_vars) return true;
if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances))
@@ -1460,7 +1575,14 @@ struct TupleVariationData
if (!calc_inferred_deltas (*contour_points))
return false;
- merge_tuple_variations ();
+ /* if iup delta opt is on, contour_points can't be null */
+ if (optimize && !contour_points)
+ return false;
+
+ if (!merge_tuple_variations (optimize ? contour_points : nullptr))
+ return false;
+
+ if (optimize && !iup_optimize (*contour_points)) return false;
return !tuple_vars.in_error ();
}
@@ -1475,21 +1597,27 @@ struct TupleVariationData
if (use_shared_points)
{
- shared_points_bytes = find_shared_points ();
- compiled_byte_size += shared_points_bytes.length;
+ find_shared_points ();
+ if (shared_points_bytes)
+ compiled_byte_size += shared_points_bytes->length;
}
// compile delta and tuple var header for each tuple variation
for (auto& tuple: tuple_vars)
{
const hb_vector_t<bool>* points_set = &(tuple.indices);
- hb_bytes_t *points_data;
+ hb_vector_t<char> *points_data;
if (unlikely (!point_data_map.has (points_set, &points_data)))
return false;
+ /* when iup optimization is enabled, num of referenced points could be 0
+ * and thus the compiled points bytes is empty, we should skip compiling
+ * this tuple */
+ if (!points_data->length)
+ continue;
if (!tuple.compile_deltas ())
return false;
- unsigned points_data_length = (*points_data != shared_points_bytes) ? points_data->length : 0;
+ unsigned points_data_length = (points_data != shared_points_bytes) ? points_data->length : 0;
if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
shared_tuples_idx_map))
return false;
@@ -1513,18 +1641,24 @@ struct TupleVariationData
bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
{
TRACE_SERIALIZE (this);
- if (is_gvar)
- shared_points_bytes.copy (c);
+ if (is_gvar && shared_points_bytes)
+ {
+ hb_bytes_t s (shared_points_bytes->arrayZ, shared_points_bytes->length);
+ s.copy (c);
+ }
for (const auto& tuple: tuple_vars)
{
const hb_vector_t<bool>* points_set = &(tuple.indices);
- hb_bytes_t *point_data;
+ hb_vector_t<char> *point_data;
if (!point_data_map.has (points_set, &point_data))
return_trace (false);
- if (!is_gvar || *point_data != shared_points_bytes)
- point_data->copy (c);
+ if (!is_gvar || point_data != shared_points_bytes)
+ {
+ hb_bytes_t s (point_data->arrayZ, point_data->length);
+ s.copy (c);
+ }
tuple.compiled_deltas.as_array ().copy (c);
if (c->in_error ()) return_trace (false);
@@ -1711,13 +1845,15 @@ struct TupleVariationData
const hb_map_t *axes_old_index_tag_map,
const hb_vector_t<unsigned> &shared_indices,
const hb_array_t<const F2DOT14> shared_tuples,
- tuple_variations_t& tuple_variations /* OUT */) const
+ tuple_variations_t& tuple_variations, /* OUT */
+ bool is_composite_glyph = false) const
{
return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
point_count, is_gvar,
axes_old_index_tag_map,
shared_indices,
- shared_tuples);
+ shared_tuples,
+ is_composite_glyph);
}
bool serialize (hb_serialize_context_t *c,
@@ -1831,7 +1967,7 @@ struct item_variations_t
const hb_map_t& get_varidx_map () const
{ return varidx_map; }
- bool instantiate (const VariationStore& varStore,
+ bool instantiate (const ItemVariationStore& varStore,
const hb_subset_plan_t *plan,
bool optimize=true,
bool use_no_variation_idx=true,
@@ -1845,7 +1981,7 @@ struct item_variations_t
}
/* keep below APIs public only for unit test: test-item-varstore */
- bool create_from_item_varstore (const VariationStore& varStore,
+ bool create_from_item_varstore (const ItemVariationStore& varStore,
const hb_map_t& axes_old_index_tag_map,
const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
index 1c7a1f6c1e..59aad57e37 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
@@ -101,10 +101,15 @@ struct glyph_variations_t
continue;
}
+ bool is_composite_glyph = false;
+#ifdef HB_EXPERIMENTAL_API
+ is_composite_glyph = plan->composite_new_gids.has (new_gid);
+#endif
if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */,
iterator, &(plan->axes_old_index_tag_map),
shared_indices, shared_tuples,
- tuple_vars /* OUT */))
+ tuple_vars, /* OUT */
+ is_composite_glyph))
return false;
glyph_variations.push (std::move (tuple_vars));
}
@@ -114,13 +119,17 @@ struct glyph_variations_t
bool instantiate (const hb_subset_plan_t *plan)
{
unsigned count = plan->new_to_old_gid_list.length;
+ bool iup_optimize = false;
+#ifdef HB_EXPERIMENTAL_API
+ iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS;
+#endif
for (unsigned i = 0; i < count; i++)
{
hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;
contour_point_vector_t *all_points;
if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
return false;
- if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points))
+ if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize))
return false;
}
return true;
@@ -340,7 +349,8 @@ struct gvar
const glyph_variations_t& glyph_vars,
Iterator it,
unsigned axis_count,
- unsigned num_glyphs) const
+ unsigned num_glyphs,
+ bool force_long_offsets) const
{
TRACE_SERIALIZE (this);
gvar *out = c->allocate_min<gvar> ();
@@ -352,7 +362,7 @@ struct gvar
out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
unsigned glyph_var_data_size = glyph_vars.compiled_byte_size ();
- bool long_offset = glyph_var_data_size & ~0xFFFFu;
+ bool long_offset = glyph_var_data_size & ~0xFFFFu || force_long_offsets;
out->flags = long_offset ? 1 : 0;
HBUINT8 *glyph_var_data_offsets = c->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
@@ -393,7 +403,12 @@ struct gvar
unsigned axis_count = c->plan->axes_index_map.get_population ();
unsigned num_glyphs = c->plan->num_output_glyphs ();
auto it = hb_iter (c->plan->new_to_old_gid_list);
- return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs));
+
+ bool force_long_offsets = false;
+#ifdef HB_EXPERIMENTAL_API
+ force_long_offsets = c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS;
+#endif
+ return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs, force_long_offsets));
}
bool subset (hb_subset_context_t *c) const
@@ -429,7 +444,7 @@ struct gvar
}
bool long_offset = (subset_data_size & ~0xFFFFu);
- #ifdef HB_EXPERIMENTAL_API
+#ifdef HB_EXPERIMENTAL_API
long_offset = long_offset || (c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
#endif
out->flags = long_offset ? 1 : 0;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
index 53a4642d38..33a4e1a40e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
@@ -188,7 +188,7 @@ struct hvarvvar_subset_plan_t
~hvarvvar_subset_plan_t() { fini (); }
void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps,
- const VariationStore &_var_store,
+ const ItemVariationStore &_var_store,
const hb_subset_plan_t *plan)
{
index_map_plans.resize (index_maps.length);
@@ -263,7 +263,7 @@ struct hvarvvar_subset_plan_t
hb_inc_bimap_t outer_map;
hb_vector_t<hb_inc_bimap_t> inner_maps;
hb_vector_t<index_map_subset_plan_t> index_map_plans;
- const VariationStore *var_store;
+ const ItemVariationStore *var_store;
protected:
hb_vector_t<hb_set_t *> inner_sets;
@@ -296,7 +296,7 @@ struct HVARVVAR
rsbMap.sanitize (c, this));
}
- const VariationStore& get_var_store () const
+ const ItemVariationStore& get_var_store () const
{ return this+varStore; }
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
@@ -384,7 +384,7 @@ struct HVARVVAR
float get_advance_delta_unscaled (hb_codepoint_t glyph,
const int *coords, unsigned int coord_count,
- VariationStore::cache_t *store_cache = nullptr) const
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
uint32_t varidx = (this+advMap).map (glyph);
return (this+varStore).get_delta (varidx,
@@ -405,7 +405,7 @@ struct HVARVVAR
public:
FixedVersion<>version; /* Version of the metrics variation table
* initially set to 0x00010000u */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to item variation store table. */
Offset32To<DeltaSetIndexMap>
advMap; /* Offset to advance var-idx mapping. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
index 6d69777618..1f0401d1d3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
@@ -56,7 +56,7 @@ struct VariationValueRecord
public:
Tag valueTag; /* Four-byte tag identifying a font-wide measure. */
- VarIdx varIdx; /* Outer/inner index into VariationStore item. */
+ VarIdx varIdx; /* Outer/inner index into ItemVariationStore item. */
public:
DEFINE_SIZE_STATIC (8);
@@ -106,7 +106,7 @@ struct MVAR
out->valueRecordCount = valueRecordCount;
item_variations_t item_vars;
- const VariationStore& src_var_store = this+varStore;
+ const ItemVariationStore& src_var_store = this+varStore;
if (!item_vars.instantiate (src_var_store, c->plan))
return_trace (false);
@@ -159,7 +159,7 @@ protected:
HBUINT16 valueRecordSize;/* The size in bytes of each value record —
* must be greater than zero. */
HBUINT16 valueRecordCount;/* The number of value records — may be zero. */
- Offset16To<VariationStore>
+ Offset16To<ItemVariationStore>
varStore; /* Offset to item variation store table. */
UnsizedArrayOf<HBUINT8>
valuesZ; /* Array of value records. The records must be
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
index 9b962a29d9..274d5df4c5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
@@ -163,7 +163,7 @@ struct hb_priority_queue_t
goto repeat;
}
- void swap (unsigned a, unsigned b)
+ void swap (unsigned a, unsigned b) noexcept
{
assert (a < heap.length);
assert (b < heap.length);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
index e9cd376ad3..ed40f271cc 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
@@ -239,6 +239,54 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& over
}
static inline
+bool _resolve_shared_overflow(const hb_vector_t<graph::overflow_record_t>& overflows,
+ int overflow_index,
+ graph_t& sorted_graph)
+{
+ const graph::overflow_record_t& r = overflows[overflow_index];
+
+ // Find all of the parents in overflowing links that link to this
+ // same child node. We will then try duplicating the child node and
+ // re-assigning all of these parents to the duplicate.
+ hb_set_t parents;
+ parents.add(r.parent);
+ for (int i = overflow_index - 1; i >= 0; i--) {
+ const graph::overflow_record_t& r2 = overflows[i];
+ if (r2.child == r.child) {
+ parents.add(r2.parent);
+ }
+ }
+
+ unsigned result = sorted_graph.duplicate(&parents, r.child);
+ if (result == (unsigned) -1 && parents.get_population() > 2) {
+ // All links to the child are overflowing, so we can't include all
+ // in the duplication. Remove one parent from the duplication.
+ // Remove the lowest index parent, which will be the closest to the child.
+ parents.del(parents.get_min());
+ result = sorted_graph.duplicate(&parents, r.child);
+ }
+
+ if (result == (unsigned) -1) return result;
+
+ if (parents.get_population() > 1) {
+ // If the duplicated node has more than one parent pre-emptively raise it's priority to the maximum.
+ // This will place it close to the parents. Node's with only one parent, don't need this as normal overflow
+ // resolution will raise priority if needed.
+ //
+ // Reasoning: most of the parents to this child are likely at the same layer in the graph. Duplicating
+ // the child will theoretically allow it to be placed closer to it's parents. However, due to the shortest
+ // distance sort by default it's placement will remain in the same layer, thus it will remain in roughly the
+ // same position (and distance from parents) as the original child node. The overflow resolution will attempt
+ // to move nodes closer, but only for non-shared nodes. Since this node is shared, it will simply be given
+ // further duplication which defeats the attempt to duplicate with multiple parents. To fix this we
+ // pre-emptively raise priority now which allows the duplicated node to pack into the same layer as it's parents.
+ sorted_graph.vertices_[result].give_max_priority();
+ }
+
+ return result;
+}
+
+static inline
bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
hb_set_t& priority_bumped_parents,
graph_t& sorted_graph)
@@ -254,7 +302,7 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
{
// The child object is shared, we may be able to eliminate the overflow
// by duplicating it.
- if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
+ if (!_resolve_shared_overflow(overflows, i, sorted_graph)) continue;
return true;
}
@@ -388,7 +436,7 @@ template<typename T>
inline hb_blob_t*
hb_resolve_overflows (const T& packed,
hb_tag_t table_tag,
- unsigned max_rounds = 20,
+ unsigned max_rounds = 32,
bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
if (sorted_graph.in_error ())
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
index 15eccb6a09..e988451eb3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
@@ -91,7 +91,27 @@ struct hb_serialize_context_t
}
#endif
- friend void swap (object_t& a, object_t& b)
+ bool add_virtual_link (objidx_t objidx)
+ {
+ if (!objidx)
+ return false;
+
+ auto& link = *virtual_links.push ();
+ if (virtual_links.in_error ())
+ return false;
+
+ link.objidx = objidx;
+ // Remaining fields were previously zero'd by push():
+ // link.width = 0;
+ // link.is_signed = 0;
+ // link.whence = 0;
+ // link.position = 0;
+ // link.bias = 0;
+
+ return true;
+ }
+
+ friend void swap (object_t& a, object_t& b) noexcept
{
hb_swap (a.head, b.head);
hb_swap (a.tail, b.tail);
@@ -156,9 +176,9 @@ struct hb_serialize_context_t
object_t *next;
auto all_links () const HB_AUTO_RETURN
- (( hb_concat (this->real_links, this->virtual_links) ));
+ (( hb_concat (real_links, virtual_links) ));
auto all_links_writer () HB_AUTO_RETURN
- (( hb_concat (this->real_links.writer (), this->virtual_links.writer ()) ));
+ (( hb_concat (real_links.writer (), virtual_links.writer ()) ));
};
struct snapshot_t
@@ -469,16 +489,40 @@ struct hb_serialize_context_t
assert (current);
- auto& link = *current->virtual_links.push ();
- if (current->virtual_links.in_error ())
+ if (!current->add_virtual_link(objidx))
err (HB_SERIALIZE_ERROR_OTHER);
+ }
- link.width = 0;
- link.objidx = objidx;
- link.is_signed = 0;
- link.whence = 0;
- link.position = 0;
- link.bias = 0;
+ objidx_t last_added_child_index() const {
+ if (unlikely (in_error ())) return (objidx_t) -1;
+
+ assert (current);
+ if (!bool(current->real_links)) {
+ return (objidx_t) -1;
+ }
+
+ return current->real_links[current->real_links.length - 1].objidx;
+ }
+
+ // For the current object ensure that the sub-table bytes for child objidx are always placed
+ // after the subtable bytes for any other existing children. This only ensures that the
+ // repacker will not move the target subtable before the other children
+ // (by adding virtual links). It is up to the caller to ensure the initial serialization
+ // order is correct.
+ void repack_last(objidx_t objidx) {
+ if (unlikely (in_error ())) return;
+
+ if (!objidx)
+ return;
+
+ assert (current);
+ for (auto& l : current->real_links) {
+ if (l.objidx == objidx) {
+ continue;
+ }
+
+ packed[l.objidx]->add_virtual_link(objidx);
+ }
}
template <typename T>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
index ff2a170d2d..ce69ea2c9b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
@@ -44,10 +44,10 @@ struct hb_sparseset_t
~hb_sparseset_t () { fini (); }
hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); }
- hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); }
+ hb_sparseset_t (hb_sparseset_t&& other) noexcept : hb_sparseset_t () { s = std::move (other.s); }
hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; }
- hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; }
- friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); }
+ hb_sparseset_t& operator = (hb_sparseset_t&& other) noexcept { s = std::move (other.s); return *this; }
+ friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) noexcept { hb_swap (a.s, b.s); }
hb_sparseset_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t ()
{
@@ -166,7 +166,7 @@ struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t>
~hb_set_t () = default;
hb_set_t () : sparseset () {};
hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {};
- hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {}
+ hb_set_t (hb_set_t&& o) noexcept : sparseset (std::move ((sparseset &) o)) {}
hb_set_t& operator = (const hb_set_t&) = default;
hb_set_t& operator = (hb_set_t&&) = default;
hb_set_t (std::initializer_list<hb_codepoint_t> lst) : sparseset (lst) {}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
index abc108e571..eb5cb0c625 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
@@ -248,7 +248,7 @@ struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs
struct cff2_private_blend_encoder_param_t
{
cff2_private_blend_encoder_param_t (hb_serialize_context_t *c,
- const CFF2VariationStore *varStore,
+ const CFF2ItemVariationStore *varStore,
hb_array_t<int> normalized_coords) :
c (c), varStore (varStore), normalized_coords (normalized_coords) {}
@@ -284,7 +284,7 @@ struct cff2_private_blend_encoder_param_t
unsigned ivs = 0;
unsigned region_count = 0;
hb_vector_t<float> scalars;
- const CFF2VariationStore *varStore = nullptr;
+ const CFF2ItemVariationStore *varStore = nullptr;
hb_array_t<int> normalized_coords;
};
@@ -378,7 +378,7 @@ struct cff2_private_dict_blend_opset_t : dict_opset_t
struct cff2_private_dict_op_serializer_t : op_serializer_t
{
cff2_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_, bool pinned_,
- const CFF::CFF2VariationStore* varStore_,
+ const CFF::CFF2ItemVariationStore* varStore_,
hb_array_t<int> normalized_coords_)
: desubroutinize (desubroutinize_), drop_hints (drop_hints_), pinned (pinned_),
varStore (varStore_), normalized_coords (normalized_coords_) {}
@@ -416,7 +416,7 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t
const bool desubroutinize;
const bool drop_hints;
const bool pinned;
- const CFF::CFF2VariationStore* varStore;
+ const CFF::CFF2ItemVariationStore* varStore;
hb_array_t<int> normalized_coords;
};
@@ -628,10 +628,10 @@ OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
}
/* variation store */
- if (varStore != &Null (CFF2VariationStore) &&
+ if (varStore != &Null (CFF2ItemVariationStore) &&
!plan.pinned)
{
- auto *dest = c->push<CFF2VariationStore> ();
+ auto *dest = c->push<CFF2ItemVariationStore> ();
if (unlikely (!dest->serialize (c, varStore)))
{
c->pop_discard ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
index 1e0a89a630..68a3e77788 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
@@ -24,6 +24,7 @@
* Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
*/
+#include "hb-subset-instancer-solver.hh"
#include "hb-subset.hh"
#include "hb-set.hh"
#include "hb-utf.hh"
@@ -50,7 +51,6 @@ hb_subset_input_t::hb_subset_input_t ()
HB_TAG ('k', 'e', 'r', 'n'),
// Copied from fontTools:
- HB_TAG ('B', 'A', 'S', 'E'),
HB_TAG ('J', 'S', 'T', 'F'),
HB_TAG ('D', 'S', 'I', 'G'),
HB_TAG ('E', 'B', 'D', 'T'),
@@ -418,6 +418,46 @@ hb_subset_input_keep_everything (hb_subset_input_t *input)
#ifndef HB_NO_VAR
/**
+ * hb_subset_input_pin_all_axes_to_default: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ *
+ * Pin all axes to default locations in the given subset input object.
+ *
+ * All axes in a font must be pinned. Additionally, `CFF2` table, if present,
+ * will be de-subroutinized.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 8.3.1
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input,
+ hb_face_t *face)
+{
+ unsigned axis_count = hb_ot_var_get_axis_count (face);
+ if (!axis_count) return false;
+
+ hb_ot_var_axis_info_t *axis_infos = (hb_ot_var_axis_info_t *) hb_calloc (axis_count, sizeof (hb_ot_var_axis_info_t));
+ if (unlikely (!axis_infos)) return false;
+
+ (void) hb_ot_var_get_axis_infos (face, 0, &axis_count, axis_infos);
+
+ for (unsigned i = 0; i < axis_count; i++)
+ {
+ hb_tag_t axis_tag = axis_infos[i].tag;
+ float default_val = axis_infos[i].default_value;
+ if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)))
+ {
+ hb_free (axis_infos);
+ return false;
+ }
+ }
+ hb_free (axis_infos);
+ return true;
+}
+
+/**
* hb_subset_input_pin_axis_to_default: (skip)
* @input: a #hb_subset_input_t object.
* @face: a #hb_face_t object.
@@ -481,16 +521,13 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
* @input: a #hb_subset_input_t object.
* @face: a #hb_face_t object.
* @axis_tag: Tag of the axis
- * @axis_min_value: Minimum value of the axis variation range to set
- * @axis_max_value: Maximum value of the axis variation range to set
- * @axis_def_value: Default value of the axis variation range to set, in case of
- * null, it'll be determined automatically
+ * @axis_min_value: Minimum value of the axis variation range to set, if NaN the existing min will be used.
+ * @axis_max_value: Maximum value of the axis variation range to set if NaN the existing max will be used.
+ * @axis_def_value: Default value of the axis variation range to set, if NaN the existing default will be used.
*
* Restricting the range of variation on an axis in the given subset input object.
* New min/default/max values will be clamped if they're not within the fvar axis range.
- * If the new default value is null:
- * If the fvar axis default value is within the new range, then new default
- * value is the same as original default value.
+ *
* If the fvar axis default value is not within the new range, the new default
* value will be changed to the new min or max value, whichever is closer to the fvar
* axis default.
@@ -509,21 +546,57 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
hb_tag_t axis_tag,
float axis_min_value,
float axis_max_value,
- float *axis_def_value /* IN, maybe NULL */)
+ float axis_def_value)
{
- if (axis_min_value > axis_max_value)
- return false;
-
hb_ot_var_axis_info_t axis_info;
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false;
- float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value);
- float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value);
- float new_default_val = axis_def_value ? *axis_def_value : axis_info.default_value;
- new_default_val = hb_clamp(new_default_val, new_min_val, new_max_val);
+ float min = !std::isnan(axis_min_value) ? axis_min_value : axis_info.min_value;
+ float max = !std::isnan(axis_max_value) ? axis_max_value : axis_info.max_value;
+ float def = !std::isnan(axis_def_value) ? axis_def_value : axis_info.default_value;
+
+ if (min > max)
+ return false;
+
+ float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value);
+ float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value);
+ float new_default_val = hb_clamp(def, new_min_val, new_max_val);
return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));
}
+
+/**
+ * hb_subset_input_get_axis_range: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis
+ * @axis_min_value: Set to the previously configured minimum value of the axis variation range.
+ * @axis_max_value: Set to the previously configured maximum value of the axis variation range.
+ * @axis_def_value: Set to the previously configured default value of the axis variation range.
+ *
+ * Gets the axis range assigned by previous calls to hb_subset_input_set_axis_range.
+ *
+ * Return value: `true` if a range has been set for this axis tag, `false` otherwise.
+ *
+ * XSince: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t *input,
+ hb_tag_t axis_tag,
+ float *axis_min_value,
+ float *axis_max_value,
+ float *axis_def_value)
+
+{
+ Triple* triple;
+ if (!input->axes_location.has(axis_tag, &triple)) {
+ return false;
+ }
+
+ *axis_min_value = triple->minimum;
+ *axis_def_value = triple->middle;
+ *axis_max_value = triple->maximum;
+ return true;
+}
#endif
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc
new file mode 100644
index 0000000000..35a964d082
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc
@@ -0,0 +1,532 @@
+/*
+ * Copyright © 2024 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-subset-instancer-iup.hh"
+
+/* This file is a straight port of the following:
+ *
+ * https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/varLib/iup.py
+ *
+ * Where that file returns optimzied deltas vector, we return optimized
+ * referenced point indices.
+ */
+
+constexpr static unsigned MAX_LOOKBACK = 8;
+
+static void _iup_contour_bound_forced_set (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ hb_set_t& forced_set, /* OUT */
+ float tolerance = 0.f)
+{
+ unsigned len = contour_points.length;
+ unsigned next_i = 0;
+ for (int i = len - 1; i >= 0; i--)
+ {
+ unsigned last_i = (len + i -1) % len;
+ for (unsigned j = 0; j < 2; j++)
+ {
+ float cj, lcj, ncj;
+ int dj, ldj, ndj;
+ if (j == 0)
+ {
+ cj = contour_points.arrayZ[i].x;
+ dj = x_deltas.arrayZ[i];
+ lcj = contour_points.arrayZ[last_i].x;
+ ldj = x_deltas.arrayZ[last_i];
+ ncj = contour_points.arrayZ[next_i].x;
+ ndj = x_deltas.arrayZ[next_i];
+ }
+ else
+ {
+ cj = contour_points.arrayZ[i].y;
+ dj = y_deltas.arrayZ[i];
+ lcj = contour_points.arrayZ[last_i].y;
+ ldj = y_deltas.arrayZ[last_i];
+ ncj = contour_points.arrayZ[next_i].y;
+ ndj = y_deltas.arrayZ[next_i];
+ }
+
+ float c1, c2;
+ int d1, d2;
+ if (lcj <= ncj)
+ {
+ c1 = lcj;
+ c2 = ncj;
+ d1 = ldj;
+ d2 = ndj;
+ }
+ else
+ {
+ c1 = ncj;
+ c2 = lcj;
+ d1 = ndj;
+ d2 = ldj;
+ }
+
+ bool force = false;
+ if (c1 == c2)
+ {
+ if (abs (d1 - d2) > tolerance && abs (dj) > tolerance)
+ force = true;
+ }
+ else if (c1 <= cj && cj <= c2)
+ {
+ if (!(hb_min (d1, d2) - tolerance <= dj &&
+ dj <= hb_max (d1, d2) + tolerance))
+ force = true;
+ }
+ else
+ {
+ if (d1 != d2)
+ {
+ if (cj < c1)
+ {
+ if (abs (dj) > tolerance &&
+ abs (dj - d1) > tolerance &&
+ ((dj - tolerance < d1) != (d1 < d2)))
+ force = true;
+ }
+ else
+ {
+ if (abs (dj) > tolerance &&
+ abs (dj - d2) > tolerance &&
+ ((d2 < dj + tolerance) != (d1 < d2)))
+ force = true;
+ }
+ }
+ }
+
+ if (force)
+ {
+ forced_set.add (i);
+ break;
+ }
+ }
+ next_i = i;
+ }
+}
+
+template <typename T,
+ hb_enable_if (hb_is_trivially_copyable (T))>
+static bool rotate_array (const hb_array_t<const T>& org_array,
+ int k,
+ hb_vector_t<T>& out)
+{
+ unsigned n = org_array.length;
+ if (!n) return true;
+ if (unlikely (!out.resize (n, false)))
+ return false;
+
+ unsigned item_size = hb_static_size (T);
+ if (k < 0)
+ k = n - (-k) % n;
+ else
+ k %= n;
+
+ hb_memcpy ((void *) out.arrayZ, (const void *) (org_array.arrayZ + n - k), k * item_size);
+ hb_memcpy ((void *) (out.arrayZ + k), (const void *) org_array.arrayZ, (n - k) * item_size);
+ return true;
+}
+
+static bool rotate_set (const hb_set_t& org_set,
+ int k,
+ unsigned n,
+ hb_set_t& out)
+{
+ if (!n) return false;
+ k %= n;
+ if (k < 0)
+ k = n + k;
+
+ if (k == 0)
+ {
+ out.set (org_set);
+ }
+ else
+ {
+ for (auto v : org_set)
+ out.add ((v + k) % n);
+ }
+ return !out.in_error ();
+}
+
+/* Given two reference coordinates (start and end of contour_points array),
+ * output interpolated deltas for points in between */
+static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ const contour_point_t& p1, const contour_point_t& p2,
+ int p1_dx, int p2_dx,
+ int p1_dy, int p2_dy,
+ hb_vector_t<float>& interp_x_deltas, /* OUT */
+ hb_vector_t<float>& interp_y_deltas /* OUT */)
+{
+ unsigned n = contour_points.length;
+ if (unlikely (!interp_x_deltas.resize (n, false) ||
+ !interp_y_deltas.resize (n, false)))
+ return false;
+
+ for (unsigned j = 0; j < 2; j++)
+ {
+ float x1, x2, d1, d2;
+ float *out;
+ if (j == 0)
+ {
+ x1 = p1.x;
+ x2 = p2.x;
+ d1 = p1_dx;
+ d2 = p2_dx;
+ out = interp_x_deltas.arrayZ;
+ }
+ else
+ {
+ x1 = p1.y;
+ x2 = p2.y;
+ d1 = p1_dy;
+ d2 = p2_dy;
+ out = interp_y_deltas.arrayZ;
+ }
+
+ if (x1 == x2)
+ {
+ if (d1 == d2)
+ {
+ for (unsigned i = 0; i < n; i++)
+ out[i] = d1;
+ }
+ else
+ {
+ for (unsigned i = 0; i < n; i++)
+ out[i] = 0.f;
+ }
+ continue;
+ }
+
+ if (x1 > x2)
+ {
+ hb_swap (x1, x2);
+ hb_swap (d1, d2);
+ }
+
+ float scale = (d2 - d1) / (x2 - x1);
+ for (unsigned i = 0; i < n; i++)
+ {
+ float x = j == 0 ? contour_points.arrayZ[i].x : contour_points.arrayZ[i].y;
+ float d;
+ if (x <= x1)
+ d = d1;
+ else if (x >= x2)
+ d = d2;
+ else
+ d = d1 + (x - x1) * scale;
+
+ out[i] = d;
+ }
+ }
+ return true;
+}
+
+static bool _can_iup_in_between (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ const contour_point_t& p1, const contour_point_t& p2,
+ int p1_dx, int p2_dx,
+ int p1_dy, int p2_dy,
+ float tolerance)
+{
+ hb_vector_t<float> interp_x_deltas, interp_y_deltas;
+ if (!_iup_segment (contour_points, x_deltas, y_deltas,
+ p1, p2, p1_dx, p2_dx, p1_dy, p2_dy,
+ interp_x_deltas, interp_y_deltas))
+ return false;
+
+ unsigned num = contour_points.length;
+
+ for (unsigned i = 0; i < num; i++)
+ {
+ float dx = x_deltas.arrayZ[i] - interp_x_deltas.arrayZ[i];
+ float dy = y_deltas.arrayZ[i] - interp_y_deltas.arrayZ[i];
+
+ if (sqrtf ((float)dx * dx + (float)dy * dy) > tolerance)
+ return false;
+ }
+ return true;
+}
+
+static bool _iup_contour_optimize_dp (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ const hb_set_t& forced_set,
+ float tolerance,
+ unsigned lookback,
+ hb_vector_t<unsigned>& costs, /* OUT */
+ hb_vector_t<int>& chain /* OUT */)
+{
+ unsigned n = contour_points.length;
+ if (unlikely (!costs.resize (n, false) ||
+ !chain.resize (n, false)))
+ return false;
+
+ lookback = hb_min (lookback, MAX_LOOKBACK);
+
+ for (unsigned i = 0; i < n; i++)
+ {
+ unsigned best_cost = (i == 0 ? 1 : costs.arrayZ[i-1] + 1);
+
+ costs.arrayZ[i] = best_cost;
+ chain.arrayZ[i] = (i == 0 ? -1 : i - 1);
+
+ if (i > 0 && forced_set.has (i - 1))
+ continue;
+
+ int lookback_index = hb_max ((int) i - (int) lookback + 1, -1);
+ for (int j = i - 2; j >= lookback_index; j--)
+ {
+ unsigned cost = j == -1 ? 1 : costs.arrayZ[j] + 1;
+ /* num points between i and j */
+ unsigned num_points = i - j - 1;
+ unsigned p1 = (j == -1 ? n - 1 : j);
+ if (cost < best_cost &&
+ _can_iup_in_between (contour_points.as_array ().sub_array (j + 1, num_points),
+ x_deltas.as_array ().sub_array (j + 1, num_points),
+ y_deltas.as_array ().sub_array (j + 1, num_points),
+ contour_points.arrayZ[p1], contour_points.arrayZ[i],
+ x_deltas.arrayZ[p1], x_deltas.arrayZ[i],
+ y_deltas.arrayZ[p1], y_deltas.arrayZ[i],
+ tolerance))
+ {
+ best_cost = cost;
+ costs.arrayZ[i] = best_cost;
+ chain.arrayZ[i] = j;
+ }
+
+ if (j > 0 && forced_set.has (j))
+ break;
+ }
+ }
+ return true;
+}
+
+static bool _iup_contour_optimize (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ hb_array_t<bool> opt_indices, /* OUT */
+ float tolerance = 0.f)
+{
+ unsigned n = contour_points.length;
+ if (opt_indices.length != n ||
+ x_deltas.length != n ||
+ y_deltas.length != n)
+ return false;
+
+ bool all_within_tolerance = true;
+ for (unsigned i = 0; i < n; i++)
+ {
+ int dx = x_deltas.arrayZ[i];
+ int dy = y_deltas.arrayZ[i];
+ if (sqrtf ((float)dx * dx + (float)dy * dy) > tolerance)
+ {
+ all_within_tolerance = false;
+ break;
+ }
+ }
+
+ /* If all are within tolerance distance, do nothing, opt_indices is
+ * initilized to false */
+ if (all_within_tolerance)
+ return true;
+
+ /* If there's exactly one point, return it */
+ if (n == 1)
+ {
+ opt_indices.arrayZ[0] = true;
+ return true;
+ }
+
+ /* If all deltas are exactly the same, return just one (the first one) */
+ bool all_deltas_are_equal = true;
+ for (unsigned i = 1; i < n; i++)
+ if (x_deltas.arrayZ[i] != x_deltas.arrayZ[0] ||
+ y_deltas.arrayZ[i] != y_deltas.arrayZ[0])
+ {
+ all_deltas_are_equal = false;
+ break;
+ }
+
+ if (all_deltas_are_equal)
+ {
+ opt_indices.arrayZ[0] = true;
+ return true;
+ }
+
+ /* else, solve the general problem using Dynamic Programming */
+ hb_set_t forced_set;
+ _iup_contour_bound_forced_set (contour_points, x_deltas, y_deltas, forced_set, tolerance);
+
+ if (!forced_set.is_empty ())
+ {
+ int k = n - 1 - forced_set.get_max ();
+ if (k < 0)
+ return false;
+
+ hb_vector_t<int> rot_x_deltas, rot_y_deltas;
+ contour_point_vector_t rot_points;
+ hb_set_t rot_forced_set;
+ if (!rotate_array (contour_points, k, rot_points) ||
+ !rotate_array (x_deltas, k, rot_x_deltas) ||
+ !rotate_array (y_deltas, k, rot_y_deltas) ||
+ !rotate_set (forced_set, k, n, rot_forced_set))
+ return false;
+
+ hb_vector_t<unsigned> costs;
+ hb_vector_t<int> chain;
+
+ if (!_iup_contour_optimize_dp (rot_points, rot_x_deltas, rot_y_deltas,
+ rot_forced_set, tolerance, n,
+ costs, chain))
+ return false;
+
+ hb_set_t solution;
+ int index = n - 1;
+ while (index != -1)
+ {
+ solution.add (index);
+ index = chain.arrayZ[index];
+ }
+
+ if (solution.is_empty () ||
+ forced_set.get_population () > solution.get_population ())
+ return false;
+
+ for (unsigned i : solution)
+ opt_indices.arrayZ[i] = true;
+
+ hb_vector_t<bool> rot_indices;
+ const hb_array_t<const bool> opt_indices_array (opt_indices.arrayZ, opt_indices.length);
+ rotate_array (opt_indices_array, -k, rot_indices);
+
+ for (unsigned i = 0; i < n; i++)
+ opt_indices.arrayZ[i] = rot_indices.arrayZ[i];
+ }
+ else
+ {
+ hb_vector_t<int> repeat_x_deltas, repeat_y_deltas;
+ contour_point_vector_t repeat_points;
+
+ if (unlikely (!repeat_x_deltas.resize (n * 2, false) ||
+ !repeat_y_deltas.resize (n * 2, false) ||
+ !repeat_points.resize (n * 2, false)))
+ return false;
+
+ unsigned contour_point_size = hb_static_size (contour_point_t);
+ for (unsigned i = 0; i < n; i++)
+ {
+ hb_memcpy ((void *) repeat_x_deltas.arrayZ, (const void *) x_deltas.arrayZ, n * sizeof (float));
+ hb_memcpy ((void *) (repeat_x_deltas.arrayZ + n), (const void *) x_deltas.arrayZ, n * sizeof (float));
+
+ hb_memcpy ((void *) repeat_y_deltas.arrayZ, (const void *) y_deltas.arrayZ, n * sizeof (float));
+ hb_memcpy ((void *) (repeat_y_deltas.arrayZ + n), (const void *) y_deltas.arrayZ, n * sizeof (float));
+
+ hb_memcpy ((void *) repeat_points.arrayZ, (const void *) contour_points.arrayZ, n * contour_point_size);
+ hb_memcpy ((void *) (repeat_points.arrayZ + n), (const void *) contour_points.arrayZ, n * contour_point_size);
+ }
+
+ hb_vector_t<unsigned> costs;
+ hb_vector_t<int> chain;
+ if (!_iup_contour_optimize_dp (repeat_points, repeat_x_deltas, repeat_y_deltas,
+ forced_set, tolerance, n,
+ costs, chain))
+ return false;
+
+ unsigned best_cost = n + 1;
+ int len = costs.length;
+ hb_set_t best_sol;
+ for (int start = n - 1; start < len; start++)
+ {
+ hb_set_t solution;
+ int i = start;
+ int lookback = start - (int) n;
+ while (i > lookback)
+ {
+ solution.add (i % n);
+ i = chain.arrayZ[i];
+ }
+ if (i == lookback)
+ {
+ unsigned cost_i = i < 0 ? 0 : costs.arrayZ[i];
+ unsigned cost = costs.arrayZ[start] - cost_i;
+ if (cost <= best_cost)
+ {
+ best_sol.set (solution);
+ best_cost = cost;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < n; i++)
+ if (best_sol.has (i))
+ opt_indices.arrayZ[i] = true;
+ }
+ return true;
+}
+
+bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ hb_vector_t<bool>& opt_indices, /* OUT */
+ float tolerance)
+{
+ if (!opt_indices.resize (contour_points.length))
+ return false;
+
+ hb_vector_t<unsigned> end_points;
+ unsigned count = contour_points.length;
+ if (unlikely (!end_points.alloc (count)))
+ return false;
+
+ for (unsigned i = 0; i < count - 4; i++)
+ if (contour_points.arrayZ[i].is_end_point)
+ end_points.push (i);
+
+ /* phantom points */
+ for (unsigned i = count - 4; i < count; i++)
+ end_points.push (i);
+
+ if (end_points.in_error ()) return false;
+
+ unsigned start = 0;
+ for (unsigned end : end_points)
+ {
+ unsigned len = end - start + 1;
+ if (!_iup_contour_optimize (contour_points.as_array ().sub_array (start, len),
+ x_deltas.as_array ().sub_array (start, len),
+ y_deltas.as_array ().sub_array (start, len),
+ opt_indices.as_array ().sub_array (start, len),
+ tolerance))
+ return false;
+ start = end + 1;
+ }
+ return true;
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh
new file mode 100644
index 0000000000..7eac5935a4
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2024 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_SUBSET_INSTANCER_IUP_HH
+#define HB_SUBSET_INSTANCER_IUP_HH
+
+#include "hb-subset-plan.hh"
+/* given contour points and deltas, optimize a set of referenced points within error
+ * tolerance. Returns optimized referenced point indices */
+HB_INTERNAL bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ hb_vector_t<bool>& opt_indices, /* OUT */
+ float tolerance = 0.f);
+
+#endif /* HB_SUBSET_INSTANCER_IUP_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
index 4876bc4379..70783c0a0d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
@@ -256,7 +256,10 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
*/
float newUpper = peak + (1 - gain) * (upper - peak);
assert (axisMax <= newUpper); // Because outGain > gain
- if (newUpper <= axisDef + (axisMax - axisDef) * 2)
+ /* Disabled because ots doesn't like us:
+ * https://github.com/fonttools/fonttools/issues/3350 */
+
+ if (false && (newUpper <= axisDef + (axisMax - axisDef) * 2))
{
upper = newUpper;
if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
index 71da80e387..74416b92f9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
@@ -140,6 +140,15 @@ HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_height_vec)
//map: new_gid -> contour points vector
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, contour_point_vector_t>), new_gid_contour_points_map)
+//new gids set for composite glyphs
+HB_SUBSET_PLAN_MEMBER (hb_set_t, composite_new_gids)
+
+//Old BASE item variation index -> (New varidx, 0) mapping
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), base_variation_idx_map)
+
+//BASE table varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, base_varstore_inner_maps)
+
#ifdef HB_EXPERIMENTAL_API
// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
// None to indicate should remove
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
index 5786223196..068fddaedd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
@@ -32,6 +32,7 @@
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
+#include "hb-ot-layout-base-table.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-gsub-table.hh"
@@ -431,6 +432,52 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
gdef.destroy ();
gpos.destroy ();
}
+
+#ifndef HB_NO_BASE
+/* used by BASE table only, delta is always set to 0 in the output map */
+static inline void
+_remap_variation_indices (const hb_set_t& indices,
+ unsigned subtable_count,
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& variation_idx_delta_map /* OUT */)
+{
+ unsigned new_major = 0, new_minor = 0;
+ unsigned last_major = (indices.get_min ()) >> 16;
+ for (unsigned idx : indices)
+ {
+ uint16_t major = idx >> 16;
+ if (major >= subtable_count) break;
+ if (major != last_major)
+ {
+ new_minor = 0;
+ ++new_major;
+ }
+
+ unsigned new_idx = (new_major << 16) + new_minor;
+ variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (new_idx, 0));
+ ++new_minor;
+ last_major = major;
+ }
+}
+
+static inline void
+_collect_base_variation_indices (hb_subset_plan_t* plan)
+{
+ hb_blob_ptr_t<OT::BASE> base = plan->source_table<OT::BASE> ();
+ if (!base->has_var_store ())
+ {
+ base.destroy ();
+ return;
+ }
+
+ hb_set_t varidx_set;
+ base->collect_variation_indices (plan, varidx_set);
+ unsigned subtable_count = base->get_var_store ().get_sub_table_count ();
+ base.destroy ();
+
+ _remap_variation_indices (varidx_set, subtable_count, plan->base_variation_idx_map);
+ _generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps);
+}
+#endif
#endif
static inline void
@@ -994,8 +1041,8 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
OT::cff2::accelerator_t cff2 (plan->source);
if (!cff2.is_valid ()) return;
- hb_font_t *font = nullptr;
- if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
+ hb_font_t *font = _get_hb_font_with_variations (plan);
+ if (unlikely (!plan->check_success (font != nullptr)))
{
hb_font_destroy (font);
return;
@@ -1073,8 +1120,8 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
static bool
_get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
{
- /* contour_points vector only needed for updating gvar table (infer delta)
- * during partial instancing */
+ /* contour_points vector only needed for updating gvar table (infer delta and
+ * iup delta optimization) during partial instancing */
if (plan->user_axes_location.is_empty () || plan->all_axes_pinned)
return true;
@@ -1092,10 +1139,17 @@ _get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
}
hb_codepoint_t old_gid = _.second;
- if (unlikely (!glyf.glyph_for_gid (old_gid).get_all_points_without_var (plan->source, all_points)))
+ auto glyph = glyf.glyph_for_gid (old_gid);
+ if (unlikely (!glyph.get_all_points_without_var (plan->source, all_points)))
return false;
if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
return false;
+
+#ifdef HB_EXPERIMENTAL_API
+ /* composite new gids are only needed by iup delta optimization */
+ if ((plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS) && glyph.is_composite ())
+ plan->composite_new_gids.add (new_gid);
+#endif
}
return true;
}
@@ -1205,6 +1259,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
if (!drop_tables.has (HB_OT_TAG_GDEF))
_remap_used_mark_sets (this, used_mark_sets_map);
+#ifndef HB_NO_VAR
+#ifndef HB_NO_BASE
+ if (!drop_tables.has (HB_OT_TAG_BASE))
+ _collect_base_variation_indices (this);
+#endif
+#endif
+
if (unlikely (in_error ()))
return;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
index 1f19a58c1e..19a9fa6918 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
@@ -78,6 +78,13 @@ struct contour_point_t
y = x * matrix[1] + y * matrix[3];
x = x_;
}
+
+ void add_delta (float delta_x, float delta_y)
+ {
+ x += delta_x;
+ y += delta_y;
+ }
+
HB_ALWAYS_INLINE
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
@@ -99,6 +106,22 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t>
unsigned count = a.length;
hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
}
+
+ bool add_deltas (const hb_vector_t<float> deltas_x,
+ const hb_vector_t<float> deltas_y,
+ const hb_vector_t<bool> indices)
+ {
+ if (indices.length != deltas_x.length ||
+ indices.length != deltas_y.length)
+ return false;
+
+ for (unsigned i = 0; i < indices.length; i++)
+ {
+ if (!indices.arrayZ[i]) continue;
+ arrayZ[i].add_delta (deltas_x.arrayZ[i], deltas_y.arrayZ[i]);
+ }
+ return true;
+ }
};
namespace OT {
@@ -147,7 +170,7 @@ struct hb_subset_plan_t
bool gsub_insert_catch_all_feature_variation_rec;
bool gpos_insert_catch_all_feature_variation_rec;
- // whether GDEF VarStore is retained
+ // whether GDEF ItemVariationStore is retained
mutable bool has_gdef_varstore;
#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
index 06e77dd8eb..f10ef54dbd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
@@ -48,6 +48,7 @@
#include "hb-ot-cff2-table.hh"
#include "hb-ot-vorg-table.hh"
#include "hb-ot-name-table.hh"
+#include "hb-ot-layout-base-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-var-avar-table.hh"
@@ -503,6 +504,7 @@ _subset_table (hb_subset_plan_t *plan,
case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf);
case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf);
+ case HB_OT_TAG_BASE: return _subset<const OT::BASE> (plan, buf);
#ifndef HB_NO_SUBSET_CFF
case HB_OT_TAG_CFF1: return _subset<const OT::cff1> (plan, buf);
@@ -548,6 +550,7 @@ _subset_table (hb_subset_plan_t *plan,
}
#endif
return _passthrough (plan, tag);
+
default:
if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
return _passthrough (plan, tag);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.h b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
index d79e7f762a..73dcae4660 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
@@ -76,6 +76,8 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset
* to allow it to be used with incremental font transfer IFTB patches. Primarily,
* this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL
+ * @HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS: If set perform IUP delta optimization on the
+ * remaining gvar table's deltas. Since: EXPERIMENTAL
*
* List of boolean properties that can be configured on the subset input.
*
@@ -95,6 +97,7 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
#ifdef HB_EXPERIMENTAL_API
HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00000400u,
+ HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS = 0x00000800u,
#endif
} hb_subset_flags_t;
@@ -171,6 +174,10 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
unsigned value);
HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input,
+ hb_face_t *face);
+
+HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag);
@@ -183,12 +190,19 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t *input,
+ hb_tag_t axis_tag,
+ float *axis_min_value,
+ float *axis_max_value,
+ float *axis_def_value);
+
+HB_EXTERN hb_bool_t
hb_subset_input_set_axis_range (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag,
float axis_min_value,
float axis_max_value,
- float *axis_def_value);
+ float axis_def_value);
HB_EXTERN hb_bool_t
hb_subset_input_override_name_table (hb_subset_input_t *input,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
index dfe1b7d1c7..c0cc7063ff 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
@@ -78,7 +78,7 @@ struct hb_vector_t
if (unlikely (in_error ())) return;
copy_array (o);
}
- hb_vector_t (hb_vector_t &&o)
+ hb_vector_t (hb_vector_t &&o) noexcept
{
allocated = o.allocated;
length = o.length;
@@ -122,7 +122,7 @@ struct hb_vector_t
resize (0);
}
- friend void swap (hb_vector_t& a, hb_vector_t& b)
+ friend void swap (hb_vector_t& a, hb_vector_t& b) noexcept
{
hb_swap (a.allocated, b.allocated);
hb_swap (a.length, b.length);
@@ -139,7 +139,7 @@ struct hb_vector_t
return *this;
}
- hb_vector_t& operator = (hb_vector_t &&o)
+ hb_vector_t& operator = (hb_vector_t &&o) noexcept
{
hb_swap (*this, o);
return *this;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h
index b08dd1f09f..68681874ca 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-version.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h
@@ -47,7 +47,7 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 3
+#define HB_VERSION_MINOR 4
/**
* HB_VERSION_MICRO:
*
@@ -60,7 +60,7 @@ HB_BEGIN_DECLS
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "8.3.0"
+#define HB_VERSION_STRING "8.4.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
index a70b766646..a8b91879a4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
@@ -240,7 +240,7 @@ acquire_shape_plan (hb_face_t *face,
goto fail;
}
- func = wasm_runtime_lookup_function (module_inst, "shape_plan_create", nullptr);
+ func = wasm_runtime_lookup_function (module_inst, "shape_plan_create");
if (func)
{
wasm_val_t results[1];
@@ -297,7 +297,7 @@ release_shape_plan (const hb_wasm_face_data_t *face_data,
if (plan->wasm_shape_planptr)
{
- auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy", nullptr);
+ auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy");
if (func)
{
wasm_val_t arguments[1];
@@ -395,7 +395,7 @@ retry:
goto fail;
}
- func = wasm_runtime_lookup_function (module_inst, "shape", nullptr);
+ func = wasm_runtime_lookup_function (module_inst, "shape");
if (unlikely (!func))
{
DEBUG_MSG (WASM, module_inst, "Shape function not found.");
diff --git a/src/3rdparty/harfbuzz-ng/src/hb.hh b/src/3rdparty/harfbuzz-ng/src/hb.hh
index 972608d6a3..0ceeb99f50 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb.hh
@@ -64,6 +64,7 @@
#pragma GCC diagnostic error "-Wbitwise-instead-of-logical"
#pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type"
+#pragma GCC diagnostic error "-Wcast-function-type-strict"
#pragma GCC diagnostic error "-Wconstant-conversion"
#pragma GCC diagnostic error "-Wcomma"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
@@ -177,6 +178,11 @@
#define HB_EXTERN __declspec (dllexport) extern
#endif
+// https://github.com/harfbuzz/harfbuzz/pull/4619
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
+
#include "hb.h"
#define HB_H_IN
#include "hb-ot.h"
@@ -212,6 +218,12 @@
#include <winapifamily.h>
#endif
+#ifndef PRId32
+# define PRId32 "d"
+# define PRIu32 "u"
+# define PRIx32 "x"
+#endif
+
#define HB_PASTE1(a,b) a##b
#define HB_PASTE(a,b) HB_PASTE1(a,b)
diff --git a/src/3rdparty/libjpeg/LICENSE b/src/3rdparty/libjpeg/LICENSE
index bf8a7fda7f..2204864fa1 100644
--- a/src/3rdparty/libjpeg/LICENSE
+++ b/src/3rdparty/libjpeg/LICENSE
@@ -1,30 +1,33 @@
libjpeg-turbo Licenses
======================
-libjpeg-turbo is covered by three compatible BSD-style open source licenses:
+libjpeg-turbo is covered by two compatible BSD-style open source licenses:
- The IJG (Independent JPEG Group) License, which is listed in
[README.ijg](README.ijg)
- This license applies to the libjpeg API library and associated programs
- (any code inherited from libjpeg, and any modifications to that code.)
+ This license applies to the libjpeg API library and associated programs,
+ including any code inherited from libjpeg and any modifications to that
+ code. Note that the libjpeg-turbo SIMD source code bears the
+ [zlib License](https://opensource.org/licenses/Zlib), but in the context of
+ the overall libjpeg API library, the terms of the zlib License are subsumed
+ by the terms of the IJG License.
- The Modified (3-clause) BSD License, which is listed below
- This license covers the TurboJPEG API library and associated programs, as
- well as the build system.
-
-- The [zlib License](https://opensource.org/licenses/Zlib)
-
- This license is a subset of the other two, and it covers the libjpeg-turbo
- SIMD extensions.
+ This license applies to the TurboJPEG API library and associated programs, as
+ well as the build system. Note that the TurboJPEG API library wraps the
+ libjpeg API library, so in the context of the overall TurboJPEG API library,
+ both the terms of the IJG License and the terms of the Modified (3-clause)
+ BSD License apply.
Complying with the libjpeg-turbo Licenses
=========================================
This section provides a roll-up of the libjpeg-turbo licensing terms, to the
-best of our understanding.
+best of our understanding. This is not a license in and of itself. It is
+intended solely for clarification.
1. If you are distributing a modified version of the libjpeg-turbo source,
then:
@@ -38,7 +41,7 @@ best of our understanding.
- Clauses 1 and 3 of the zlib License
2. You must add your own copyright notice to the header of each source
- file you modified, so others can tell that you modified that file (if
+ file you modified, so others can tell that you modified that file. (If
there is not an existing copyright header in that file, then you can
simply add a notice stating that you modified the file.)
@@ -119,8 +122,8 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-Why Three Licenses?
-===================
+Why Two Licenses?
+=================
The zlib License could have been used instead of the Modified (3-clause) BSD
License, and since the IJG License effectively subsumes the distribution
diff --git a/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh b/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh
index fea6c5c9b4..0c984a8eed 100755
--- a/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh
+++ b/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh
@@ -145,7 +145,7 @@ sed -i -e "s/@COPYRIGHT_YEAR@/$cyear/" $TARGET_DIR/src/jversion.h
sed -n -e 's/^[ ]*"//
s/\(\\n\)*"[ ]*\\*$//
- /JCOPYRIGHT\ /,/^[ ]*$/ {
+ /JCOPYRIGHT.\ /,/^[ ]*$/ {
/Copyright/p
}
' $TARGET_DIR/src/jversion.h > $TARGET_DIR/COPYRIGHT.txt
diff --git a/src/3rdparty/libjpeg/qt_attribution.json b/src/3rdparty/libjpeg/qt_attribution.json
index 0b06d5c01e..a73ef1572d 100644
--- a/src/3rdparty/libjpeg/qt_attribution.json
+++ b/src/3rdparty/libjpeg/qt_attribution.json
@@ -7,11 +7,11 @@
"Description": "The Independent JPEG Group's JPEG software",
"Homepage": "http://libjpeg-turbo.virtualgl.org/",
- "Version": "3.0.2",
- "DownloadLocation": "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.0.2/libjpeg-turbo-3.0.2.tar.gz",
+ "Version": "3.0.3",
+ "DownloadLocation": "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.0.3/libjpeg-turbo-3.0.3.tar.gz",
"License": "Independent JPEG Group License and BSD 3-Clause \"New\" or \"Revised\" License and zlib License",
- "LicenseId": "IJG AND BSD-3-Clause AND Zlib",
- "LicenseFiles": [ "LICENSE", "ijg-license.txt", "zlib-license.txt"],
+ "LicenseId": "IJG AND BSD-3-Clause",
+ "LicenseFiles": [ "LICENSE", "ijg-license.txt" ],
"CopyrightFile": "COPYRIGHT.txt"
}
diff --git a/src/3rdparty/libjpeg/src/ChangeLog.md b/src/3rdparty/libjpeg/src/ChangeLog.md
index a929b62a8c..8039c5536d 100644
--- a/src/3rdparty/libjpeg/src/ChangeLog.md
+++ b/src/3rdparty/libjpeg/src/ChangeLog.md
@@ -1,3 +1,27 @@
+3.0.3
+=====
+
+### Significant changes relative to 3.0.2:
+
+1. Fixed an issue in the build system, introduced in 3.0.2, that caused all
+libjpeg-turbo components to depend on the Visual C++ run-time DLL when built
+with Visual C++ and CMake 3.15 or later, regardless of value of the
+`WITH_CRT_DLL` CMake variable.
+
+2. The x86-64 SIMD extensions now include support for Intel Control-flow
+Enforcement Technology (CET), which is enabled automatically if CET is enabled
+in the C compiler.
+
+3. Fixed a regression introduced by 3.0 beta2[6] that made it impossible for
+calling applications to supply custom Huffman tables when generating
+12-bit-per-component lossy JPEG images using the libjpeg API.
+
+4. Fixed a segfault that occurred when attempting to use the jpegtran `-drop`
+option with a specially-crafted malformed input image or drop image
+(specifically an image in which all of the scans contain fewer components than
+the number of components specified in the Start Of Frame segment.)
+
+
3.0.2
=====
diff --git a/src/3rdparty/libjpeg/src/jcmaster.c b/src/3rdparty/libjpeg/src/jcmaster.c
index 7e1408fcc9..161019763d 100644
--- a/src/3rdparty/libjpeg/src/jcmaster.c
+++ b/src/3rdparty/libjpeg/src/jcmaster.c
@@ -7,7 +7,7 @@
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2016, 2018, 2022-2023, D. R. Commander.
+ * Copyright (C) 2010, 2016, 2018, 2022-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -50,6 +50,113 @@ jpeg_calc_jpeg_dimensions(j_compress_ptr cinfo)
#endif
+LOCAL(boolean)
+using_std_huff_tables(j_compress_ptr cinfo)
+{
+ int i;
+
+ static const UINT8 bits_dc_luminance[17] = {
+ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+ };
+ static const UINT8 val_dc_luminance[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+ };
+
+ static const UINT8 bits_dc_chrominance[17] = {
+ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+ };
+ static const UINT8 val_dc_chrominance[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+ };
+
+ static const UINT8 bits_ac_luminance[17] = {
+ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+ };
+ static const UINT8 val_ac_luminance[] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ static const UINT8 bits_ac_chrominance[17] = {
+ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+ };
+ static const UINT8 val_ac_chrominance[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ if (cinfo->dc_huff_tbl_ptrs[0] == NULL ||
+ cinfo->ac_huff_tbl_ptrs[0] == NULL ||
+ cinfo->dc_huff_tbl_ptrs[1] == NULL ||
+ cinfo->ac_huff_tbl_ptrs[1] == NULL)
+ return FALSE;
+
+ for (i = 2; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL ||
+ cinfo->ac_huff_tbl_ptrs[i] != NULL)
+ return FALSE;
+ }
+
+ if (memcmp(cinfo->dc_huff_tbl_ptrs[0]->bits, bits_dc_luminance,
+ sizeof(bits_dc_luminance)) ||
+ memcmp(cinfo->dc_huff_tbl_ptrs[0]->huffval, val_dc_luminance,
+ sizeof(val_dc_luminance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[0]->bits, bits_ac_luminance,
+ sizeof(bits_ac_luminance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[0]->huffval, val_ac_luminance,
+ sizeof(val_ac_luminance)) ||
+ memcmp(cinfo->dc_huff_tbl_ptrs[1]->bits, bits_dc_chrominance,
+ sizeof(bits_dc_chrominance)) ||
+ memcmp(cinfo->dc_huff_tbl_ptrs[1]->huffval, val_dc_chrominance,
+ sizeof(val_dc_chrominance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[1]->bits, bits_ac_chrominance,
+ sizeof(bits_ac_chrominance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[1]->huffval, val_ac_chrominance,
+ sizeof(val_ac_chrominance)))
+ return FALSE;
+
+ return TRUE;
+}
+
+
LOCAL(void)
initial_setup(j_compress_ptr cinfo, boolean transcode_only)
/* Do computations that are needed before master selection phase */
@@ -605,6 +712,8 @@ GLOBAL(void)
jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only)
{
my_master_ptr master = (my_master_ptr)cinfo->master;
+ boolean empty_huff_tables = TRUE;
+ int i;
master->pub.prepare_for_pass = prepare_for_pass;
master->pub.pass_startup = pass_startup;
@@ -646,7 +755,16 @@ jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only)
(cinfo->progressive_mode && !cinfo->arith_code))
cinfo->optimize_coding = TRUE; /* assume default tables no good for
progressive mode or lossless mode */
- if (cinfo->data_precision == 12 && !cinfo->arith_code)
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL ||
+ cinfo->ac_huff_tbl_ptrs[i] != NULL) {
+ empty_huff_tables = FALSE;
+ break;
+ }
+ }
+ if (cinfo->data_precision == 12 && !cinfo->arith_code &&
+ !cinfo->optimize_coding &&
+ (empty_huff_tables || using_std_huff_tables(cinfo)))
cinfo->optimize_coding = TRUE; /* assume default tables no good for 12-bit
data precision */
diff --git a/src/3rdparty/libjpeg/src/jconfig.h b/src/3rdparty/libjpeg/src/jconfig.h
index 1e03e166e7..e81574b9a4 100644
--- a/src/3rdparty/libjpeg/src/jconfig.h
+++ b/src/3rdparty/libjpeg/src/jconfig.h
@@ -2,9 +2,9 @@
#define JPEG_LIB_VERSION 80
-#define LIBJPEG_TURBO_VERSION 3.0.2
+#define LIBJPEG_TURBO_VERSION 3.0.3
-#define LIBJPEG_TURBO_VERSION_NUMBER 3000002
+#define LIBJPEG_TURBO_VERSION_NUMBER 3000003
#define C_ARITH_CODING_SUPPORTED 1
diff --git a/src/3rdparty/libjpeg/src/jconfigint.h b/src/3rdparty/libjpeg/src/jconfigint.h
index afcb25d247..6e7dbd75a1 100644
--- a/src/3rdparty/libjpeg/src/jconfigint.h
+++ b/src/3rdparty/libjpeg/src/jconfigint.h
@@ -10,7 +10,7 @@
#define PACKAGE_NAME "libjpeg-turbo"
-#define VERSION "3.0.2"
+#define VERSION "3.0.3"
#if SIZE_MAX == 0xffffffff
#define SIZEOF_SIZE_T 4
diff --git a/src/3rdparty/libjpeg/src/jerror.c b/src/3rdparty/libjpeg/src/jerror.c
index d0ab5b88b0..3a75fec02c 100644
--- a/src/3rdparty/libjpeg/src/jerror.c
+++ b/src/3rdparty/libjpeg/src/jerror.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2022, D. R. Commander.
+ * Copyright (C) 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -46,7 +46,7 @@
#define JMESSAGE(code, string) string,
-const char * const jpeg_std_message_table[] = {
+static const char * const jpeg_std_message_table[] = {
#include "jerror.h"
NULL
};
@@ -229,23 +229,17 @@ reset_error_mgr(j_common_ptr cinfo)
GLOBAL(struct jpeg_error_mgr *)
jpeg_std_error(struct jpeg_error_mgr *err)
{
+ memset(err, 0, sizeof(struct jpeg_error_mgr));
+
err->error_exit = error_exit;
err->emit_message = emit_message;
err->output_message = output_message;
err->format_message = format_message;
err->reset_error_mgr = reset_error_mgr;
- err->trace_level = 0; /* default = no tracing */
- err->num_warnings = 0; /* no warnings emitted yet */
- err->msg_code = 0; /* may be useful as a flag for "no error" */
-
/* Initialize message table pointers */
err->jpeg_message_table = jpeg_std_message_table;
err->last_jpeg_message = (int)JMSG_LASTMSGCODE - 1;
- err->addon_message_table = NULL;
- err->first_addon_message = 0; /* for safety */
- err->last_addon_message = 0;
-
return err;
}
diff --git a/src/3rdparty/libjpeg/src/jversion.h b/src/3rdparty/libjpeg/src/jversion.h
index 5c127dc635..3b21737362 100644
--- a/src/3rdparty/libjpeg/src/jversion.h
+++ b/src/3rdparty/libjpeg/src/jversion.h
@@ -36,20 +36,21 @@
* their code
*/
-#define JCOPYRIGHT \
+#define JCOPYRIGHT1 \
"Copyright (C) 2009-2024 D. R. Commander\n" \
"Copyright (C) 2015, 2020 Google, Inc.\n" \
"Copyright (C) 2019-2020 Arm Limited\n" \
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
"Copyright (C) 2011-2016 Siarhei Siamashka\n" \
- "Copyright (C) 2015 Intel Corporation\n" \
+ "Copyright (C) 2015 Intel Corporation\n"
+#define JCOPYRIGHT2 \
"Copyright (C) 2013-2014 Linaro Limited\n" \
"Copyright (C) 2013-2014 MIPS Technologies, Inc.\n" \
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
"Copyright (C) 1999 Ken Murchison\n" \
- "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
+ "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding\n"
#define JCOPYRIGHT_SHORT \
"Copyright (C) 1991-2024 The libjpeg-turbo Project and many others"
diff --git a/src/3rdparty/libjpeg/zlib-license.txt b/src/3rdparty/libjpeg/zlib-license.txt
deleted file mode 100644
index 480c61edca..0000000000
--- a/src/3rdparty/libjpeg/zlib-license.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any damages
-arising from the use of this software.
-
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
-3. This notice may not be removed or altered from any source distribution.
diff --git a/src/3rdparty/sqlite/qt_attribution.json b/src/3rdparty/sqlite/qt_attribution.json
index f878c0cb48..c5a5b12062 100644
--- a/src/3rdparty/sqlite/qt_attribution.json
+++ b/src/3rdparty/sqlite/qt_attribution.json
@@ -9,7 +9,7 @@
"Homepage": "https://www.sqlite.org/",
"Version": "3.45.3",
"DownloadLocation": "https://www.sqlite.org/2024/sqlite-amalgamation-3450300.zip",
- "License": "Public Domain",
- "LicenseId": "CC0-1.0",
+ "License": "SQLite Blessing",
+ "LicenseId": "blessing",
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
}
diff --git a/src/android/CMakeLists.txt b/src/android/CMakeLists.txt
index 045076c8d3..007430598e 100644
--- a/src/android/CMakeLists.txt
+++ b/src/android/CMakeLists.txt
@@ -8,5 +8,6 @@ if (ANDROID)
add_subdirectory(jar)
add_subdirectory(java)
add_subdirectory(templates)
+ add_subdirectory(templates_aar)
endif()
diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt
index 698853588c..c36bbdf75b 100644
--- a/src/android/jar/CMakeLists.txt
+++ b/src/android/jar/CMakeLists.txt
@@ -38,6 +38,8 @@ set(java_sources
src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java
src/org/qtproject/qt/android/QtEmbeddedLoader.java
src/org/qtproject/qt/android/QtView.java
+ src/org/qtproject/qt/android/QtEmbeddedViewInterface.java
+ src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
)
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java
index ea77739339..d23c87e792 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java
@@ -187,6 +187,15 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate
});
}
+ public void notifyObjectShow(int parentId)
+ {
+ QtNative.runAction(() -> {
+ // When the object is shown, we need to notify its parent about
+ // content change, not the shown object itself
+ invalidateVirtualViewId(parentId);
+ });
+ }
+
public void notifyObjectFocus(int viewId)
{
QtNative.runAction(() -> {
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
index f9f1dc3b10..1e1a36be3c 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
@@ -224,33 +224,6 @@ class QtActivityDelegate extends QtActivityDelegateBase
});
}
- void handleUiModeChange(int uiMode)
- {
- // QTBUG-108365
- if (Build.VERSION.SDK_INT >= 30) {
- // Since 29 version we are using Theme_DeviceDefault_DayNight
- Window window = m_activity.getWindow();
- WindowInsetsController controller = window.getInsetsController();
- if (controller != null) {
- // set APPEARANCE_LIGHT_STATUS_BARS if needed
- int appearanceLight = Color.luminance(window.getStatusBarColor()) > 0.5 ?
- WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS : 0;
- controller.setSystemBarsAppearance(appearanceLight,
- WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
- }
- }
- switch (uiMode) {
- case Configuration.UI_MODE_NIGHT_NO:
- ExtractStyle.runIfNeeded(m_activity, false);
- QtDisplayManager.handleUiDarkModeChanged(0);
- break;
- case Configuration.UI_MODE_NIGHT_YES:
- ExtractStyle.runIfNeeded(m_activity, true);
- QtDisplayManager.handleUiDarkModeChanged(1);
- break;
- }
- }
-
@UsedFromNativeCode
public void resetOptionsMenu()
{
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
index 8625c1f601..6fd539d8dd 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
@@ -175,6 +175,14 @@ abstract class QtActivityDelegateBase
}
@UsedFromNativeCode
+ public void notifyObjectShow(int parentId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyObjectShow(parentId);
+ }
+
+ @UsedFromNativeCode
public void notifyObjectFocus(int viewId)
{
if (m_accessibilityDelegate == null)
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java
index 1c0fd0f7d8..ff694777d5 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java
@@ -21,16 +21,14 @@ import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.HashMap;
-class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppStateDetailsListener {
+class QtEmbeddedDelegate extends QtActivityDelegateBase
+ implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface
+{
// TODO simplistic implementation with one QtView, expand to support multiple views QTBUG-117649
private QtView m_view;
- private long m_rootWindowRef = 0L;
private QtNative.ApplicationStateDetails m_stateDetails;
private boolean m_windowLoaded = false;
- private static native void createRootWindow(View rootView, int x, int y, int width, int height);
- static native void deleteWindow(long windowReference);
-
public QtEmbeddedDelegate(Activity context) {
super(context);
@@ -82,7 +80,6 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppS
QtNative.terminateQt();
QtNative.setActivity(null);
QtNative.getQtThread().exit();
- onDestroy();
}
}
});
@@ -92,11 +89,17 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppS
public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
synchronized (this) {
m_stateDetails = details;
- if (m_stateDetails.nativePluginIntegrationReady) {
+ }
+ }
+
+ @Override
+ public void onNativePluginIntegrationReadyChanged(boolean ready)
+ {
+ synchronized (this) {
+ if (ready) {
QtNative.runAction(() -> {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
- QtDisplayManager.setApplicationDisplayMetrics(m_activity,
- metrics.widthPixels,
+ QtDisplayManager.setApplicationDisplayMetrics(m_activity, metrics.widthPixels,
metrics.heightPixels);
});
@@ -131,6 +134,14 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppS
return m_view.getQtWindow();
}
+ // QtEmbeddedViewInterface implementation begin
+ @Override
+ public void startQtApplication(String appParams, String mainLib)
+ {
+ super.startNativeApplication(appParams, mainLib);
+ }
+
+ @Override
public void queueLoadWindow()
{
synchronized (this) {
@@ -139,12 +150,15 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppS
}
}
- void setView(QtView view) {
+ @Override
+ public void setView(QtView view)
+ {
m_view = view;
updateInputDelegate();
if (m_view != null)
registerGlobalFocusChangeListener(m_view);
}
+ // QtEmbeddedViewInterface implementation end
private void updateInputDelegate() {
if (m_view == null) {
@@ -154,20 +168,10 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppS
m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_view));
}
-
- public void setRootWindowRef(long ref) {
- m_rootWindowRef = ref;
- }
-
- public void onDestroy() {
- if (m_rootWindowRef != 0L)
- deleteWindow(m_rootWindowRef);
- m_rootWindowRef = 0L;
- }
-
private void createRootWindow() {
if (m_view != null && !m_windowLoaded) {
- createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(), m_view.getHeight());
+ QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(),
+ m_view.getHeight());
m_windowLoaded = true;
}
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java
index 65cfcbeef1..0c6c4b49f0 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java
@@ -41,6 +41,7 @@ class QtEmbeddedLoader extends QtLoader {
setEnvironmentVariable("QT_ANDROID_THEME_DISPLAY_DPI", String.valueOf(displayDensity));
String stylePath = ExtractStyle.setup(m_context, "minimal", displayDensity);
setEnvironmentVariable("ANDROID_STYLE_PATH", stylePath);
+ setEnvironmentVariable("QT_ANDROID_NO_EXIT_CALL", String.valueOf(true));
}
@Override
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java
new file mode 100644
index 0000000000..a83a65e32c
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java
@@ -0,0 +1,15 @@
+// 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;
+
+/**
+ * QtEmbeddedViewInterface is intended to encapsulate the needs of QtView, so that the Activity and
+ * Service implementations of these functions may be split clearly, and the interface can be stored
+ * and used conveniently in QtView.
+**/
+interface QtEmbeddedViewInterface {
+ void startQtApplication(String appParams, String mainLib);
+ void setView(QtView view);
+ void queueLoadWindow();
+};
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
index 11346ed715..cfa273e410 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
@@ -502,8 +502,8 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener {
// tablet methods
// pointer methods
- public static native void mouseDown(int winId, int x, int y);
- public static native void mouseUp(int winId, int x, int y);
+ public static native void mouseDown(int winId, int x, int y, int mouseButtonState);
+ public static native void mouseUp(int winId, int x, int y, int mouseButtonState);
public static native void mouseMove(int winId, int x, int y);
public static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta);
public static native void touchBegin(int winId);
@@ -619,11 +619,11 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener {
{
switch (event.getActionMasked()) {
case MotionEvent.ACTION_UP:
- mouseUp(id, (int) event.getX(), (int) event.getY());
+ mouseUp(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
break;
case MotionEvent.ACTION_DOWN:
- mouseDown(id, (int) event.getX(), (int) event.getY());
+ mouseDown(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
m_oldX = (int) event.getX();
m_oldY = (int) event.getY();
break;
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/QtNative.java
index 97a45ef8fa..b2a2887ad5 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java
@@ -196,7 +196,8 @@ class QtNative
}
interface AppStateDetailsListener {
- void onAppStateDetailsChanged(ApplicationStateDetails details);
+ default void onAppStateDetailsChanged(ApplicationStateDetails details) {}
+ default void onNativePluginIntegrationReadyChanged(boolean ready) {}
}
// Keep in sync with src/corelib/global/qnamespace.h
@@ -228,6 +229,7 @@ class QtNative
public static void notifyNativePluginIntegrationReady(boolean ready)
{
m_stateDetails.nativePluginIntegrationReady = ready;
+ notifyNativePluginIntegrationReadyChanged(ready);
notifyAppStateDetailsChanged(m_stateDetails);
}
@@ -258,6 +260,13 @@ class QtNative
}
}
+ static void notifyNativePluginIntegrationReadyChanged(boolean ready) {
+ synchronized (m_appStateListenersLock) {
+ for (final AppStateDetailsListener listener : m_appStateListeners)
+ listener.onNativePluginIntegrationReadyChanged(ready);
+ }
+ }
+
static void notifyAppStateDetailsChanged(ApplicationStateDetails details) {
synchronized (m_appStateListenersLock) {
for (AppStateDetailsListener listener : m_appStateListeners)
@@ -343,7 +352,7 @@ class QtNative
if (isServiceValid())
m_service.get().stopSelf();
m_stateDetails.isStarted = false;
- // Likely no use to call notifyAppStateDetailsChanged at this point since we are exiting
+ notifyAppStateDetailsChanged(m_stateDetails);
});
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
new file mode 100644
index 0000000000..29f1d1790f
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
@@ -0,0 +1,115 @@
+// 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 static org.qtproject.qt.android.QtNative.ApplicationState.ApplicationSuspended;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.view.Display;
+import android.view.View;
+import android.util.DisplayMetrics;
+
+/**
+ * QtServiceEmbeddedDelegate is used for embedding QML into Android Service contexts. Implements
+ * {@link QtEmbeddedViewInterface} so it can be used by QtView to communicate with the Qt layer.
+ */
+class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.AppStateDetailsListener
+{
+ private final Service m_service;
+ private QtView m_view;
+ private boolean m_windowLoaded = false;
+
+ QtServiceEmbeddedDelegate(Service service)
+ {
+ m_service = service;
+ QtNative.registerAppStateListener(this);
+ QtNative.setService(service);
+ }
+
+ @UsedFromNativeCode
+ QtInputDelegate getInputDelegate()
+ {
+ // TODO Implement text input (QTBUG-122552)
+ return null;
+ }
+
+ @Override
+ public void onNativePluginIntegrationReadyChanged(boolean ready)
+ {
+ synchronized (this) {
+ if (ready) {
+ QtNative.runAction(() -> {
+ if (m_view == null)
+ return;
+
+ final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
+
+ final int maxWidth = m_view.getWidth();
+ final int maxHeight = m_view.getHeight();
+ final int width = maxWidth;
+ final int height = maxHeight;
+ final int insetLeft = m_view.getLeft();
+ final int insetTop = m_view.getTop();
+
+ final DisplayManager dm = m_service.getSystemService(DisplayManager.class);
+ QtDisplayManager.setDisplayMetrics(
+ maxWidth, maxHeight, insetLeft, insetTop, width, height,
+ QtDisplayManager.getXDpi(metrics), QtDisplayManager.getYDpi(metrics),
+ metrics.scaledDensity, metrics.density,
+ QtDisplayManager.getRefreshRate(
+ dm.getDisplay(Display.DEFAULT_DISPLAY)));
+ });
+ createRootWindow();
+ }
+ }
+ }
+
+ // QtEmbeddedViewInterface implementation begin
+ @Override
+ public void startQtApplication(String appParams, String mainLib)
+ {
+ QtNative.startApplication(appParams, mainLib);
+ }
+
+ @Override
+ public void setView(QtView view)
+ {
+ m_view = view;
+ // If the embedded view is destroyed, do cleanup:
+ if (view == null)
+ cleanup();
+ }
+
+ @Override
+ public void queueLoadWindow()
+ {
+ synchronized (this) {
+ if (QtNative.getStateDetails().nativePluginIntegrationReady)
+ createRootWindow();
+ }
+ }
+ // QtEmbeddedViewInterface implementation end
+
+ private void createRootWindow()
+ {
+ if (m_view != null && !m_windowLoaded) {
+ QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(),
+ m_view.getHeight());
+ m_windowLoaded = true;
+ }
+ }
+
+ private void cleanup()
+ {
+ QtNative.setApplicationState(ApplicationSuspended);
+ QtNative.unregisterAppStateListener(QtServiceEmbeddedDelegate.this);
+
+ QtNative.terminateQt();
+ QtNative.setService(null);
+ QtNative.getQtThread().exit();
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtView.java b/src/android/jar/src/org/qtproject/qt/android/QtView.java
index 6836171187..ddf70b3b5b 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtView.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtView.java
@@ -29,14 +29,17 @@ abstract class QtView extends ViewGroup {
protected QtWindow m_window;
protected long m_windowReference;
+ protected long m_parentWindowReference;
protected QtWindowListener m_windowListener;
- protected QtEmbeddedDelegate m_delegate;
+ protected QtEmbeddedViewInterface m_viewInterface;
// Implement in subclass to handle the creation of the QWindow and its parent container.
// TODO could we take care of the parent window creation and parenting outside of the
// window creation method to simplify things if user would extend this? Preferably without
// too much JNI back and forth. Related to parent window creation, so handle with QTBUG-121511.
abstract protected void createWindow(long parentWindowRef);
+ static native void createRootWindow(View rootView, int x, int y, int width, int height);
+ static native void deleteWindow(long windowReference);
private static native void setWindowVisible(long windowReference, boolean visible);
private static native void resizeWindow(long windowReference,
int x, int y, int width, int height);
@@ -57,7 +60,7 @@ abstract class QtView extends ViewGroup {
}
QtEmbeddedLoader loader = new QtEmbeddedLoader(context);
- m_delegate = QtEmbeddedDelegateFactory.create((Activity)context);
+ m_viewInterface = QtEmbeddedDelegateFactory.create((Activity)context);
loader.setMainLibraryName(appLibName);
addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
@@ -77,22 +80,22 @@ abstract class QtView extends ViewGroup {
});
loader.loadQtLibraries();
// Start Native Qt application
- m_delegate.startNativeApplication(loader.getApplicationParameters(),
- loader.getMainLibraryPath());
+ m_viewInterface.startQtApplication(loader.getApplicationParameters(),
+ loader.getMainLibraryPath());
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- m_delegate.setView(this);
- m_delegate.queueLoadWindow();
+ m_viewInterface.setView(this);
+ m_viewInterface.queueLoadWindow();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
destroyWindow();
- m_delegate.setView(null);
+ m_viewInterface.setView(null);
}
@Override
@@ -156,7 +159,7 @@ abstract class QtView extends ViewGroup {
// viewReference - the reference to the created QQuickView
void addQtWindow(QtWindow window, long viewReference, long parentWindowRef) {
setWindowReference(viewReference);
- m_delegate.setRootWindowRef(parentWindowRef);
+ m_parentWindowReference = parentWindowRef;
final Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
@@ -176,9 +179,9 @@ abstract class QtView extends ViewGroup {
// Destroy the underlying QWindow
void destroyWindow() {
- if (m_windowReference != 0L)
- QtEmbeddedDelegate.deleteWindow(m_windowReference);
- m_windowReference = 0L;
+ if (m_parentWindowReference != 0L)
+ deleteWindow(m_parentWindowReference);
+ m_parentWindowReference = 0L;
}
QtWindow getQtWindow() {
diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle
index f94ffbde54..f8989db80d 100644
--- a/src/android/templates/build.gradle
+++ b/src/android/templates/build.gradle
@@ -14,11 +14,11 @@ repositories {
mavenCentral()
}
-apply plugin: 'com.android.application'
+apply plugin: qtGradlePluginType
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
- implementation 'androidx.core:core:1.10.1'
+ implementation 'androidx.core:core:1.13.1'
}
android {
@@ -29,12 +29,14 @@ android {
* - qtAndroidDir - holds the path to qt android files
* needed to build any Qt application
* on Android.
+ * - qtGradlePluginType - whether to build an app or a library
*
* are defined in gradle.properties file. This file is
* updated by QtCreator and androiddeployqt tools.
* Changing them manually might break the compilation!
*******************************************************/
+ namespace androidPackageName
compileSdkVersion androidCompileSdkVersion
buildToolsVersion androidBuildToolsVersion
ndkVersion androidNdkVersion
diff --git a/src/android/templates/doc/src/android-manifest-file-configuration.qdoc b/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
index db0d3c7277..79268f7576 100644
--- a/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
+++ b/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
@@ -50,6 +50,8 @@ Qt sets the following manifest configuration by default:
\li {1, 5} \l {Android: App Manifest <manifest>}{<manifest>}
\li package
\li Sets the package name. The default value is \c {org.qtproject.example.app_name}.
+ \warning This field is deprecated and moved to \c build.gradle. It will be removed
+ in an upcoming release.
\row
\li \c {android:installLocation}
\li Sets the app's installation location, whether internal or external storage.
diff --git a/src/android/templates_aar/AndroidManifest.xml b/src/android/templates_aar/AndroidManifest.xml
new file mode 100644
index 0000000000..9c9e91e650
--- /dev/null
+++ b/src/android/templates_aar/AndroidManifest.xml
@@ -0,0 +1,9 @@
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="org.qtproject.example"
+ android:versionCode="-- %%INSERT_VERSION_CODE%% --"
+ android:versionName="-- %%INSERT_VERSION_NAME%% --">
+ <!-- %%INSERT_PERMISSIONS -->
+ <!-- %%INSERT_FEATURES -->
+</manifest>
diff --git a/src/android/templates_aar/CMakeLists.txt b/src/android/templates_aar/CMakeLists.txt
new file mode 100644
index 0000000000..07c421fbab
--- /dev/null
+++ b/src/android/templates_aar/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Android aar specific template files
+
+set(templates_aar_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/AndroidManifest.xml")
+
+add_custom_target(Qt${QtBase_VERSION_MAJOR}AndroidAarTemplates
+ SOURCES
+ ${templates_aar_files}
+)
+
+qt_path_join(destination ${QT_INSTALL_DIR} ${INSTALL_DATADIR} "src/android/templates_aar")
+
+qt_copy_or_install(FILES ${templates_aar_files}
+ DESTINATION "${destination}")
+
+if(NOT QT_WILL_INSTALL)
+ qt_internal_copy_at_build_time(TARGET Qt${QtBase_VERSION_MAJOR}AndroidAarTemplates
+ FILES ${templates_aar_files}
+ DESTINATION ${destination}
+ )
+endif()
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index e1fb0d7e39..3707d5f886 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -456,7 +456,7 @@ endif()
set(core_version_tagging_files
global/qversiontagging.cpp)
qt_internal_extend_target(Core
- CONDITION TEST_ld_version_script OR APPLE OR WIN32
+ CONDITION QT_FEATURE_version_tagging
SOURCES ${core_version_tagging_files}
)
@@ -897,7 +897,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_timezone AND UNIX AND NOT AN
qt_internal_extend_target(Core
CONDITION
- QT_FEATURE_icu AND QT_FEATURE_timezone AND NOT ANDROID AND NOT APPLE
+ QT_FEATURE_icu AND QT_FEATURE_timezone AND NOT UNIX
SOURCES
time/qtimezoneprivate_icu.cpp
)
diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake
index 6218df1947..3e96130b85 100644
--- a/src/corelib/Qt6AndroidMacros.cmake
+++ b/src/corelib/Qt6AndroidMacros.cmake
@@ -217,6 +217,10 @@ function(qt6_android_generate_deployment_settings target)
${target} "_qt_android_native_package_source_dir")
# version code
+ _qt_internal_add_android_deployment_property(file_contents "android-package-name"
+ ${target} "QT_ANDROID_PACKAGE_NAME")
+
+ # version code
_qt_internal_add_android_deployment_property(file_contents "android-version-code"
${target} "QT_ANDROID_VERSION_CODE")
@@ -381,6 +385,9 @@ function(qt6_android_add_apk_target target)
if(TARGET aab)
add_dependencies(aab ${target}_make_aab)
endif()
+ if(TARGET aar)
+ add_dependencies(aar ${target}_make_aar)
+ endif()
if(TARGET apk)
add_dependencies(apk ${target}_make_apk)
_qt_internal_create_global_apk_all_target_if_needed()
@@ -418,8 +425,10 @@ function(qt6_android_add_apk_target target)
endif()
set(apk_file_name "${target}.apk")
+ set(aar_file_name "${target}.aar")
set(dep_file_name "${target}.d")
set(apk_final_file_path "${apk_final_dir}/${apk_file_name}")
+ set(aar_final_file_path "${apk_final_dir}/${aar_file_name}")
set(dep_file_path "${apk_final_dir}/${dep_file_name}")
set(target_file_copy_relative_path
"libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>")
@@ -523,10 +532,33 @@ function(qt6_android_add_apk_target target)
VERBATIM
${uses_terminal}
)
+
+ # Add custom command that creates the aar and triggers rebuild if files listed in
+ # ${dep_file_path} are changed.
+ add_custom_command(OUTPUT "${aar_final_file_path}"
+ COMMAND ${CMAKE_COMMAND}
+ -E copy "$<TARGET_FILE:${target}>"
+ "${apk_final_dir}/${target_file_copy_relative_path}"
+ COMMAND "${deployment_tool}"
+ --input "${deployment_file}"
+ --output "${apk_final_dir}"
+ --apk "${aar_final_file_path}"
+ --depfile "${dep_file_path}"
+ --builddir "${relative_to_dir}"
+ --build-aar
+ ${extra_args}
+ COMMENT "Creating AAR for ${target}"
+ DEPENDS "${target}" "${deployment_file}" ${extra_deps}
+ DEPFILE "${dep_file_path}"
+ VERBATIM
+ ${uses_terminal}
+ )
cmake_policy(POP)
# Create a ${target}_make_apk target to trigger the apk build.
add_custom_target(${target}_make_apk DEPENDS "${apk_final_file_path}")
+ # Create a ${target}_make_aar target to trigger the aar build.
+ add_custom_target(${target}_make_aar DEPENDS "${aar_final_file_path}")
else()
add_custom_target(${target}_make_apk
DEPENDS ${target}_prepare_apk_dir
@@ -540,6 +572,19 @@ function(qt6_android_add_apk_target target)
VERBATIM
${uses_terminal}
)
+
+ add_custom_target(${target}_make_aar
+ DEPENDS ${target}_prepare_apk_dir
+ COMMAND ${deployment_tool}
+ --input ${deployment_file}
+ --output ${apk_final_dir}
+ --apk ${aar_final_file_path}
+ --build-aar
+ ${extra_args}
+ COMMENT "Creating AAR for ${target}"
+ VERBATIM
+ ${uses_terminal}
+ )
endif()
# Add target triggering AAB creation. Since the _make_aab target is not added to the ALL
@@ -638,6 +683,11 @@ function(_qt_internal_create_global_android_targets)
# It will trigger building all the apk build targets that are added as part of the project.
# Allow opting out.
_qt_internal_create_global_android_targets_impl(aab)
+
+ # Create a top-level "aar" target for convenience, so that users can call 'ninja aar'.
+ # It will trigger building all the aar build targets that are added as part of the project.
+ # Allow opting out.
+ _qt_internal_create_global_android_targets_impl(aar)
endfunction()
# The function collects all known non-imported shared libraries that are created in the build tree.
diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake
index 9e71b4265a..1a449b4aa3 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -3155,13 +3155,17 @@ endfunction()
# Write deployment information for the targets of the project.
function(_qt_internal_write_target_deploy_info out_file)
set(targets "")
+ set(dynamic_target_types EXECUTABLE SHARED_LIBRARY MODULE_LIBRARY)
_qt_internal_collect_buildsystem_targets(targets
- "${CMAKE_SOURCE_DIR}" INCLUDE EXECUTABLE SHARED_LIBRARY MODULE_LIBRARY)
+ "${CMAKE_SOURCE_DIR}" INCLUDE ${dynamic_target_types} STATIC_LIBRARY)
set(content "")
foreach(target IN LISTS targets)
set(var_prefix "__QT_DEPLOY_TARGET_${target}")
string(APPEND content "set(${var_prefix}_FILE $<TARGET_FILE:${target}>)\n")
- if(WIN32 AND CMAKE_VERSION GREATER_EQUAL "3.21")
+ get_target_property(target_type ${target} TYPE)
+ string(APPEND content "set(${var_prefix}_TYPE ${target_type})\n")
+ if(WIN32 AND CMAKE_VERSION GREATER_EQUAL "3.21"
+ AND target_type IN_LIST dynamic_target_types)
string(APPEND content
"set(${var_prefix}_RUNTIME_DLLS $<TARGET_RUNTIME_DLLS:${target}>)\n")
endif()
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp
index 4bca576ed4..8bb7dad008 100644
--- a/src/corelib/compat/removed_api.cpp
+++ b/src/corelib/compat/removed_api.cpp
@@ -4,7 +4,6 @@
#define QT_CORE_BUILD_REMOVED_API
#include "qglobal.h"
-#include "qnumeric.h"
QT_USE_NAMESPACE
@@ -211,7 +210,7 @@ void QObject::setObjectName(const QString &name)
void QSettings::beginGroup(const QString &prefix)
{
- return beginGroup(qToAnyStringViewIgnoringNull(prefix));
+ beginGroup(qToAnyStringViewIgnoringNull(prefix));
}
int QSettings::beginReadArray(const QString &prefix)
@@ -929,6 +928,7 @@ QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode)
#endif // QT_CORE_REMOVED_SINCE(6, 7)
#if QT_CORE_REMOVED_SINCE(6, 8)
+#include "qbitarray.h" // inlined API
#include "qbytearray.h" // inlined API
@@ -952,6 +952,13 @@ bool QDir::operator==(const QDir &dir) const
return comparesEqual(*this, dir);
}
+#include "qeasingcurve.h"
+
+bool QEasingCurve::operator==(const QEasingCurve &other) const
+{
+ return comparesEqual(*this, other);
+}
+
#include "qfileinfo.h" // inlined API
bool QFileInfo::operator==(const QFileInfo &fileinfo) const
@@ -1005,6 +1012,31 @@ bool QJsonValue::operator!=(const QJsonValue &other) const
return !comparesEqual(*this, other);
}
+#include "qline.h" // inlined API
+
+#include "qmimetype.h"
+
+bool QMimeType::operator==(const QMimeType &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+#include "qobject.h"
+#include "qnumeric.h"
+
+int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType)
+{
+ using namespace std::chrono;
+ using ratio = std::ratio_divide<std::milli, std::nano>;
+ nanoseconds::rep r;
+ if (qMulOverflow<ratio::num>(time.count(), &r)) {
+ qWarning("QObject::startTimer(std::chrono::milliseconds): "
+ "'time' arg overflowed when converted to nanoseconds.");
+ r = nanoseconds::max().count();
+ }
+ return startTimer(nanoseconds{r}, timerType);
+}
+
#if QT_CONFIG(processenvironment)
#include "qprocess.h" // inlined API
@@ -1014,6 +1046,65 @@ bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const
}
#endif // QT_CONFIG(processenvironment)
+#if QT_CONFIG(regularexpression)
+#include "qregularexpression.h"
+
+bool QRegularExpressionMatch::hasCaptured(QStringView name) const
+{
+ return hasCaptured(QAnyStringView(name));
+}
+
+QString QRegularExpressionMatch::captured(QStringView name) const
+{
+ return captured(QAnyStringView(name));
+}
+
+QStringView QRegularExpressionMatch::capturedView(QStringView name) const
+{
+ return capturedView(QAnyStringView(name));
+}
+
+qsizetype QRegularExpressionMatch::capturedStart(QStringView name) const
+{
+ return capturedStart(QAnyStringView(name));
+}
+
+qsizetype QRegularExpressionMatch::capturedLength(QStringView name) const
+{
+ return capturedLength(QAnyStringView(name));
+}
+
+qsizetype QRegularExpressionMatch::capturedEnd(QStringView name) const
+{
+ return capturedEnd(QAnyStringView(name));
+}
+
+bool QRegularExpression::operator==(const QRegularExpression &other) const
+{
+ return comparesEqual(*this, other);
+}
+#endif // QT_CONFIG(regularexpression)
+
+#if QT_CONFIG(future)
+#include "qresultstore.h"
+
+bool QtPrivate::ResultIteratorBase::operator==(const QtPrivate::ResultIteratorBase &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+bool QtPrivate::ResultIteratorBase::operator!=(const QtPrivate::ResultIteratorBase &other) const
+{
+ return !comparesEqual(*this, other);
+}
+#endif // QT_CONFIG(future)
+
+#include "qstring.h" // inlined API
+
+#if QT_CONFIG(thread)
+# include "qthreadpool.h" // inlined API
+#endif
+
#include "qurl.h"
bool QUrl::operator<(const QUrl &url) const
@@ -1038,21 +1129,6 @@ bool QUrlQuery::operator==(const QUrlQuery &other) const
return comparesEqual(*this, other);
}
-#include "qobject.h"
-
-int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType)
-{
- using namespace std::chrono;
- using ratio = std::ratio_divide<std::milli, std::nano>;
- if (nanoseconds::rep r; qMulOverflow<ratio::num>(time.count(), &r)) {
- qWarning("QObject::startTimer(std::chrono::milliseconds time ...): "
- "'time' arg will overflow when converted to nanoseconds.");
- }
- return startTimer(nanoseconds{time}, timerType);
-}
-
-#include "qstring.h" // inlined API
-
#include "qxmlstream.h" // inlined API
// #include "qotherheader.h"
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index 80e6d93193..83983dfa2e 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -430,6 +430,34 @@ const auto backtrace = std::stacktrace::current();
CXX_STANDARD 23
)
+# <future>
+qt_config_compile_test(cxx_std_async_noncopyable
+ LABEL "std::async() NonCopyable"
+ CODE
+"// Calling std::async with lambda which takes non-copyable argument causes compilation error on
+// some platforms (VxWorks 24.03 and older with C++17-compatibility for example)
+#include <future>
+
+class NonCopyable {
+public:
+ NonCopyable(const NonCopyable&) = delete;
+ NonCopyable(NonCopyable&&) = default;
+
+ NonCopyable(int value)
+ :value (value)
+ {}
+
+ int value;
+};
+
+int main(int argc, char** argv) {
+ return std::async(
+ std::launch::deferred,
+ [](NonCopyable value) { return value.value; },
+ NonCopyable(argc - 1)).get();
+}
+")
+
#### Features
qt_feature("clock-gettime" PRIVATE
@@ -458,7 +486,7 @@ qt_feature("system-doubleconversion" PRIVATE
)
qt_feature("cxx11_future" PUBLIC
LABEL "C++11 <future>"
- CONDITION NOT VXWORKS
+ CONDITION TEST_cxx_std_async_noncopyable
)
qt_feature("cxx17_filesystem" PUBLIC
LABEL "C++17 <filesystem>"
@@ -832,7 +860,8 @@ qt_feature("timezone_locale" PRIVATE
SECTION "Utilities"
LABEL "QTimeZone"
PURPOSE "Provides support for localized time-zone display names."
- DISABLE ON # Implementation is currently incomplete, so leave turned off
+ CONDITION
+ QT_FEATURE_timezone AND ( ( UNIX AND NOT APPLE AND NOT ANDROID ) OR QT_FEATURE_icu )
)
qt_feature("datetimeparser" PRIVATE
SECTION "Utilities"
diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc
index 8fe2b0e88f..3740b29612 100644
--- a/src/corelib/doc/src/cmake/cmake-properties.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc
@@ -245,6 +245,55 @@ CMake will attempt to use the latest installed version.
*/
/*!
+\page cmake-target-property-qt-android-package-name.html
+\ingroup cmake-properties-qtcore
+\ingroup cmake-target-properties-qtcore
+
+\title QT_ANDROID_PACKAGE_NAME
+\target cmake-target-property-QT_ANDROID_PACKAGE_NAME
+
+\summary {The app's package name.}
+
+\cmakepropertysince 6.8
+\preliminarycmakeproperty
+\cmakepropertyandroidonly
+
+Specifies the app's package name. This is usually a unique dot separated
+name for the app, that will be used to identify the app on devices or in
+the Play Store. For example, "org.qtproject.example.gallery".
+
+The package name set by this property is passed to the \c build.gradle file
+as a \c namespace property, instead of \c AndroidManifest.xml, since the
+latter is deprecated since Android Gradle Plugin 7.4.
+
+The package name considers some words or characters as illegal and the build
+will clean such names if any is encountered. An underscore (\c _) either replaces
+illegal characters or is appended to illegal words.
+
+\list
+ \li Allowed characters: alphanumeric, an underscore or a dot [a-zA-Z0-9_.].
+ \li Illegal words: abstract, continue, for, new, switch, assert, default,
+ if, package, synchronized, boolean, do, goto, private, this, break,
+ double, implements, protected, throw, byte, else, import, public,
+ throws, case, enum, instanceof, return, transient, catch, extends,
+ int, short, try, char, final, interface, static, void, class, finally,
+ long, strictfp, volatile, const, float, native, super, while.
+\endlist
+
+The default package name for Qt for Android apps is \c org.qtproject.example.<target_name>.
+
+\note Setting the package name manually in \c build.gradle (via
+\c namespace property) takes precedence over \c AndroidManifest.xml
+(via \c package attribute), and the latter also takes precedence over
+this property.
+
+For more information, see Android's
+\l{Android: Configure the app module}{configure the app module}.
+
+\sa{qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}
+*/
+
+/*!
\page cmake-target-property-qt-android-version-code.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
diff --git a/src/corelib/doc/src/cmake/qt_android_generate_deployment_settings.qdoc b/src/corelib/doc/src/cmake/qt_android_generate_deployment_settings.qdoc
index 5a7bbdc33f..daa3680070 100644
--- a/src/corelib/doc/src/cmake/qt_android_generate_deployment_settings.qdoc
+++ b/src/corelib/doc/src/cmake/qt_android_generate_deployment_settings.qdoc
@@ -63,6 +63,7 @@ how to accomplish this.
\li \l{cmake-target-property-QT_ANDROID_MIN_SDK_VERSION}{QT_ANDROID_MIN_SDK_VERSION}
\li \l{cmake-target-property-QT_ANDROID_PACKAGE_SOURCE_DIR}{QT_ANDROID_PACKAGE_SOURCE_DIR}
\li \l{cmake-target-property-QT_ANDROID_TARGET_SDK_VERSION}{QT_ANDROID_TARGET_SDK_VERSION}
+\li \l{cmake-target-property-QT_ANDROID_PACKAGE_NAME}{QT_ANDROID_PACKAGE_NAME}
\li \l{cmake-target-property-QT_ANDROID_VERSION_NAME}{QT_ANDROID_VERSION_NAME}
\li \l{cmake-target-property-QT_ANDROID_VERSION_CODE}{QT_ANDROID_VERSION_CODE}
\li \l{cmake-target-property-QT_QML_IMPORT_PATH}{QT_QML_IMPORT_PATH}
diff --git a/src/corelib/doc/src/foreach-keyword.qdoc b/src/corelib/doc/src/foreach-keyword.qdoc
index b3a4482528..6aa21d5880 100644
--- a/src/corelib/doc/src/foreach-keyword.qdoc
+++ b/src/corelib/doc/src/foreach-keyword.qdoc
@@ -81,7 +81,10 @@
/*!
\macro QT_NO_FOREACH
\since 6.0
+ \relates <QtGlobal>
Defining this macro removes the availability of Qt's \c foreach
loop.
+
+ \sa QT_NO_KEYWORDS
*/
diff --git a/src/corelib/global/qcomparehelpers.h b/src/corelib/global/qcomparehelpers.h
index 0e43ac296b..97c972bfa7 100644
--- a/src/corelib/global/qcomparehelpers.h
+++ b/src/corelib/global/qcomparehelpers.h
@@ -145,8 +145,8 @@ template <typename In> constexpr auto to_Qt(In in) noexcept
noexcept(noexcept(compareThreeWay(rhs, lhs))) \
{ \
const auto r = compareThreeWay(rhs, lhs); \
- if (r > 0) return std::strong_ordering::less; \
- if (r < 0) return std::strong_ordering::greater; \
+ if (is_gt(r)) return std::strong_ordering::less; \
+ if (is_lt(r)) return std::strong_ordering::greater; \
return r; \
}
@@ -157,8 +157,8 @@ template <typename In> constexpr auto to_Qt(In in) noexcept
noexcept(noexcept(compareThreeWay(rhs, lhs))) \
{ \
const auto r = compareThreeWay(rhs, lhs); \
- if (r > 0) return std::weak_ordering::less; \
- if (r < 0) return std::weak_ordering::greater; \
+ if (is_gt(r)) return std::weak_ordering::less; \
+ if (is_lt(r)) return std::weak_ordering::greater; \
return r; \
}
@@ -169,8 +169,8 @@ template <typename In> constexpr auto to_Qt(In in) noexcept
noexcept(noexcept(compareThreeWay(rhs, lhs))) \
{ \
const auto r = compareThreeWay(rhs, lhs); \
- if (r > 0) return std::partial_ordering::less; \
- if (r < 0) return std::partial_ordering::greater; \
+ if (is_gt(r)) return std::partial_ordering::less; \
+ if (is_lt(r)) return std::partial_ordering::greater; \
return r; \
}
@@ -218,19 +218,19 @@ template <typename In> constexpr auto to_Qt(In in) noexcept
Attributes \
friend Constexpr bool operator<(LeftType const &lhs, RightType const &rhs) \
noexcept(noexcept(compareThreeWay(lhs, rhs))) \
- { return compareThreeWay(lhs, rhs) < 0; } \
+ { return is_lt(compareThreeWay(lhs, rhs)); } \
Attributes \
friend Constexpr bool operator>(LeftType const &lhs, RightType const &rhs) \
noexcept(noexcept(compareThreeWay(lhs, rhs))) \
- { return compareThreeWay(lhs, rhs) > 0; } \
+ { return is_gt(compareThreeWay(lhs, rhs)); } \
Attributes \
friend Constexpr bool operator<=(LeftType const &lhs, RightType const &rhs) \
noexcept(noexcept(compareThreeWay(lhs, rhs))) \
- { return compareThreeWay(lhs, rhs) <= 0; } \
+ { return is_lteq(compareThreeWay(lhs, rhs)); } \
Attributes \
friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) \
noexcept(noexcept(compareThreeWay(lhs, rhs))) \
- { return compareThreeWay(lhs, rhs) >= 0; }
+ { return is_gteq(compareThreeWay(lhs, rhs)); }
#define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr, \
@@ -255,19 +255,19 @@ template <typename In> constexpr auto to_Qt(In in) noexcept
Attributes \
friend Constexpr bool operator<(RightType const &lhs, LeftType const &rhs) \
noexcept(noexcept(compareThreeWay(rhs, lhs))) \
- { return compareThreeWay(rhs, lhs) > 0; } \
+ { return is_gt(compareThreeWay(rhs, lhs)); } \
Attributes \
friend Constexpr bool operator>(RightType const &lhs, LeftType const &rhs) \
noexcept(noexcept(compareThreeWay(rhs, lhs))) \
- { return compareThreeWay(rhs, lhs) < 0; } \
+ { return is_lt(compareThreeWay(rhs, lhs)); } \
Attributes \
friend Constexpr bool operator<=(RightType const &lhs, LeftType const &rhs) \
noexcept(noexcept(compareThreeWay(rhs, lhs))) \
- { return compareThreeWay(rhs, lhs) >= 0; } \
+ { return is_gteq(compareThreeWay(rhs, lhs)); } \
Attributes \
friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) \
noexcept(noexcept(compareThreeWay(rhs, lhs))) \
- { return compareThreeWay(rhs, lhs) <= 0; }
+ { return is_lteq(compareThreeWay(rhs, lhs)); }
#define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, \
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 9c46ea0efb..b2340bff8e 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -857,6 +857,8 @@
# if _MSC_VER < 1936
# define Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
# endif
+// QTBUG-124376: MSVC is slow at compiling qstrnlen()
+# define Q_COMPILER_SLOW_QSTRNLEN_COMPILATION
# endif /* __cplusplus */
#endif // defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
@@ -1404,7 +1406,11 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic
#endif
#if defined(__cplusplus) && __cplusplus >= 202002L // P0846 doesn't have a feature macro :/
+# if !defined(Q_CC_MSVC_ONLY) || Q_CC_MSVC < 1939 // claims C++20 support but lacks P0846
+ // 1939 is known to work
+ // 1936 is known to fail
# define QT_COMPILER_HAS_P0846
+# endif
#endif
#ifdef QT_COMPILER_HAS_P0846
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 222c008f8a..99e4e49c9c 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -170,6 +170,19 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
}
/*!
+ \macro QT_NO_KEYWORDS
+ \relates <QtGlobal>
+
+ Define this macro to disable the Qt-specific keywords that are usually enabled,
+ such as \c signals and \c slots. Use \c Q_SIGNALS and \c Q_SLOTS instead.
+
+ Libraries should define this macro to make sure that they don't use the generic
+ keywords without the \c Q_ prefix in their public headers.
+
+ \sa QT_NO_FOREACH
+*/
+
+/*!
\macro QT_NAMESPACE
\internal
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 1009057bad..2d70e82370 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -67,8 +67,9 @@
#include <QtCore/qtresource.h>
#include <QtCore/qttranslation.h>
#include <QtCore/qttypetraits.h>
+#if QT_CONFIG(version_tagging)
#include <QtCore/qversiontagging.h>
-
+#endif
#endif /* __cplusplus */
#endif /* QGLOBAL_H */
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 92729b06f1..1b03733d2a 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -554,6 +554,10 @@ QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMo
}
qsizetype startIndex = 0;
+ /* We support placeholders of the form $(<ENV_VAR>) in qt.conf.
+ The loop below tries to find all such placeholders, and replaces
+ them with the actual value of the ENV_VAR environment variable
+ */
while (true) {
startIndex = ret.indexOf(u'$', startIndex);
if (startIndex < 0)
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 2398c0a1a4..1569577b12 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -1356,6 +1356,11 @@ namespace Qt {
PreventContextMenu
};
+ enum class ContextMenuTrigger {
+ Press,
+ Release,
+ };
+
enum InputMethodQuery {
ImEnabled = 0x1,
ImCursorRectangle = 0x2,
@@ -1731,6 +1736,7 @@ namespace Qt {
Q_ENUM_NS(ScrollBarPolicy)
Q_ENUM_NS(FocusPolicy)
Q_ENUM_NS(ContextMenuPolicy)
+ Q_ENUM_NS(ContextMenuTrigger)
Q_ENUM_NS(ArrowType)
Q_ENUM_NS(ToolButtonStyle)
Q_ENUM_NS(PenStyle)
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index ddfade675a..b2ec64f435 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -2087,6 +2087,18 @@
*/
/*!
+ \enum Qt::ContextMenuTrigger
+ \since 6.8
+
+ This enum type defines the mouse event used to trigger a context menu event.
+
+ \value Press context menu on mouse press event, default on UNIX systems.
+ \value Release context menu on mouse release event, default on Windows.
+
+ \sa QStyleHints::contextMenuTrigger
+*/
+
+/*!
\enum Qt::FocusPolicy
This enum type defines the various policies a widget can have with
diff --git a/src/corelib/global/qtconfigmacros.h b/src/corelib/global/qtconfigmacros.h
index 018161eac4..03d52d885a 100644
--- a/src/corelib/global/qtconfigmacros.h
+++ b/src/corelib/global/qtconfigmacros.h
@@ -9,6 +9,7 @@
#endif
#include <QtCore/qtconfiginclude.h>
+#include <QtCore/qtversionchecks.h>
#include <assert.h>
diff --git a/src/corelib/global/qversiontagging.h b/src/corelib/global/qversiontagging.h
index 73faf5b6eb..fa2dd23728 100644
--- a/src/corelib/global/qversiontagging.h
+++ b/src/corelib/global/qversiontagging.h
@@ -4,11 +4,17 @@
#if !defined(QVERSIONTAGGING_H)
#define QVERSIONTAGGING_H
+#if 0
+#pragma qt_no_master_include
+#endif
+
#include <QtCore/qcompilerdetection.h>
#include <QtCore/qtconfigmacros.h>
#include <QtCore/qtversionchecks.h>
#include <QtCore/qtypes.h>
+QT_REQUIRE_CONFIG(version_tagging);
+
QT_BEGIN_NAMESPACE
/*
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index c9f218ddf5..ea5ce13b5e 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -779,10 +779,7 @@ bool QAbstractFileEngine::atEnd() const
uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
- MapExtensionOption option;
- option.offset = offset;
- option.size = size;
- option.flags = flags;
+ const MapExtensionOption option(offset, size, flags);
MapExtensionReturn r;
if (!extension(MapExtension, &option, &r))
return nullptr;
@@ -803,8 +800,7 @@ uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlag
*/
bool QAbstractFileEngine::unmap(uchar *address)
{
- UnMapExtensionOption options;
- options.address = address;
+ const UnMapExtensionOption options(address);
return extension(UnMapExtension, &options);
}
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
index 903ee1276c..b2e0b248da 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -147,19 +147,26 @@ public:
{};
class MapExtensionOption : public ExtensionOption {
+ Q_DISABLE_COPY_MOVE(MapExtensionOption)
public:
qint64 offset;
qint64 size;
QFile::MemoryMapFlags flags;
+ constexpr MapExtensionOption(qint64 off, qint64 sz, QFile::MemoryMapFlags f)
+ : offset(off), size(sz), flags(f) {}
};
class MapExtensionReturn : public ExtensionReturn {
+ Q_DISABLE_COPY_MOVE(MapExtensionReturn)
public:
- uchar *address;
+ MapExtensionReturn() = default;
+ uchar *address = nullptr;
};
class UnMapExtensionOption : public ExtensionOption {
+ Q_DISABLE_COPY_MOVE(UnMapExtensionOption)
public:
- uchar *address;
+ uchar *address = nullptr;
+ constexpr UnMapExtensionOption(uchar *p) : address(p) {}
};
virtual bool extension(Extension extension, const ExtensionOption *option = nullptr, ExtensionReturn *output = nullptr);
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index 763620692c..4e513bc7cf 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -282,8 +282,7 @@ void QBuffer::setData(const char *data, qsizetype size)
qWarning("QBuffer::setData: Buffer is open");
return;
}
- d->buf->replace(qsizetype(0), d->buf->size(), // ### QByteArray lacks assign(ptr, n)
- data, size);
+ d->buf->assign(data, data + size);
}
/*!
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 9291201d88..05947f3380 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -313,9 +313,10 @@ inline void QDirPrivate::sortFileList(QDir::SortFlags sort, const QFileInfoList
names->append(fi.fileName());
}
} else {
- QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]);
+ QVarLengthArray<QDirSortItem, 64> si;
+ si.reserve(n);
for (qsizetype i = 0; i < n; ++i)
- si[i] = QDirSortItem{l.at(i), sort};
+ si.emplace_back(l.at(i), sort);
#ifndef QT_BOOTSTRAPPED
if (sort.testAnyFlag(QDir::LocaleAware)) {
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index bda2962f8d..2f6c0ae184 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -642,7 +642,7 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
{
Q_CHECK_FILE_NAME(entry, entry);
-#if !defined(Q_OS_DARWIN) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L && !defined(Q_OS_VXWORKS)
// realpath(X,0) is not supported
Q_UNUSED(data);
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index a4d0cc0e4f..f49106edd4 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -990,6 +990,17 @@ bool QFSFileEngine::remove()
return ret;
}
+/*
+ An alternative to setFileName() when you have already constructed
+ a QFileSystemEntry.
+*/
+void QFSFileEngine::setFileEntry(QFileSystemEntry &&entry)
+{
+ Q_D(QFSFileEngine);
+ d->init();
+ d->fileEntry = std::move(entry);
+}
+
bool QFSFileEngine::rename_helper(const QString &newName, RenameMode mode)
{
Q_D(QFSFileEngine);
@@ -997,10 +1008,14 @@ bool QFSFileEngine::rename_helper(const QString &newName, RenameMode mode)
auto func = mode == Rename ? QFileSystemEngine::renameFile
: QFileSystemEngine::renameOverwriteFile;
QSystemError error;
- const bool ret = func(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret)
+ auto newEntry = QFileSystemEntry(newName);
+ const bool ret = func(d->fileEntry, newEntry, error);
+ if (!ret) {
setError(QFile::RenameError, error.toString());
- return ret;
+ return false;
+ }
+ setFileEntry(std::move(newEntry));
+ return true;
}
/*!
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index 231ad9020a..dfc40e20b6 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -83,6 +83,7 @@ public:
bool setFileTime(const QDateTime &newDate, QFile::FileTime time) override;
QDateTime fileTime(QFile::FileTime time) const override;
void setFileName(const QString &file) override;
+ void setFileEntry(QFileSystemEntry &&entry);
int handle() const override;
#ifndef QT_NO_FILESYSTEMITERATOR
@@ -160,7 +161,7 @@ public:
bool isSequentialFdFh() const;
#endif
#ifdef Q_OS_WIN
- bool nativeRenameOverwrite(const QString &newName);
+ bool nativeRenameOverwrite(const QFileSystemEntry &newEntry);
#endif
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index 20f6f8e8ff..4ac305f49b 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -396,11 +396,10 @@ bool QFSFileEnginePrivate::nativeIsSequential() const
|| (fileType == FILE_TYPE_PIPE);
}
-bool QFSFileEnginePrivate::nativeRenameOverwrite(const QString &newName)
+bool QFSFileEnginePrivate::nativeRenameOverwrite(const QFileSystemEntry &newEntry)
{
if (fileHandle == INVALID_HANDLE_VALUE)
return false;
- QFileSystemEntry newEntry(newName, QFileSystemEntry::FromInternalPath());
const QString newFilePath = newEntry.nativeFilePath();
const size_t nameByteLength = newFilePath.length() * sizeof(wchar_t);
if (nameByteLength + sizeof(wchar_t) > std::numeric_limits<DWORD>::max())
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index f5e9708365..108ee0b7c3 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -2281,6 +2281,10 @@ void QProcess::start(OpenMode mode)
void QProcess::startCommand(const QString &command, OpenMode mode)
{
QStringList args = splitCommand(command);
+ if (args.isEmpty()) {
+ qWarning("QProcess::startCommand: empty or whitespace-only command was provided");
+ return;
+ }
const QString program = args.takeFirst();
start(program, args, mode);
}
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index fcbce92ade..5c696433fd 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -37,6 +37,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
+#include <termios.h>
#include <unistd.h>
#if __has_include(<paths.h>)
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index b76d2b6478..581e1e75ef 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -36,6 +36,16 @@
#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP
# include <sys/mman.h>
+# ifdef Q_OS_LINUX
+// since 5.7, so define in case we're being compiled with older kernel headers
+# define MREMAP_DONTUNMAP 4
+# elif defined(Q_OS_DARWIN)
+# include <mach/mach.h>
+# include <mach/vm_map.h>
+# endif
+#endif
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
#endif
//#define DEBUG_RESOURCE_MATCH
@@ -65,6 +75,7 @@ RCC_FEATURE_SYMBOL(Zstd)
#undef RCC_FEATURE_SYMBOL
+namespace {
class QStringSplitter
{
public:
@@ -130,7 +141,7 @@ public:
return QResource::NoCompression;
}
const uchar *data(int node, qint64 *size) const;
- quint64 lastModified(int node) const;
+ qint64 lastModified(int node) const;
QStringList children(int node) const;
virtual QString mappingRoot() const { return QString(); }
bool mappingRootSubdir(const QString &path, QString *match = nullptr) const;
@@ -159,15 +170,18 @@ static QString cleanPath(const QString &_path)
path.remove(0, 1);
return path;
}
+} // unnamed namespace
Q_DECLARE_TYPEINFO(QResourceRoot, Q_RELOCATABLE_TYPE);
typedef QList<QResourceRoot*> ResourceList;
+namespace {
struct QResourceGlobalData
{
QRecursiveMutex resourceMutex;
ResourceList resourceList;
};
+}
Q_GLOBAL_STATIC(QResourceGlobalData, resourceGlobalData)
static inline QRecursiveMutex &resourceMutex()
@@ -279,14 +293,16 @@ public:
bool load(const QString &file);
void clear();
+ static bool mayRemapData(const QResource &resource);
+
QLocale locale;
QString fileName, absoluteFilePath;
QList<QResourceRoot *> related;
- mutable qint64 size;
- mutable quint64 lastModified;
- mutable const uchar *data;
+ qint64 size;
+ qint64 lastModified;
+ const uchar *data;
mutable QStringList children;
- mutable quint8 compressionAlgo;
+ quint8 compressionAlgo;
bool container;
/* 2 or 6 padding bytes */
@@ -928,14 +944,14 @@ const uchar *QResourceRoot::data(int node, qint64 *size) const
return nullptr;
}
-quint64 QResourceRoot::lastModified(int node) const
+qint64 QResourceRoot::lastModified(int node) const
{
if (node == -1 || version < 0x02)
return 0;
const int offset = findOffset(node) + 14;
- return qFromBigEndian<quint64>(tree + offset);
+ return qFromBigEndian<qint64>(tree + offset);
}
QStringList QResourceRoot::children(int node) const
@@ -1031,8 +1047,8 @@ Q_CORE_EXPORT bool qUnregisterResourceData(int version, const unsigned char *tre
return false;
}
+namespace {
// run time resource creation
-
class QDynamicBufferResourceRoot : public QResourceRoot
{
QString root;
@@ -1105,6 +1121,11 @@ public:
class QDynamicFileResourceRoot : public QDynamicBufferResourceRoot
{
+public:
+ static uchar *map_sys(QFile &file, qint64 base, qsizetype size);
+ static void unmap_sys(void *base, qsizetype size);
+
+private:
QString fileName;
// for mmap'ed files, this is what needs to be unmapped.
uchar *unmapPointer;
@@ -1115,22 +1136,18 @@ public:
: QDynamicBufferResourceRoot(_root), unmapPointer(nullptr), unmapLength(0)
{ }
~QDynamicFileResourceRoot() {
-#if defined(QT_USE_MMAP)
- if (unmapPointer) {
- munmap(reinterpret_cast<char *>(unmapPointer), unmapLength);
- unmapPointer = nullptr;
- unmapLength = 0;
- } else
-#endif
- {
+ if (wasMemoryMapped())
+ unmap_sys(unmapPointer, unmapLength);
+ else
delete[] mappingBuffer();
- }
}
QString mappingFile() const { return fileName; }
ResourceRootType type() const override { return Resource_File; }
+ bool wasMemoryMapped() const { return unmapPointer; }
bool registerSelf(const QString &f);
};
+} // unnamed namespace
#ifndef MAP_FILE
# define MAP_FILE 0
@@ -1139,49 +1156,69 @@ public:
# define MAP_FAILED reinterpret_cast<void *>(-1)
#endif
-bool QDynamicFileResourceRoot::registerSelf(const QString &f)
+void QDynamicFileResourceRoot::unmap_sys(void *base, qsizetype size)
+{
+#if defined(QT_USE_MMAP)
+ munmap(base, size);
+#elif defined(Q_OS_WIN)
+ Q_UNUSED(size)
+ UnmapViewOfFile(reinterpret_cast<void *>(base));
+#endif
+}
+
+// Note: caller must ensure \a offset and \a size are acceptable to the OS.
+uchar *QDynamicFileResourceRoot::map_sys(QFile &file, qint64 offset, qsizetype size)
{
- bool fromMM = false;
- uchar *data = nullptr;
- qsizetype data_len = 0;
+ Q_ASSERT(file.isOpen());
+ void *ptr = nullptr;
+ if (size < 0)
+ size = qMin(file.size() - offset, (std::numeric_limits<qsizetype>::max)());
+ // We don't use QFile::map() here because we want to dispose of the QFile object
#if defined(QT_USE_MMAP)
- int fd = QT_OPEN(QFile::encodeName(f), O_RDONLY);
- if (fd >= 0) {
- QT_STATBUF st;
- if (!QT_FSTAT(fd, &st) && st.st_size <= std::numeric_limits<qsizetype>::max()) {
- int protection = PROT_READ; // read-only memory
- int flags = MAP_FILE | MAP_PRIVATE; // swap-backed map from file
- void *ptr = QT_MMAP(nullptr, st.st_size, // any address, whole file
- protection, flags,
- fd, 0); // from offset 0 of fd
- if (ptr != MAP_FAILED) {
- data = static_cast<uchar *>(ptr);
- data_len = st.st_size;
- fromMM = true;
- }
+ int fd = file.handle();
+ int protection = PROT_READ; // read-only memory
+ int flags = MAP_FILE | MAP_PRIVATE; // swap-backed map from file
+ ptr = QT_MMAP(nullptr, size, protection, flags, fd, offset);
+ if (ptr == MAP_FAILED)
+ ptr = nullptr;
+#elif defined(Q_OS_WIN)
+ int fd = file.handle();
+ HANDLE fileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (fileHandle != INVALID_HANDLE_VALUE) {
+ HANDLE mapHandle = CreateFileMapping(fileHandle, 0, PAGE_WRITECOPY, 0, 0, 0);
+ if (mapHandle) {
+ ptr = MapViewOfFile(mapHandle, FILE_MAP_COPY, DWORD(offset >> 32), DWORD(offset), size);
+ CloseHandle(mapHandle);
}
- QT_CLOSE(fd);
}
#endif // QT_USE_MMAP
- if (!data) {
- QFile file(f);
+ return static_cast<uchar *>(ptr);
+}
+
+bool QDynamicFileResourceRoot::registerSelf(const QString &f)
+{
+ QFile file(f);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+
+ qint64 data_len = file.size();
+ if (data_len > std::numeric_limits<qsizetype>::max())
+ return false;
+
+ uchar *data = map_sys(file, 0, data_len);
+ bool fromMM = !!data;
+
+ if (!fromMM) {
bool ok = false;
- if (file.open(QIODevice::ReadOnly)) {
- qint64 fsize = file.size();
- if (fsize <= std::numeric_limits<qsizetype>::max()) {
- data_len = file.size();
- data = new uchar[data_len];
- ok = (data_len == file.read(reinterpret_cast<char *>(data), data_len));
- }
- }
+ data = new uchar[data_len];
+ ok = (data_len == file.read(reinterpret_cast<char *>(data), data_len));
if (!ok) {
delete[] data;
data = nullptr;
data_len = 0;
return false;
}
- fromMM = false;
}
if (data && QDynamicBufferResourceRoot::registerSelf(data, data_len)) {
if (fromMM) {
@@ -1349,11 +1386,22 @@ private:
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
void uncompress() const;
- qint64 offset;
+ void mapUncompressed();
+ bool mapUncompressed_sys();
+ void unmapUncompressed_sys();
+ qint64 offset = 0;
QResource resource;
mutable QByteArray uncompressed;
+ bool mustUnmap = false;
+
+ // minimum size for which we'll try to re-open ourselves in mapUncompressed()
+ static constexpr qsizetype RemapCompressedThreshold = 16384;
protected:
- QResourceFileEnginePrivate() : offset(0) { }
+ ~QResourceFileEnginePrivate()
+ {
+ if (mustUnmap)
+ unmapUncompressed_sys();
+ }
};
bool QResourceFileEngine::caseSensitive() const
@@ -1565,7 +1613,9 @@ bool QResourceFileEngine::supportsExtension(Extension extension) const
uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
Q_Q(QResourceFileEngine);
- Q_UNUSED(flags);
+ Q_ASSERT_X(resource.compressionAlgorithm() == QResource::NoCompression
+ || !uncompressed.isNull(), "QFile::map()",
+ "open() should have uncompressed compressed resources");
qint64 max = resource.uncompressedSize();
qint64 end;
@@ -1575,11 +1625,15 @@ uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::Memory
return nullptr;
}
- const uchar *address = resource.data();
- if (resource.compressionAlgorithm() != QResource::NoCompression) {
- uncompress();
- if (uncompressed.isNull())
- return nullptr;
+ const uchar *address = reinterpret_cast<const uchar *>(uncompressed.constBegin());
+ if (!uncompressed.isNull())
+ return const_cast<uchar *>(address) + offset;
+
+ // resource was not compressed
+ address = resource.data();
+ if (flags & QFile::MapPrivateOption) {
+ // We need to provide read-write memory
+ mapUncompressed();
address = reinterpret_cast<const uchar *>(uncompressed.constData());
}
@@ -1600,6 +1654,131 @@ void QResourceFileEnginePrivate::uncompress() const
uncompressed = resource.uncompressedData();
}
+void QResourceFileEnginePrivate::mapUncompressed()
+{
+ Q_ASSERT(resource.compressionAlgorithm() == QResource::NoCompression);
+ if (!uncompressed.isNull())
+ return; // nothing to do
+
+ if (resource.uncompressedSize() >= RemapCompressedThreshold) {
+ if (mapUncompressed_sys())
+ return;
+ }
+
+ uncompressed = resource.uncompressedData();
+ uncompressed.detach();
+}
+
+#if defined(MREMAP_MAYMOVE) && defined(MREMAP_DONTUNMAP)
+inline bool QResourcePrivate::mayRemapData(const QResource &resource)
+{
+ auto d = resource.d_func();
+
+ // assumptions from load():
+ // - d->related is not empty
+ // - the first item in d->related is the one with our data
+ // by current construction, it's also the only item
+ const QResourceRoot *root = d->related.at(0);
+
+ switch (root->type()) {
+ case QResourceRoot::Resource_Builtin:
+ return true; // always acceptable, memory is read-only
+ case QResourceRoot::Resource_Buffer:
+ return false; // never acceptable, memory is heap
+ case QResourceRoot::Resource_File:
+ break;
+ }
+
+ auto df = static_cast<const QDynamicFileResourceRoot *>(root);
+ return df->wasMemoryMapped();
+}
+#endif
+
+// Returns the page boundaries of where \a location is located in memory.
+static auto mappingBoundaries(const void *location, qsizetype size)
+{
+#ifdef Q_OS_WIN
+ auto getpagesize = [] {
+ SYSTEM_INFO sysinfo;
+ ::GetSystemInfo(&sysinfo);
+ return sysinfo.dwAllocationGranularity;
+ };
+#endif
+ struct R {
+ void *begin;
+ qsizetype size;
+ qptrdiff offset;
+ } r;
+
+ const quintptr pageMask = getpagesize() - 1;
+ quintptr data = quintptr(location);
+ quintptr begin = data & ~pageMask;
+ quintptr end = (data + size + pageMask) & ~pageMask;
+ r.begin = reinterpret_cast<void *>(begin);
+ r.size = end - begin;
+ r.offset = data & pageMask;
+ return r;
+}
+
+bool QResourceFileEnginePrivate::mapUncompressed_sys()
+{
+ auto r = mappingBoundaries(resource.data(), resource.uncompressedSize());
+ void *ptr = nullptr;
+
+#if defined(MREMAP_MAYMOVE) && defined(MREMAP_DONTUNMAP)
+ // Use MREMAP_MAYMOVE to tell the kernel to give us a new address and use
+ // MREMAP_DONTUNMAP (supported since kernel 5.7) to request that it create
+ // a new mapping of the same pages, instead of moving. We can only do that
+ // for pages that are read-only, otherwise the kernel replaces the source
+ // with pages full of nulls.
+ if (!QResourcePrivate::mayRemapData(resource))
+ return false;
+
+ ptr = mremap(r.begin, r.size, r.size, MREMAP_MAYMOVE | MREMAP_DONTUNMAP);
+ if (ptr == MAP_FAILED)
+ return false;
+
+ // Allow writing, which the documentation says we allow. This is safe
+ // because MREMAP_DONTUNMAP only works for private mappings.
+ if (mprotect(ptr, r.size, PROT_READ | PROT_WRITE) != 0) {
+ munmap(ptr, r.size);
+ return false;
+ }
+#elif defined(Q_OS_DARWIN)
+ mach_port_t self = mach_task_self();
+ vm_address_t addr = 0;
+ vm_address_t mask = 0;
+ bool anywhere = true;
+ bool copy = true;
+ vm_prot_t cur_prot = VM_PROT_READ | VM_PROT_WRITE;
+ vm_prot_t max_prot = VM_PROT_ALL;
+ kern_return_t res = vm_remap(self, &addr, r.size, mask, anywhere,
+ self, vm_address_t(r.begin), copy, &cur_prot,
+ &max_prot, VM_INHERIT_DEFAULT);
+ if (res != KERN_SUCCESS)
+ return false;
+
+ ptr = reinterpret_cast<void *>(addr);
+ if ((max_prot & VM_PROT_WRITE) == 0 || mprotect(ptr, r.size, PROT_READ | PROT_WRITE) != 0) {
+ munmap(ptr, r.size);
+ return false;
+ }
+#endif
+
+ if (!ptr)
+ return false;
+ const char *newdata = static_cast<char *>(ptr) + r.offset;
+ uncompressed = QByteArray::fromRawData(newdata, resource.uncompressedSize());
+ mustUnmap = true;
+ return true;
+}
+
+void QResourceFileEnginePrivate::unmapUncompressed_sys()
+{
+ auto r = mappingBoundaries(uncompressed.constBegin(), uncompressed.size());
+ QDynamicFileResourceRoot::unmap_sys(r.begin, r.size);
+}
+
#endif // !defined(QT_BOOTSTRAPPED)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index 6d8918c29c..cc59bb3725 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -113,10 +113,10 @@ QSaveFile::QSaveFile(const QString &name, QObject *parent)
QSaveFile::~QSaveFile()
{
Q_D(QSaveFile);
- QFileDevice::close();
- if (d->fileEngine) {
+ if (isOpen()) {
+ QFileDevice::close();
+ Q_ASSERT(d->fileEngine);
d->fileEngine->remove();
- d->fileEngine.reset();
}
}
@@ -298,7 +298,7 @@ bool QSaveFile::commit()
}
QFileDevice::close(); // calls flush()
- const auto fe = std::move(d->fileEngine);
+ const auto &fe = d->fileEngine;
// Sync to disk if possible. Ignore errors (e.g. not supported).
fe->syncToDisk();
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index d76bc3b328..4e48a18d91 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -393,8 +393,13 @@ bool QTemporaryFileEngine::renameOverwrite(const QString &newName)
}
#ifdef Q_OS_WIN
if (flags & Win32NonShared) {
- bool ok = d_func()->nativeRenameOverwrite(newName);
+ QFileSystemEntry newEntry(newName, QFileSystemEntry::FromInternalPath());
+ bool ok = d_func()->nativeRenameOverwrite(newEntry);
QFSFileEngine::close();
+ if (ok) {
+ // Match what QFSFileEngine::renameOverwrite() does
+ setFileEntry(std::move(newEntry));
+ }
return ok;
}
#endif
@@ -868,7 +873,6 @@ bool QTemporaryFile::rename(const QString &newName)
if (tef->rename(newName)) {
unsetError();
// engine was able to handle the new name so we just reset it
- tef->setFileName(newName);
d->fileName = newName;
return true;
}
diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h
index 8815069daa..d160afe41e 100644
--- a/src/corelib/io/qtemporaryfile_p.h
+++ b/src/corelib/io/qtemporaryfile_p.h
@@ -88,8 +88,7 @@ public:
if (filePathIsTemplate) {
d->fileEntry.clear();
} else {
- d->fileEntry = QFileSystemEntry(file);
- QFSFileEngine::setFileName(file);
+ QFSFileEngine::setFileEntry(QFileSystemEntry(file));
}
}
~QTemporaryFileEngine();
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 4360b5b076..1e285bb36b 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -1014,8 +1014,9 @@ inline bool QUrlPrivate::setScheme(const QString &value, qsizetype len, bool doS
inline void QUrlPrivate::setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
{
sectionIsPresent &= ~Authority;
- sectionIsPresent |= Host;
port = -1;
+ if (from == end && !auth.isNull())
+ sectionIsPresent |= Host; // empty but not null authority implies host
// we never actually _loop_
while (from != end) {
@@ -1155,8 +1156,11 @@ inline void QUrlPrivate::setQuery(const QString &value, qsizetype from, qsizetyp
inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions options) const
{
- if (host.isEmpty())
+ if (host.isEmpty()) {
+ if ((sectionIsPresent & Host) && appendTo.isNull())
+ appendTo.detach();
return;
+ }
if (host.at(0).unicode() == '[') {
// IPv6 addresses might contain a zone-id which needs to be recoded
if (options != 0)
@@ -1274,7 +1278,9 @@ QUrlPrivate::setHost(const QString &value, qsizetype from, qsizetype iend, QUrl:
const qsizetype len = end - begin;
host.clear();
- sectionIsPresent |= Host;
+ sectionIsPresent &= ~Host;
+ if (!value.isNull() || (sectionIsPresent & Authority))
+ sectionIsPresent |= Host;
if (len == 0)
return true;
@@ -2029,11 +2035,6 @@ void QUrl::setAuthority(const QString &authority, ParsingMode mode)
}
d->setAuthority(authority, 0, authority.size(), mode);
- if (authority.isNull()) {
- // QUrlPrivate::setAuthority cleared almost everything
- // but it leaves the Host bit set
- d->sectionIsPresent &= ~QUrlPrivate::Authority;
- }
}
/*!
@@ -2297,8 +2298,7 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
}
if (d->setHost(data, 0, data.size(), mode)) {
- if (host.isNull())
- d->sectionIsPresent &= ~QUrlPrivate::Host;
+ return;
} else if (!data.startsWith(u'[')) {
// setHost failed, it might be IPv6 or IPvFuture in need of bracketing
Q_ASSERT(d->error);
@@ -2311,6 +2311,7 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
// source data contains ':', so it's an IPv6 error
d->error->code = QUrlPrivate::InvalidIPv6AddressError;
}
+ d->sectionIsPresent &= ~QUrlPrivate::Host;
} else {
// succeeded
d->clearError();
diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
index a9ead2e1eb..a5284dbad4 100644
--- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp
+++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
@@ -688,8 +688,10 @@ void QSortFilterProxyModelPrivate::sort_source_rows(
QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q);
std::stable_sort(source_rows.begin(), source_rows.end(), gt);
}
- } else { // restore the source model order
- std::stable_sort(source_rows.begin(), source_rows.end());
+ } else if (sort_order == Qt::AscendingOrder) {
+ std::stable_sort(source_rows.begin(), source_rows.end(), std::less{});
+ } else {
+ std::stable_sort(source_rows.begin(), source_rows.end(), std::greater{});
}
}
@@ -2490,7 +2492,10 @@ QSize QSortFilterProxyModel::span(const QModelIndex &index) const
}
/*!
- \reimp
+ \reimp
+ Sorts the model by \a column in the given \a order.
+ If the sort \a column is less than zero, the model will be sorted by source model row
+ in the given \a order.
*/
void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
{
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index 54c4373aed..00b0d078d7 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -541,7 +541,7 @@ QMacRootLevelAutoReleasePool::QMacRootLevelAutoReleasePool()
if (qEnvironmentVariableIsSet(ROOT_LEVEL_POOL_DISABLE_SWITCH))
return;
- pool.reset(new QMacAutoReleasePool);
+ pool.emplace();
[[[ROOT_LEVEL_POOL_MARKER alloc] init] autorelease];
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index e63c320805..5ecf8072f4 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -19,6 +19,8 @@
#include <QtCore/qoperatingsystemversion.h>
+#include <optional>
+
#ifdef Q_OS_MACOS
#include <mach/port.h>
struct mach_header;
@@ -48,7 +50,6 @@ kern_return_t IOObjectRelease(io_object_t object);
#endif
#include "qstring.h"
-#include "qscopedpointer.h"
#include "qpair.h"
#if defined( __OBJC__) && defined(QT_NAMESPACE)
@@ -129,7 +130,7 @@ public:
Q_NODISCARD_CTOR QMacRootLevelAutoReleasePool();
~QMacRootLevelAutoReleasePool();
private:
- QScopedPointer<QMacAutoReleasePool> pool;
+ std::optional<QMacAutoReleasePool> pool = std::nullopt;
};
#endif
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 939965cff7..a494369c5d 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -525,6 +525,7 @@ void QCoreApplicationPrivate::eventDispatcherReady()
}
Q_CONSTINIT QBasicAtomicPointer<QThread> QCoreApplicationPrivate::theMainThread = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
+Q_CONSTINIT QBasicAtomicPointer<void> QCoreApplicationPrivate::theMainThreadId = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
QThread *QCoreApplicationPrivate::mainThread()
{
Q_ASSERT(theMainThread.loadRelaxed() != nullptr);
@@ -1090,6 +1091,14 @@ bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute)
\brief Whether the use of the QEventLoopLocker feature can cause the
application to quit.
+ When this property is \c true the release of the last remaining
+ QEventLoopLocker operating on the application will attempt to
+ quit the application.
+
+ Note that attempting a quit may not necessarily result in the
+ application quitting, for example if there still are open windows,
+ or the QEvent::Quit event is ignored.
+
The default is \c true.
\sa QEventLoopLocker
@@ -2093,7 +2102,13 @@ bool QCoreApplicationPrivate::canQuitAutomatically()
if (!in_exec)
return false;
- if (quitLockEnabled && quitLockRef.loadRelaxed())
+ // The automatic quit functionality is triggered by
+ // both QEventLoopLocker and maybeLastWindowClosed.
+ // In either case, we don't want to quit if there
+ // are active QEventLoopLockers, even if quitLockEnabled
+ // is not enabled, as the property signals whether to
+ // trigger the automatic quit, not whether to block it.
+ if (quitLockRef.loadRelaxed())
return false;
return true;
@@ -3236,7 +3251,7 @@ void QCoreApplication::installNativeEventFilter(QAbstractNativeEventFilter *filt
*/
void QCoreApplication::removeNativeEventFilter(QAbstractNativeEventFilter *filterObject)
{
- QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
+ QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(QCoreApplicationPrivate::theMainThread.loadAcquire());
if (!filterObject || !eventDispatcher)
return;
eventDispatcher->removeNativeEventFilter(filterObject);
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 1c1577c9ff..bfd65d2c9a 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -108,6 +108,7 @@ public:
virtual void quit();
static QBasicAtomicPointer<QThread> theMainThread;
+ static QBasicAtomicPointer<void> theMainThreadId;
static QThread *mainThread();
static bool threadRequiresCoreApplication();
diff --git a/src/corelib/kernel/qcoreapplication_platform.h b/src/corelib/kernel/qcoreapplication_platform.h
index e430f3495b..d5f266179e 100644
--- a/src/corelib/kernel/qcoreapplication_platform.h
+++ b/src/corelib/kernel/qcoreapplication_platform.h
@@ -43,7 +43,7 @@ struct Q_CORE_EXPORT QAndroidApplication
{
QT_DECLARE_NATIVE_INTERFACE(QAndroidApplication, 1, QCoreApplication)
#ifdef Q_QDOC
- static jobject context();
+ static QJniObject context();
#else
static QtJniTypes::Context context();
#endif
diff --git a/src/corelib/kernel/qelapsedtimer.cpp b/src/corelib/kernel/qelapsedtimer.cpp
index 511b81a04e..c4308a0b8f 100644
--- a/src/corelib/kernel/qelapsedtimer.cpp
+++ b/src/corelib/kernel/qelapsedtimer.cpp
@@ -14,6 +14,8 @@ QT_BEGIN_NAMESPACE
\reentrant
\ingroup tools
+ \compares strong
+
The QElapsedTimer class is usually used to quickly calculate how much
time has elapsed between two events. Its API is similar to that of QTime,
so code that was using that can be ported quickly to the new class.
@@ -155,8 +157,7 @@ QT_BEGIN_NAMESPACE
Returns \c true if \a lhs and \a rhs contain different times, false otherwise.
*/
/*!
- \fn bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
- \relates QElapsedTimer
+ \fn bool QElapsedTimer::operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
Returns \c true if \a lhs was started before \a rhs, false otherwise.
diff --git a/src/corelib/kernel/qelapsedtimer.h b/src/corelib/kernel/qelapsedtimer.h
index 7d8b889f61..e71573456d 100644
--- a/src/corelib/kernel/qelapsedtimer.h
+++ b/src/corelib/kernel/qelapsedtimer.h
@@ -4,6 +4,7 @@
#ifndef QELAPSEDTIMER_H
#define QELAPSEDTIMER_H
+#include <QtCore/qcompare.h>
#include <QtCore/qglobal.h>
#include <chrono>
@@ -45,15 +46,41 @@ public:
Duration durationTo(const QElapsedTimer &other) const noexcept;
qint64 msecsTo(const QElapsedTimer &other) const noexcept;
qint64 secsTo(const QElapsedTimer &other) const noexcept;
-
- friend bool operator==(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
- { return lhs.t1 == rhs.t1 && lhs.t2 == rhs.t2; }
- friend bool operator!=(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
- { return !(lhs == rhs); }
-
friend bool Q_CORE_EXPORT operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept;
private:
+ friend bool comparesEqual(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
+ {
+ return lhs.t1 == rhs.t1 && lhs.t2 == rhs.t2;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QElapsedTimer)
+
+ friend Qt::strong_ordering compareThreeWay(const QElapsedTimer &lhs,
+ const QElapsedTimer &rhs) noexcept
+ {
+ return Qt::compareThreeWay(lhs.t1, rhs.t1);
+ }
+
+#if defined(__cpp_lib_three_way_comparison)
+ friend std::strong_ordering
+ operator<=>(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
+ {
+ return compareThreeWay(lhs, rhs);
+ }
+#else
+ friend bool operator>(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
+ {
+ return is_gt(compareThreeWay(lhs, rhs));
+ }
+ friend bool operator<=(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
+ {
+ return is_lteq(compareThreeWay(lhs, rhs));
+ }
+ friend bool operator>=(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
+ {
+ return is_gteq(compareThreeWay(lhs, rhs));
+ }
+#endif // defined(__cpp_lib_three_way_comparison)
qint64 t1 = Q_INT64_C(0x8000000000000000);
qint64 t2 = Q_INT64_C(0x8000000000000000);
};
diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp
index f4fcdbb8b2..4aa435b64b 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm.cpp
+++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp
@@ -938,10 +938,11 @@ void QEventDispatcherWasm::callOnLoadedIfRequired()
void QEventDispatcherWasm::onLoaded()
{
- emscripten::val qt = emscripten::val::module_property("qt");
- if (qt.isUndefined())
- return;
- qt.call<void>("onLoaded");
+ // TODO: call qtloader.js onLoaded from here, in order to delay
+ // hiding the "Loading..." message until the app is ready to paint
+ // the first frame. Currently onLoaded must be called early before
+ // main() in order to ensure that the screen/container elements
+ // have valid geometry at startup.
}
namespace {
diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
index d318069ca0..e314a17ff8 100644
--- a/src/corelib/kernel/qeventloop.cpp
+++ b/src/corelib/kernel/qeventloop.cpp
@@ -346,7 +346,11 @@ static_assert(alignof(QCoreApplication) >= 4);
/*!
Creates an event locker operating on the QCoreApplication.
- The application will quit when there are no more QEventLoopLockers operating on it.
+ The application will attempt to quit when there are no more QEventLoopLockers
+ operating on it, as long as QCoreApplication::isQuitLockEnabled() is \c true.
+
+ Note that attempting a quit may not necessarily result in the application quitting,
+ if there for example are open windows, or the QEvent::Quit event is ignored.
\sa QCoreApplication::quit(), QCoreApplication::isQuitLockEnabled()
*/
diff --git a/src/corelib/kernel/qjniarray.h b/src/corelib/kernel/qjniarray.h
index 976b4e92e3..2ea82e39db 100644
--- a/src/corelib/kernel/qjniarray.h
+++ b/src/corelib/kernel/qjniarray.h
@@ -18,7 +18,7 @@ QT_BEGIN_NAMESPACE
template <typename T> class QJniArray;
template <typename T>
-struct QJniArrayIterator
+struct QT_TECH_PREVIEW_API QJniArrayIterator
{
QJniArrayIterator() = default;
@@ -86,7 +86,7 @@ private:
{}
};
-class QJniArrayBase
+class QT_TECH_PREVIEW_API QJniArrayBase
{
// for SFINAE'ing out the fromContainer named constructor
template <typename Container, typename = void> struct CanConvertHelper : std::false_type {};
@@ -193,7 +193,7 @@ private:
};
template <typename T>
-class QJniArray : public QJniArrayBase
+class QT_TECH_PREVIEW_API QJniArray : public QJniArrayBase
{
friend struct QJniArrayIterator<T>;
public:
diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h
index dda8dc0950..09f7ec7948 100644
--- a/src/corelib/kernel/qjnienvironment.h
+++ b/src/corelib/kernel/qjnienvironment.h
@@ -69,6 +69,7 @@ public:
, std::enable_if_t<QtJniTypes::isObjectType<Class>(), bool> = true
#endif
>
+ QT_TECH_PREVIEW_API
bool registerNativeMethods(std::initializer_list<JNINativeMethod> methods)
{
return registerNativeMethods(QtJniTypes::Traits<Class>::className().data(), methods);
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index 8244a4390f..892f02e7a4 100644
--- a/src/corelib/kernel/qjniobject.cpp
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -105,9 +105,9 @@ using namespace Qt::StringLiterals;
// C++ code
QJniObject string1 = QJniObject::fromString("String1");
QJniObject string2 = QJniObject::fromString("String2");
- QJniObject stringArray = QJniObject::callStaticObjectMethod<jstringArray>(
+ QJniObject stringArray = QJniObject::callStaticObjectMethod<jobjectArray>(
"org/qtproject/qt/TestClass",
- "stringArray"
+ "stringArray",
string1.object<jstring>(),
string2.object<jstring>());
\endcode
diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h
index 589f6489f7..707d1ae28a 100644
--- a/src/corelib/kernel/qjniobject.h
+++ b/src/corelib/kernel/qjniobject.h
@@ -670,7 +670,7 @@ inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2)
}
namespace QtJniTypes {
-struct JObjectBase
+struct QT_TECH_PREVIEW_API JObjectBase
{
operator QJniObject() const { return m_object; }
@@ -695,7 +695,7 @@ protected:
};
template<typename Type>
-class JObject : public JObjectBase
+class QT_TECH_PREVIEW_API JObject : public JObjectBase
{
public:
using Class = Type;
diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h
index 1eaae6312b..e071a3f784 100644
--- a/src/corelib/kernel/qjnitypes.h
+++ b/src/corelib/kernel/qjnitypes.h
@@ -11,6 +11,7 @@
QT_BEGIN_NAMESPACE
+// QT_TECH_PREVIEW_API
#define Q_DECLARE_JNI_TYPE_HELPER(Type) \
namespace QtJniTypes { \
struct Type : JObject<Type> \
@@ -19,7 +20,7 @@ struct Type : JObject<Type> \
}; \
} \
-
+// QT_TECH_PREVIEW_API
#define Q_DECLARE_JNI_TYPE(Type, Signature) \
Q_DECLARE_JNI_TYPE_HELPER(Type) \
template<> \
@@ -35,6 +36,7 @@ struct QtJniTypes::Traits<QtJniTypes::Type> { \
} \
}; \
+// QT_TECH_PREVIEW_API
#define Q_DECLARE_JNI_CLASS(Type, Signature) \
Q_DECLARE_JNI_TYPE_HELPER(Type) \
template<> \
@@ -176,7 +178,7 @@ va_##Method(JNIEnv *env, jclass thiz, ...)
}, argTuple); \
} \
-
+// QT_TECH_PREVIEW_API
#define Q_DECLARE_JNI_NATIVE_METHOD(...) \
QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD, __VA_ARGS__) \
@@ -194,8 +196,10 @@ static const JNINativeMethod Method##_method = { \
#define QT_DECLARE_JNI_NATIVE_METHOD_1(Method) \
QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Method) \
+// QT_TECH_PREVIEW_API
#define Q_JNI_NATIVE_METHOD(Method) QtJniMethods::Method##_method
+// QT_TECH_PREVIEW_API
#define Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(...) \
QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE, __VA_ARGS__) \
@@ -209,6 +213,7 @@ static const JNINativeMethod Method##_method = { \
#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_1(Method) \
QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Method) \
+// QT_TECH_PREVIEW_API
#define Q_JNI_NATIVE_SCOPED_METHOD(Method, Scope) Scope::Method##_method
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qmetacontainer.cpp b/src/corelib/kernel/qmetacontainer.cpp
index 200724c9f4..5f68f8fe74 100644
--- a/src/corelib/kernel/qmetacontainer.cpp
+++ b/src/corelib/kernel/qmetacontainer.cpp
@@ -14,6 +14,8 @@ QT_BEGIN_NAMESPACE
\ingroup objectmodel
+ \compares equality
+
The class provides a number of primitive container operations, using void*
as operands. This way, you can manipulate a generic container retrieved from
a Variant without knowing its type.
@@ -790,21 +792,19 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con
}
/*!
- \fn bool operator==(QMetaSequence a, QMetaSequence b)
+ \fn bool QMetaSequence::operator==(const QMetaSequence &lhs, const QMetaSequence &rhs)
\since 6.0
- \relates QMetaSequence
- Returns \c true if the QMetaSequence \a a represents the same container type
- as the QMetaSequence \a b, otherwise returns \c false.
+ Returns \c true if the QMetaSequence \a lhs represents the same container type
+ as the QMetaSequence \a rhs, otherwise returns \c false.
*/
/*!
- \fn bool operator!=(QMetaSequence a, QMetaSequence b)
+ \fn bool QMetaSequence::operator!=(const QMetaSequence &lhs, const QMetaSequence &rhs)
\since 6.0
- \relates QMetaSequence
- Returns \c true if the QMetaSequence \a a represents a different container
- type than the QMetaSequence \a b, otherwise returns \c false.
+ Returns \c true if the QMetaSequence \a lhs represents a different container
+ type than the QMetaSequence \a rhs, otherwise returns \c false.
*/
diff --git a/src/corelib/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h
index 67c0ddcf36..1bed7f9f7b 100644
--- a/src/corelib/kernel/qmetacontainer.h
+++ b/src/corelib/kernel/qmetacontainer.h
@@ -5,6 +5,7 @@
#define QMETACONTAINER_H
#include <QtCore/qcontainerinfo.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qflags.h>
#include <QtCore/qglobal.h>
@@ -975,18 +976,15 @@ public:
bool canGetValueAtConstIterator() const;
void valueAtConstIterator(const void *iterator, void *result) const;
- friend bool operator==(const QMetaSequence &a, const QMetaSequence &b)
- {
- return a.d() == b.d();
- }
- friend bool operator!=(const QMetaSequence &a, const QMetaSequence &b)
- {
- return a.d() != b.d();
- }
-
const QtMetaContainerPrivate::QMetaSequenceInterface *iface() const { return d(); }
private:
+ friend bool comparesEqual(const QMetaSequence &lhs, const QMetaSequence &rhs) noexcept
+ {
+ return lhs.d() == rhs.d();
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QMetaSequence)
+
template<typename T>
struct MetaSequence
{
@@ -1171,18 +1169,15 @@ public:
return nullptr;
}
- friend bool operator==(const QMetaAssociation &a, const QMetaAssociation &b)
- {
- return a.d() == b.d();
- }
- friend bool operator!=(const QMetaAssociation &a, const QMetaAssociation &b)
- {
- return a.d() != b.d();
- }
-
const QtMetaContainerPrivate::QMetaAssociationInterface *iface() const { return d(); }
private:
+ friend bool comparesEqual(const QMetaAssociation &lhs, const QMetaAssociation &rhs) noexcept
+ {
+ return lhs.d() == rhs.d();
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QMetaAssociation)
+
template<typename T>
struct MetaAssociation
{
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 8d304bd890..05662b385a 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -1798,6 +1798,7 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
function.
\ingroup objectmodel
+ \compares equality
A QMetaMethod has a methodType(), a methodSignature(), a list of
parameterTypes() and parameterNames(), a return typeName(), a
@@ -1825,19 +1826,19 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
invoked), otherwise returns \c false.
*/
-/*! \fn bool QMetaMethod::operator==(const QMetaMethod &m1, const QMetaMethod &m2)
+/*! \fn bool QMetaMethod::operator==(const QMetaMethod &lhs, const QMetaMethod &rhs)
\since 5.0
\overload
- Returns \c true if method \a m1 is equal to method \a m2,
+ Returns \c true if method \a lhs is equal to method \a rhs,
otherwise returns \c false.
*/
-/*! \fn bool QMetaMethod::operator!=(const QMetaMethod &m1, const QMetaMethod &m2)
+/*! \fn bool QMetaMethod::operator!=(const QMetaMethod &lhs, const QMetaMethod &rhs)
\since 5.0
\overload
- Returns \c true if method \a m1 is not equal to method \a m2,
+ Returns \c true if method \a lhs is not equal to method \a rhs,
otherwise returns \c false.
*/
@@ -3655,8 +3656,8 @@ QMetaProperty::QMetaProperty(const QMetaObject *mobj, int index)
data(getMetaPropertyData(mobj, index))
{
Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->propertyCount);
-
- if (!(data.flags() & EnumOrFlag))
+ // The code below here just resolves menum if the property is an enum type:
+ if (!(data.flags() & EnumOrFlag) || !metaType().flags().testFlag(QMetaType::IsEnumeration))
return;
QByteArrayView enum_name = typeNameFromTypeInfo(mobj, data.type());
menum = mobj->enumerator(QMetaObjectPrivate::indexOfEnumerator(mobj, enum_name));
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 4e52e854d9..91f287a8d3 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -6,6 +6,7 @@
#define QMETAOBJECT_H
#include <QtCore/qobjectdefs.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
@@ -251,10 +252,11 @@ protected:
friend struct QMetaObject;
friend struct QMetaObjectPrivate;
friend class QObject;
- friend bool operator==(const QMetaMethod &m1, const QMetaMethod &m2) noexcept
- { return m1.data == m2.data; }
- friend bool operator!=(const QMetaMethod &m1, const QMetaMethod &m2) noexcept
- { return !(m1 == m2); }
+
+private:
+ friend bool comparesEqual(const QMetaMethod &lhs, const QMetaMethod &rhs) noexcept
+ { return lhs.data == rhs.data; }
+ Q_DECLARE_EQUALITY_COMPARABLE(QMetaMethod)
};
Q_DECLARE_TYPEINFO(QMetaMethod, Q_RELOCATABLE_TYPE);
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index d2c36fceb4..d5dc9a356a 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -111,22 +111,18 @@ public:
const_cast<QArgumentType *>(this)->_name = QMetaType(_type).name();
return _name;
}
- bool operator==(const QArgumentType &other) const
- {
- if (_type && other._type)
- return _type == other._type;
- else
- return name() == other.name();
- }
- bool operator!=(const QArgumentType &other) const
+
+private:
+ friend bool comparesEqual(const QArgumentType &lhs,
+ const QArgumentType &rhs) noexcept
{
- if (_type && other._type)
- return _type != other._type;
+ if (lhs._type && rhs._type)
+ return lhs._type == rhs._type;
else
- return name() != other.name();
+ return lhs.name() == rhs.name();
}
+ Q_DECLARE_EQUALITY_COMPARABLE(QArgumentType)
-private:
int _type;
QByteArray _name;
};
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index f845eb3239..1c2665e53c 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -5,7 +5,6 @@
#include "qmetatype.h"
#include "qmetatype_p.h"
-#include "qobject.h"
#include "qobjectdefs.h"
#include "qdatetime.h"
#include "qbytearray.h"
@@ -43,6 +42,7 @@
# include "qmetaobject.h"
# include "qsequentialiterable.h"
# include "qassociativeiterable.h"
+# include "qobject.h"
#endif
#if QT_CONFIG(itemmodel)
@@ -56,7 +56,6 @@
# include "qline.h"
#endif
-#include <bitset>
#include <new>
#include <cstring>
@@ -151,13 +150,7 @@ struct QMetaTypeCustomRegistry
auto &ti = registry[idx];
// We must unregister all names.
- auto it = aliases.begin();
- while (it != aliases.end()) {
- if (it.value() == ti)
- it = aliases.erase(it);
- else
- ++it;
- }
+ aliases.removeIf([ti] (const auto &kv) { return kv.value() == ti; });
ti = nullptr;
@@ -481,6 +474,7 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte
\ingroup objectmodel
\threadsafe
+ \compares equality
The class is used as a helper to marshall types in QVariant and
in queued signals and slots connections. It associates a type
@@ -932,20 +926,20 @@ void QMetaType::unregisterMetaType(QMetaType type)
Returns the QMetaType corresponding to the type in the template parameter.
*/
-/*! \fn bool QMetaType::operator==(QMetaType a, QMetaType b)
+/*! \fn bool QMetaType::operator==(const QMetaType &lhs, const QMetaType &rhs)
\since 5.15
\overload
- Returns \c true if the QMetaType \a a represents the same type
- as the QMetaType \a b, otherwise returns \c false.
+ Returns \c true if the QMetaType \a lhs represents the same type
+ as the QMetaType \a rhs, otherwise returns \c false.
*/
-/*! \fn bool QMetaType::operator!=(QMetaType a, QMetaType b)
+/*! \fn bool QMetaType::operator!=(const QMetaType &lhs, const QMetaType &rhs)
\since 5.15
\overload
- Returns \c true if the QMetaType \a a represents a different type
- than the QMetaType \a b, otherwise returns \c false.
+ Returns \c true if the QMetaType \a lhs represents a different type
+ than the QMetaType \a rhs, otherwise returns \c false.
*/
/*! \internal */
@@ -2666,6 +2660,36 @@ bool QMetaType::hasRegisteredConverterFunction(QMetaType fromType, QMetaType toT
}
/*!
+ \internal
+ Non-template helper ("SCARY") for IsMetaTypePair::registerConverter().
+*/
+bool QtPrivate::hasRegisteredConverterFunctionToPairVariantInterface(QMetaType m)
+{
+ const QMetaType to = QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
+ return QMetaType::hasRegisteredConverterFunction(m, to);
+}
+
+/*!
+ \internal
+ Non-template helper ("SCARY") for SequentialValueTypeIsMetaType::registerConverter().
+*/
+bool QtPrivate::hasRegisteredConverterFunctionToIterableMetaSequence(QMetaType m)
+{
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
+ return QMetaType::hasRegisteredConverterFunction(m, to);
+}
+
+/*!
+ \internal
+ Non-template helper ("SCARY") for AssociativeKeyTypeIsMetaType::registerConverter().
+*/
+bool QtPrivate::hasRegisteredConverterFunctionToIterableMetaAssociation(QMetaType m)
+{
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
+ return QMetaType::hasRegisteredConverterFunction(m, to);
+}
+
+/*!
\fn template<typename From, typename To> bool QMetaType::hasRegisteredMutableViewFunction()
Returns \c true, if the meta type system has a registered mutable view on type From of type To.
\since 6.0
@@ -2683,6 +2707,26 @@ bool QMetaType::hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType t
}
/*!
+ \internal
+ Non-template helper ("SCARY") for SequentialValueTypeIsMetaType::registerMutableView().
+*/
+bool QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaSequence(QMetaType m)
+{
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
+ return QMetaType::hasRegisteredMutableViewFunction(m, to);
+}
+
+/*!
+ \internal
+ Non-template helper ("SCARY") for AssociativeKeyTypeIsMetaType::registerMutableView().
+*/
+bool QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaAssociation(QMetaType m)
+{
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
+ return QMetaType::hasRegisteredMutableViewFunction(m, to);
+}
+
+/*!
\fn const char *QMetaType::typeName(int typeId)
\deprecated
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index e3ef1474da..12a67aef58 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -518,20 +518,20 @@ public:
template<typename T>
constexpr static QMetaType fromType();
static QMetaType fromName(QByteArrayView name);
-
- friend bool operator==(QMetaType a, QMetaType b)
+private:
+ friend bool comparesEqual(const QMetaType &lhs,
+ const QMetaType &rhs) noexcept
{
- if (a.d_ptr == b.d_ptr)
+ if (lhs.d_ptr == rhs.d_ptr)
return true;
- if (!a.d_ptr || !b.d_ptr)
+ if (!lhs.d_ptr || !rhs.d_ptr)
return false; // one type is undefined, the other is defined
// avoid id call if we already have the id
- const int aId = a.id();
- const int bId = b.id();
+ const int aId = lhs.id();
+ const int bId = rhs.id();
return aId == bId;
}
- friend bool operator!=(QMetaType a, QMetaType b) { return !(a == b); }
-
+ Q_DECLARE_EQUALITY_COMPARABLE(QMetaType)
#ifndef QT_NO_DEBUG_STREAM
private:
friend Q_CORE_EXPORT QDebug operator<<(QDebug d, QMetaType m);
@@ -1750,11 +1750,19 @@ QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
QT_BEGIN_NAMESPACE
+namespace QtPrivate {
+// out-of-line helpers to reduce template code bloat ("SCARY") and improve compile times:
+Q_CORE_EXPORT bool hasRegisteredConverterFunctionToPairVariantInterface(QMetaType m);
+Q_CORE_EXPORT bool hasRegisteredConverterFunctionToIterableMetaSequence(QMetaType m);
+Q_CORE_EXPORT bool hasRegisteredMutableViewFunctionToIterableMetaSequence(QMetaType m);
+Q_CORE_EXPORT bool hasRegisteredConverterFunctionToIterableMetaAssociation(QMetaType m);
+Q_CORE_EXPORT bool hasRegisteredMutableViewFunctionToIterableMetaAssociation(QMetaType m);
+}
+
template <typename T>
inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter()
{
- const QMetaType to = QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
- if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
+ if (!QtPrivate::hasRegisteredConverterFunctionToPairVariantInterface(QMetaType::fromType<T>())) {
QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o;
return QMetaType::registerConverter<T, QtMetaTypePrivate::QPairVariantInterfaceImpl>(o);
}
@@ -1786,8 +1794,7 @@ struct SequentialValueTypeIsMetaType<T, true>
{
static bool registerConverter()
{
- const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
- if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
+ if (!QtPrivate::hasRegisteredConverterFunctionToIterableMetaSequence(QMetaType::fromType<T>())) {
QSequentialIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QIterable<QMetaSequence>>(o);
}
@@ -1796,8 +1803,7 @@ struct SequentialValueTypeIsMetaType<T, true>
static bool registerMutableView()
{
- const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
- if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
+ if (!QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaSequence(QMetaType::fromType<T>())) {
QSequentialIterableMutableViewFunctor<T> o;
return QMetaType::registerMutableView<T, QIterable<QMetaSequence>>(o);
}
@@ -1830,8 +1836,7 @@ struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T
{
static bool registerConverter()
{
- const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
- if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
+ if (!QtPrivate::hasRegisteredConverterFunctionToIterableMetaAssociation(QMetaType::fromType<T>())) {
QAssociativeIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QIterable<QMetaAssociation>>(o);
}
@@ -1840,8 +1845,7 @@ struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T
static bool registerMutableView()
{
- const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
- if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
+ if (!QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaAssociation(QMetaType::fromType<T>())) {
QAssociativeIterableMutableViewFunctor<T> o;
return QMetaType::registerMutableView<T, QIterable<QMetaAssociation>>(o);
}
diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp
index 1348c70b1a..2c0a89dbd7 100644
--- a/src/corelib/kernel/qmimedata.cpp
+++ b/src/corelib/kernel/qmimedata.cpp
@@ -90,6 +90,11 @@ static QList<QVariant> dataToUrls(QByteArrayView text)
if (from >= text.size())
break;
}
+ if (from != text.size()) {
+ const auto bav = QByteArrayView(begin + from, text.end()).trimmed();
+ if (!bav.isEmpty())
+ list.push_back(QUrl::fromEncoded(bav));
+ }
return list;
}
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 708b10a75e..e1129c5d25 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -1816,6 +1816,8 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData
int QObject::startTimer(int interval, Qt::TimerType timerType)
{
+ // no overflow can happen here:
+ // 2^31 ms * 1,000,000 always fits a 64-bit signed integer type
return startTimer(std::chrono::milliseconds{interval}, timerType);
}
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index 8ae6664a2b..376482a6af 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -19,12 +19,13 @@
#include <qproperty.h>
#include <qmetaobject.h>
-#include <qscopedpointer.h>
#include <qscopedvaluerollback.h>
#include <qvariant.h>
#include <vector>
#include <QtCore/QVarLengthArray>
+#include <memory>
+
QT_BEGIN_NAMESPACE
namespace QtPrivate {
@@ -292,7 +293,7 @@ private:
ObserverArray inlineDependencyObservers; // for things we are observing
QPropertyObserverPointer firstObserver; // list of observers observing us
- QScopedPointer<std::vector<QPropertyObserver>> heapObservers; // for things we are observing
+ std::unique_ptr<std::vector<QPropertyObserver>> heapObservers; // for things we are observing
protected:
QUntypedPropertyData *propertyDataPtr = nullptr;
diff --git a/src/corelib/kernel/qpropertyprivate.h b/src/corelib/kernel/qpropertyprivate.h
index 86dc08a6bc..a8456721d0 100644
--- a/src/corelib/kernel/qpropertyprivate.h
+++ b/src/corelib/kernel/qpropertyprivate.h
@@ -95,28 +95,20 @@ public:
void swap(QPropertyBindingPrivatePtr &other) noexcept
{ qt_ptr_swap(d, other.d); }
- friend bool operator==(const QPropertyBindingPrivatePtr &p1, const QPropertyBindingPrivatePtr &p2) noexcept
- { return p1.d == p2.d; }
- friend bool operator!=(const QPropertyBindingPrivatePtr &p1, const QPropertyBindingPrivatePtr &p2) noexcept
- { return p1.d != p2.d; }
- friend bool operator==(const QPropertyBindingPrivatePtr &p1, const T *ptr) noexcept
- { return p1.d == ptr; }
- friend bool operator!=(const QPropertyBindingPrivatePtr &p1, const T *ptr) noexcept
- { return p1.d != ptr; }
- friend bool operator==(const T *ptr, const QPropertyBindingPrivatePtr &p2) noexcept
- { return ptr == p2.d; }
- friend bool operator!=(const T *ptr, const QPropertyBindingPrivatePtr &p2) noexcept
- { return ptr != p2.d; }
- friend bool operator==(const QPropertyBindingPrivatePtr &p1, std::nullptr_t) noexcept
- { return !p1; }
- friend bool operator!=(const QPropertyBindingPrivatePtr &p1, std::nullptr_t) noexcept
- { return p1; }
- friend bool operator==(std::nullptr_t, const QPropertyBindingPrivatePtr &p2) noexcept
- { return !p2; }
- friend bool operator!=(std::nullptr_t, const QPropertyBindingPrivatePtr &p2) noexcept
- { return p2; }
-
private:
+ friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
+ const QPropertyBindingPrivatePtr &rhs) noexcept
+ { return lhs.d == rhs.d; }
+ Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr)
+ friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
+ const T *rhs) noexcept
+ { return lhs.d == rhs; }
+ Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr, T*)
+ friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
+ std::nullptr_t) noexcept
+ { return !lhs; }
+ Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr, std::nullptr_t)
+
QtPrivate::RefCounted *d;
};
diff --git a/src/corelib/kernel/qsingleshottimer_p.h b/src/corelib/kernel/qsingleshottimer_p.h
index d7e33c5221..dd1402f63a 100644
--- a/src/corelib/kernel/qsingleshottimer_p.h
+++ b/src/corelib/kernel/qsingleshottimer_p.h
@@ -19,6 +19,7 @@
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
#include "qmetaobject_p.h"
+#include "private/qnumeric_p.h"
#include <chrono>
@@ -43,6 +44,20 @@ public:
inline void startTimerForReceiver(Duration interval, Qt::TimerType timerType,
const QObject *receiver);
+ static Duration fromMsecs(std::chrono::milliseconds ms)
+ {
+ using namespace std::chrono;
+ using ratio = std::ratio_divide<std::milli, Duration::period>;
+ static_assert(ratio::den == 1);
+
+ Duration::rep r;
+ if (qMulOverflow<ratio::num>(ms.count(), &r)) {
+ qWarning("QTimer::singleShot(std::chrono::milliseconds, ...): "
+ "interval argument overflowed when converted to nanoseconds.");
+ return Duration::max();
+ }
+ return Duration{r};
+ }
Q_SIGNALS:
void timeout();
diff --git a/src/corelib/kernel/qsocketnotifier.h b/src/corelib/kernel/qsocketnotifier.h
index 8288a6b2b5..ac9e577ebc 100644
--- a/src/corelib/kernel/qsocketnotifier.h
+++ b/src/corelib/kernel/qsocketnotifier.h
@@ -83,20 +83,20 @@ public:
Q_DECL_CONSTEXPR_NOT_WIN bool isValid() const noexcept { return *this != QSocketDescriptor(); }
- friend Q_DECL_CONSTEXPR_NOT_WIN bool operator==(QSocketDescriptor lhs,
- QSocketDescriptor rhs) noexcept
+private:
+ friend Q_DECL_CONSTEXPR_NOT_WIN bool comparesEqual(const QSocketDescriptor &lhs,
+ const QSocketDescriptor &rhs) noexcept
{
return lhs.sockfd == rhs.sockfd;
}
- friend Q_DECL_CONSTEXPR_NOT_WIN bool operator!=(QSocketDescriptor lhs,
- QSocketDescriptor rhs) noexcept
- {
- return lhs.sockfd != rhs.sockfd;
- }
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+ Q_DECLARE_EQUALITY_COMPARABLE(QSocketDescriptor)
+#else
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QSocketDescriptor)
+#endif
#undef Q_DECL_CONSTEXPR_NOT_WIN
-private:
DescriptorType sockfd;
};
diff --git a/src/corelib/kernel/qsystemerror_p.h b/src/corelib/kernel/qsystemerror_p.h
index 66c434cb13..72ced63dc5 100644
--- a/src/corelib/kernel/qsystemerror_p.h
+++ b/src/corelib/kernel/qsystemerror_p.h
@@ -40,12 +40,19 @@ public:
constexpr ErrorScope scope() const { return errorScope; }
constexpr int error() const { return errorCode; }
+ constexpr bool ok() const noexcept { return errorScope == NoError; }
+ static constexpr QSystemError stdError(int error)
+ { return QSystemError(error, StandardLibraryError); }
+
static Q_CORE_EXPORT QString string(ErrorScope errorScope, int errorCode);
static Q_CORE_EXPORT QString stdString(int errorCode = -1);
#ifdef Q_OS_WIN
static Q_CORE_EXPORT QString windowsString(int errorCode = -1);
using HRESULT = long;
static Q_CORE_EXPORT QString windowsComString(HRESULT hr);
+
+ static constexpr QSystemError nativeError(int error)
+ { return QSystemError(error, NativeError); }
#endif
// data members
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index cc46c1433b..294369c1b3 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -213,7 +213,7 @@ void QTimer::start()
if (d->isActive()) // stop running timer
stop();
- const auto newId = Qt::TimerId{QObject::startTimer(d->inter * 1ms, d->type)};
+ Qt::TimerId newId{ QObject::startTimer(d->inter * 1ms, d->type) }; // overflow impossible
if (newId > Qt::TimerId::Invalid) {
d->id = newId;
d->isActiveData.notify();
@@ -332,7 +332,7 @@ void QTimer::singleShotImpl(std::chrono::milliseconds msec, Qt::TimerType timerT
return;
}
- new QSingleShotTimer(msec, timerType, receiver, slotObj);
+ new QSingleShotTimer(QSingleShotTimer::fromMsecs(msec), timerType, receiver, slotObj);
}
/*!
@@ -396,7 +396,7 @@ void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType,
Qt::QueuedConnection);
return;
}
- (void) new QSingleShotTimer(msec, timerType, receiver, member);
+ (void) new QSingleShotTimer(QSingleShotTimer::fromMsecs(msec), timerType, receiver, member);
}
}
@@ -592,7 +592,7 @@ void QTimer::setInterval(std::chrono::milliseconds interval)
d->inter.setValueBypassingBindings(msec);
if (d->isActive()) { // create new timer
QObject::killTimer(d->id); // restart timer
- const auto newId = Qt::TimerId{QObject::startTimer(msec * 1ms, d->type)};
+ Qt::TimerId newId{ QObject::startTimer(msec * 1ms, d->type) }; // overflow impossible
if (newId > Qt::TimerId::Invalid) {
// Restarted successfully. No need to update the active state.
d->id = newId;
diff --git a/src/corelib/mimetypes/mime/packages/freedesktop.org.xml b/src/corelib/mimetypes/mime/packages/freedesktop.org.xml
index b7aa6a1995..e77349a12e 100644
--- a/src/corelib/mimetypes/mime/packages/freedesktop.org.xml
+++ b/src/corelib/mimetypes/mime/packages/freedesktop.org.xml
@@ -10699,39 +10699,39 @@ command to generate the output files.
<glob pattern="*.udeb"/>
</mime-type>
<mime-type type="application/x-designer">
- <comment>Qt Designer interface document</comment>
- <comment xml:lang="zh_TW">Qt Designer 介面文件</comment>
- <comment xml:lang="zh_CN">Qt Designer 界面文档</comment>
- <comment xml:lang="uk">документ інтерфейсу Qt Designer</comment>
- <comment xml:lang="tr">Qt Designer arayüz belgesi</comment>
- <comment xml:lang="sv">Qt Designer-gränssnittsdokument</comment>
- <comment xml:lang="sq">dokument ndërfaqesh Qt Designer</comment>
- <comment xml:lang="sl">Dokument vmesnika Qt Designer</comment>
- <comment xml:lang="si">Qt Designer අතුරුමුහුණත් ලේඛනය</comment>
- <comment xml:lang="ru">Документ интерфейса Qt Designer</comment>
- <comment xml:lang="pt_BR">Documento de interface do Qt Designer</comment>
- <comment xml:lang="pt">documento de interface Qt Designer</comment>
- <comment xml:lang="pl">Dokument interfejsu Qt Designer</comment>
- <comment xml:lang="nl">Qt Designer-interfacedocument</comment>
+ <comment>Qt Widgets Designer interface document</comment>
+ <comment xml:lang="zh_TW">Qt Widgets Designer 介面文件</comment>
+ <comment xml:lang="zh_CN">Qt Widgets Designer 界面文档</comment>
+ <comment xml:lang="uk">документ інтерфейсу Qt Widgets Designer</comment>
+ <comment xml:lang="tr">Qt Widgets Designer arayüz belgesi</comment>
+ <comment xml:lang="sv">Qt Widgets Designer-gränssnittsdokument</comment>
+ <comment xml:lang="sq">dokument ndërfaqesh Qt Widgets Designer</comment>
+ <comment xml:lang="sl">Dokument vmesnika Qt Widgets Designer</comment>
+ <comment xml:lang="si">Qt Widgets Designer අතුරුමුහුණත් ලේඛනය</comment>
+ <comment xml:lang="ru">Документ интерфейса Qt Widgets Designer</comment>
+ <comment xml:lang="pt_BR">Documento de interface do Qt Widgets Designer</comment>
+ <comment xml:lang="pt">documento de interface Qt Widgets Designer</comment>
+ <comment xml:lang="pl">Dokument interfejsu Qt Widgets Designer</comment>
+ <comment xml:lang="nl">Qt Widgets Designer-interfacedocument</comment>
<comment xml:lang="ko">Qt 디자이너 인터페이스 문서</comment>
- <comment xml:lang="kk">Qt Designer интерфейс құжаты</comment>
- <comment xml:lang="ja">Qt Designer インターフェイスドキュメント</comment>
- <comment xml:lang="it">Documento interfaccia Qt Designer</comment>
- <comment xml:lang="is">Qt Designer viðmótsskjal</comment>
- <comment xml:lang="id">Dokumen antarmuka Qt Designer</comment>
- <comment xml:lang="hu">Qt Designer felületleíró dokumentum</comment>
- <comment xml:lang="hr">Qt Designer dokument sučelja</comment>
- <comment xml:lang="he">מסמך מנשק של Qt Designer</comment>
- <comment xml:lang="fr">document d'interface Qt Designer</comment>
- <comment xml:lang="fi">Qt Designer -käyttöliittymän asiakirja</comment>
- <comment xml:lang="eu">Qt Designer interfaze dokumentua</comment>
- <comment xml:lang="es">documento de interfaz de Qt Designer</comment>
- <comment xml:lang="en_GB">Qt Designer interface document</comment>
+ <comment xml:lang="kk">Qt Widgets Designer интерфейс құжаты</comment>
+ <comment xml:lang="ja">Qt Widgets Designer インターフェイスドキュメント</comment>
+ <comment xml:lang="it">Documento interfaccia Qt Widgets Designer</comment>
+ <comment xml:lang="is">Qt Widgets Designer viðmótsskjal</comment>
+ <comment xml:lang="id">Dokumen antarmuka Qt Widgets Designer</comment>
+ <comment xml:lang="hu">Qt Widgets Designer felületleíró dokumentum</comment>
+ <comment xml:lang="hr">Qt Widgets Designer dokument sučelja</comment>
+ <comment xml:lang="he">מסמך מנשק של Qt Widgets Designer</comment>
+ <comment xml:lang="fr">document d'interface Qt Widgets Designer</comment>
+ <comment xml:lang="fi">Qt Widgets Designer -käyttöliittymän asiakirja</comment>
+ <comment xml:lang="eu">Qt Widgets Designer interfaze dokumentua</comment>
+ <comment xml:lang="es">documento de interfaz de Qt Widgets Designer</comment>
+ <comment xml:lang="en_GB">Qt Widgets Designer interface document</comment>
<comment xml:lang="de">Qt-Designer-Oberflächendokument</comment>
- <comment xml:lang="da">Qt Designer-brugerflade-dokument</comment>
- <comment xml:lang="ca">document d'interfície Qt Designer</comment>
- <comment xml:lang="bg">Документ — интерфейс, Qt Designer</comment>
- <comment xml:lang="be">дакумент інтэрфейсу Qt Designer</comment>
+ <comment xml:lang="da">Qt Widgets Designer-brugerflade-dokument</comment>
+ <comment xml:lang="ca">document d'interfície Qt Widgets Designer</comment>
+ <comment xml:lang="bg">Документ — интерфейс, Qt Widgets Designer</comment>
+ <comment xml:lang="be">дакумент інтэрфейсу Qt Widgets Designer</comment>
<comment xml:lang="ar">مستند واجهة مصمم كيوت</comment>
<generic-icon name="x-office-document"/>
<sub-class-of type="application/xml"/>
diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp
index ad3c484f30..e26c8b898d 100644
--- a/src/corelib/mimetypes/qmimetype.cpp
+++ b/src/corelib/mimetypes/qmimetype.cpp
@@ -24,6 +24,7 @@ using namespace Qt::StringLiterals;
\brief The QMimeType class describes types of file or data, represented by a MIME type string.
\since 5.0
+ \compares equality
For instance a file named "readme.txt" has the MIME type "text/plain".
The MIME type can be determined from the file name, or from the file
@@ -111,14 +112,15 @@ QMimeType::~QMimeType()
}
/*!
- \fn bool QMimeType::operator==(const QMimeType &other) const;
- Returns \c true if \a other equals this QMimeType object, otherwise returns \c false.
+ \fn bool QMimeType::operator==(const QMimeType &lhs, const QMimeType &rhs);
+ Returns \c true if \a lhs equals to the \a rhs QMimeType object, otherwise
+ returns \c false.
The name is the unique identifier for a mimetype, so two mimetypes with
the same name, are equal.
*/
-bool QMimeType::operator==(const QMimeType &other) const
+bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept
{
- return d == other.d || d->name == other.d->name;
+ return lhs.d == rhs.d || lhs.d->name == rhs.d->name;
}
/*!
@@ -134,8 +136,9 @@ size_t qHash(const QMimeType &key, size_t seed) noexcept
}
/*!
- \fn bool QMimeType::operator!=(const QMimeType &other) const;
- Returns \c true if \a other does not equal this QMimeType object, otherwise returns \c false.
+ \fn bool QMimeType::operator!=(const QMimeType &lhs, const QMimeType &rhs);
+ Returns \c true if QMimeType \a lhs is not equal to QMimeType \a rhs,
+ otherwise returns \c false.
*/
/*!
diff --git a/src/corelib/mimetypes/qmimetype.h b/src/corelib/mimetypes/qmimetype.h
index 3421638f5b..508a5cfb53 100644
--- a/src/corelib/mimetypes/qmimetype.h
+++ b/src/corelib/mimetypes/qmimetype.h
@@ -49,14 +49,14 @@ public:
}
explicit QMimeType(const QMimeTypePrivate &dd);
~QMimeType();
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QMimeType &other) const;
inline bool operator!=(const QMimeType &other) const
{
return !operator==(other);
}
-
+#endif
bool isValid() const;
bool isDefault() const;
@@ -86,6 +86,10 @@ protected:
friend Q_CORE_EXPORT size_t qHash(const QMimeType &key, size_t seed) noexcept;
QExplicitlySharedDataPointer<QMimeTypePrivate> d;
+
+private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QMimeType)
};
Q_DECLARE_SHARED(QMimeType)
diff --git a/src/corelib/platform/android/qandroidnativeinterface.cpp b/src/corelib/platform/android/qandroidnativeinterface.cpp
index e9a5957895..fc3a09c78b 100644
--- a/src/corelib/platform/android/qandroidnativeinterface.cpp
+++ b/src/corelib/platform/android/qandroidnativeinterface.cpp
@@ -46,9 +46,9 @@ Q_CONSTINIT static QBasicMutex g_pendingRunnablesMutex;
QT_DEFINE_NATIVE_INTERFACE(QAndroidApplication);
/*!
- \fn jobject QNativeInterface::QAndroidApplication::context()
+ \fn QJniObject QNativeInterface::QAndroidApplication::context()
- Returns the Android context as a \c jobject. The context is an \c Activity
+ Returns the Android context as a \c QJniObject. The context is an \c Activity
if the main activity object is valid. Otherwise, the context is a \c Service.
\since 6.2
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
index cbfc6b17a5..33eb912a6d 100644
--- a/src/corelib/serialization/qcborvalue_p.h
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -195,7 +195,7 @@ public:
}
void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
{
- replaceAt_internal(*elements.insert(elements.begin() + int(idx), {}), value, disp);
+ replaceAt_internal(*elements.insert(idx, {}), value, disp);
}
void append(QtCbor::Undefined)
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index 57713d3645..329be4a294 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -70,17 +70,30 @@ constexpr quint32 QDataStream::ExtendedSize;
need of manually defining streaming operators. Enum classes are
serialized using the declared size.
- To take one example, a \c{char *} string is written as a 32-bit
- integer equal to the length of the string including the '\\0' byte,
- followed by all the characters of the string including the
- '\\0' byte. When reading a \c{char *} string, 4 bytes are read to
- create the 32-bit length value, then that many characters for the
- \c {char *} string including the '\\0' terminator are read.
-
The initial I/O device is usually set in the constructor, but can be
changed with setDevice(). If you've reached the end of the data
(or if there is no I/O device set) atEnd() will return true.
+ \section1 Serializing containers and strings
+
+ The serialization format is a length specifier first, then \a l bytes of data.
+ The length specifier is one quint32 if the version is less than 6.7 or if the
+ number of elements is less than 0xfffffffe (2^32 -2). Otherwise there is
+ an extend value 0xfffffffe followed by one quint64 with the actual value.
+ In addition for containers that support isNull(), it is encoded as a single
+ quint32 with all bits set and no data.
+
+ To take one example, if the string size fits into 32 bits, a \c{char *} string
+ is written as a 32-bit integer equal to the length of the string, including
+ the '\\0' byte, followed by all the characters of the string, including the
+ '\\0' byte. If the string size is greater, the value 0xffffffffe is written
+ as a marker of an extended size, followed by 64 bits of the actual size.
+ When reading a \c {char *} string, 4 bytes are read first. If the value is
+ not equal to 0xffffffffe (the marker of extended size), then these 4 bytes
+ are treated as the 32 bit size of the string. Otherwise, the next 8 bytes are
+ read and treated as a 64 bit size of the string. Then, all the characters for
+ the \c {char *} string, including the '\\0' terminator, are read.
+
\section1 Versioning
QDataStream's binary format has evolved since Qt 1.0, and is
@@ -1075,26 +1088,22 @@ QDataStream &QDataStream::readBytes(char *&s, qint64 &l)
qsizetype step = (dev->bytesAvailable() >= len) ? len : 1024 * 1024;
qsizetype allocated = 0;
- char *prevBuf = nullptr;
- char *curBuf = nullptr;
+ std::unique_ptr<char[]> curBuf = nullptr;
+ constexpr qsizetype StepIncreaseThreshold = std::numeric_limits<qsizetype>::max() / 2;
do {
qsizetype blockSize = qMin(step, len - allocated);
- prevBuf = curBuf;
- curBuf = new char[allocated + blockSize + 1];
- if (prevBuf) {
- memcpy(curBuf, prevBuf, allocated);
- delete [] prevBuf;
- }
- if (readBlock(curBuf + allocated, blockSize) != blockSize) {
- delete [] curBuf;
+ const qsizetype n = allocated + blockSize + 1;
+ if (const auto prevBuf = std::exchange(curBuf, std::make_unique<char[]>(n)))
+ memcpy(curBuf.get(), prevBuf.get(), allocated);
+ if (readBlock(curBuf.get() + allocated, blockSize) != blockSize)
return *this;
- }
allocated += blockSize;
- step *= 2;
+ if (step <= StepIncreaseThreshold)
+ step *= 2;
} while (allocated < len);
- s = curBuf;
+ s = curBuf.release();
s[len] = '\0';
l = len;
return *this;
diff --git a/src/corelib/serialization/qxmlstream.h b/src/corelib/serialization/qxmlstream.h
index 7eeaa1c1cc..8a12c6d611 100644
--- a/src/corelib/serialization/qxmlstream.h
+++ b/src/corelib/serialization/qxmlstream.h
@@ -206,7 +206,9 @@ typedef QList<QXmlStreamEntityDeclaration> QXmlStreamEntityDeclarations;
class Q_CORE_EXPORT QXmlStreamEntityResolver
{
+ Q_DISABLE_COPY_MOVE(QXmlStreamEntityResolver)
public:
+ QXmlStreamEntityResolver() = default;
virtual ~QXmlStreamEntityResolver();
virtual QString resolveEntity(const QString& publicId, const QString& systemId);
virtual QString resolveUndeclaredEntity(const QString &name);
diff --git a/src/corelib/text/UNICODE_LICENSE.txt b/src/corelib/text/UNICODE_LICENSE.txt
deleted file mode 100644
index 8bf2769587..0000000000
--- a/src/corelib/text/UNICODE_LICENSE.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
-
-See Terms of Use for definitions of Unicode Inc.'s
-Data Files and Software.
-
-NOTICE TO USER: Carefully read the following legal agreement.
-BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
-DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
-YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
-TERMS AND CONDITIONS OF THIS AGREEMENT.
-IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
-THE DATA FILES OR SOFTWARE.
-
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright © 1991-2022 Unicode, Inc. All rights reserved.
-Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Unicode data files and any associated documentation
-(the "Data Files") or Unicode software and any associated documentation
-(the "Software") to deal in the Data Files or Software
-without restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, and/or sell copies of
-the Data Files or Software, and to permit persons to whom the Data Files
-or Software are furnished to do so, provided that either
-(a) this copyright and permission notice appear with all copies
-of the Data Files or Software, or
-(b) this copyright and permission notice appear in associated
-Documentation.
-
-THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
-ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
-NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
-DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
-DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THE DATA FILES OR SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder
-shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in these Data Files or Software without prior
-written authorization of the copyright holder.
diff --git a/src/corelib/text/qlatin1stringmatcher.cpp b/src/corelib/text/qlatin1stringmatcher.cpp
index 68bf97db5c..9036048fff 100644
--- a/src/corelib/text/qlatin1stringmatcher.cpp
+++ b/src/corelib/text/qlatin1stringmatcher.cpp
@@ -160,6 +160,31 @@ Qt::CaseSensitivity QLatin1StringMatcher::caseSensitivity() const noexcept
*/
qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype from) const noexcept
{
+ return indexIn_helper(haystack, from);
+}
+
+/*!
+ \since 6.8
+ \overload
+
+ Searches for the pattern in the given \a haystack starting from index
+ position \a from.
+
+ \sa caseSensitivity(), pattern()
+*/
+qsizetype QLatin1StringMatcher::indexIn(QStringView haystack, qsizetype from) const noexcept
+{
+ return indexIn_helper(haystack, from);
+}
+
+/*!
+ \internal
+*/
+template <typename String>
+qsizetype QLatin1StringMatcher::indexIn_helper(String haystack, qsizetype from) const noexcept
+{
+ static_assert(QtPrivate::isLatin1OrUtf16View<String>);
+
if (m_pattern.isEmpty() && from == haystack.size())
return from;
if (from < 0) // Historical behavior (see QString::indexOf and co.)
@@ -167,8 +192,15 @@ qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype fr
if (from >= haystack.size())
return -1;
- auto begin = haystack.begin() + from;
- auto end = haystack.end();
+ const auto start = [haystack] {
+ if constexpr (std::is_same_v<String, QStringView>)
+ return haystack.utf16();
+ else
+ return haystack.begin();
+ }();
+
+ auto begin = start + from;
+ auto end = start + haystack.size();
auto found = begin;
if (m_cs == Qt::CaseSensitive) {
found = m_caseSensitiveSearcher(begin, end, m_pattern.begin(), m_pattern.end()).begin;
@@ -178,7 +210,7 @@ qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype fr
const qsizetype bufferSize = std::min(m_pattern.size(), qsizetype(sizeof m_foldBuffer));
const QLatin1StringView restNeedle = m_pattern.sliced(bufferSize);
const bool needleLongerThanBuffer = restNeedle.size() > 0;
- QLatin1StringView restHaystack = haystack;
+ String restHaystack = haystack;
do {
found = m_caseInsensitiveSearcher(found, end, m_foldBuffer, &m_foldBuffer[bufferSize])
.begin;
@@ -189,13 +221,13 @@ qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype fr
}
restHaystack = haystack.sliced(
qMin(haystack.size(),
- bufferSize + qsizetype(std::distance(haystack.begin(), found))));
+ bufferSize + qsizetype(std::distance(start, found))));
if (restHaystack.startsWith(restNeedle, Qt::CaseInsensitive))
break;
++found;
} while (true);
}
- return std::distance(haystack.begin(), found);
+ return std::distance(start, found);
}
QT_END_NAMESPACE
diff --git a/src/corelib/text/qlatin1stringmatcher.h b/src/corelib/text/qlatin1stringmatcher.h
index 3b8c24fc92..dd3414fc6d 100644
--- a/src/corelib/text/qlatin1stringmatcher.h
+++ b/src/corelib/text/qlatin1stringmatcher.h
@@ -14,6 +14,10 @@
QT_BEGIN_NAMESPACE
namespace QtPrivate {
+template <typename T>
+constexpr inline bool isLatin1OrUtf16View =
+ std::disjunction_v<std::is_same<T, QLatin1StringView>, std::is_same<T, QStringView>>;
+
template<class RandomIt1,
class Hash = std::hash<typename std::iterator_traits<RandomIt1>::value_type>,
class BinaryPredicate = std::equal_to<>>
@@ -147,6 +151,7 @@ public:
Q_CORE_EXPORT Qt::CaseSensitivity caseSensitivity() const noexcept;
Q_CORE_EXPORT qsizetype indexIn(QLatin1StringView haystack, qsizetype from = 0) const noexcept;
+ Q_CORE_EXPORT qsizetype indexIn(QStringView haystack, qsizetype from = 0) const noexcept;
private:
void setSearcher() noexcept;
@@ -164,6 +169,10 @@ private:
CaseSensitiveSearcher m_caseSensitiveSearcher;
CaseInsensitiveSearcher m_caseInsensitiveSearcher;
};
+
+ template <typename String>
+ qsizetype indexIn_helper(String haystack, qsizetype from) const noexcept;
+
char m_foldBuffer[256];
};
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index d2550fadff..86ab072b73 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -3018,6 +3018,14 @@ QString QLocale::standaloneDayName(int day, FormatType type) const
// Calendar look-up of month and day names:
+// Only used in assertions
+[[maybe_unused]] static bool sameLocale(const QLocaleData *locale, const QCalendarLocale &calendar)
+{
+ return locale->m_language_id == calendar.m_language_id
+ && locale->m_script_id == calendar.m_script_id
+ && locale->m_territory_id == calendar.m_territory_id;
+}
+
/*!
\internal
*/
@@ -3126,8 +3134,9 @@ QString QCalendarBackend::monthName(const QLocale &locale, int month, int,
QLocale::FormatType format) const
{
Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
- return rawMonthName(localeMonthIndexData()[locale.d->m_index],
- localeMonthData(), month, format);
+ const QCalendarLocale &monthly = localeMonthIndexData()[locale.d->m_index];
+ Q_ASSERT(sameLocale(locale.d->m_data, monthly));
+ return rawMonthName(monthly, localeMonthData(), month, format);
}
QString QRomanCalendar::monthName(const QLocale &locale, int month, int year,
@@ -3161,8 +3170,9 @@ QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month,
QLocale::FormatType format) const
{
Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
- return rawStandaloneMonthName(localeMonthIndexData()[locale.d->m_index],
- localeMonthData(), month, format);
+ const QCalendarLocale &monthly = localeMonthIndexData()[locale.d->m_index];
+ Q_ASSERT(sameLocale(locale.d->m_data, monthly));
+ return rawStandaloneMonthName(monthly, localeMonthData(), month, format);
}
QString QRomanCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
@@ -4750,6 +4760,11 @@ QStringList QLocale::uiLanguages(TagSeparator separator) const
const bool isSystem = d->m_data == &systemLocaleData;
if (isSystem) {
uiLanguages = systemLocale()->query(QSystemLocale::UILanguages).toStringList();
+ if (separator != TagSeparator::Dash) {
+ // Map from default separator, Dash, used by backends:
+ const QChar join = QLatin1Char(sep);
+ uiLanguages = uiLanguages.replaceInStrings(u"-", QStringView(&join, 1));
+ }
// ... but we need to include likely-adjusted forms of each of those, too.
// For now, collect up locale Ids representing the entries, for later processing:
for (const auto &entry : std::as_const(uiLanguages))
diff --git a/src/corelib/text/qlocale.h b/src/corelib/text/qlocale.h
index cb3eb64193..abef24ea0e 100644
--- a/src/corelib/text/qlocale.h
+++ b/src/corelib/text/qlocale.h
@@ -1173,8 +1173,11 @@ private:
friend class QRomanCalendar;
friend Q_CORE_EXPORT size_t qHash(const QLocale &key, size_t seed) noexcept;
- friend bool operator==(const QLocale &lhs, const QLocale &rhs) { return lhs.equals(rhs); }
- friend bool operator!=(const QLocale &lhs, const QLocale &rhs) { return !lhs.equals(rhs); }
+ friend bool comparesEqual(const QLocale &lhs, const QLocale &rhs) noexcept
+ {
+ return lhs.equals(rhs);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QLocale)
QSharedDataPointer<QLocalePrivate> d;
};
diff --git a/src/corelib/text/qlocale.qdoc b/src/corelib/text/qlocale.qdoc
index f3f0a5cc2d..0cdacfd8e5 100644
--- a/src/corelib/text/qlocale.qdoc
+++ b/src/corelib/text/qlocale.qdoc
@@ -7,6 +7,7 @@
\brief The QLocale class converts between numbers and their
string representations in various languages.
+ \compares equality
\reentrant
\ingroup i18n
\ingroup string-processing
diff --git a/src/corelib/text/qlocale_data_p.h b/src/corelib/text/qlocale_data_p.h
index a06faeffe3..6175398dd9 100644
--- a/src/corelib/text/qlocale_data_p.h
+++ b/src/corelib/text/qlocale_data_p.h
@@ -1402,674 +1402,674 @@ static constexpr quint16 locale_index[] = {
static constexpr QLocaleData locale_data[] = {
// lang script terr lStrt lpMid lpEnd lPair lDelm dec group prcnt zero minus plus exp qtOpn qtEnd altQO altQE lDFmt sDFmt lTFmt sTFmt slDay lDays ssDys sDays snDay nDays am pm byte siQnt iecQn crSym crDsp crFmt crFNg ntLng ntTer currISO curDgt curRnd dow1st wknd+ wknd- grpTop grpMid grpEnd
{ 1, 0, 0, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 8, 0, 17, 0, 0, 0, 0, 56, 56, 83, 96, 0, 0, 0, 5, 22, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 8, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 4, 0, 0, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // C/AnyScript/AnyTerritory
- { 2, 27, 90, 0, 0, 7, 7, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 27, 49, 0, 0, 109, 109, 157, 157, 179, 179, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 6, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 48, 48, 22, 22, 15, 15, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 9, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Abkhazian/Cyrillic/Georgia
- { 3, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 10, 22, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 1, 0, 2, 0, 15, 20, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 12, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 4, 0, 5, 7, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afar/Latin/Ethiopia
- { 3, 66, 67, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 10, 22, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 3, 0, 2, 0, 15, 27, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 12, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 5, 7, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Afar/Latin/Djibouti
- { 3, 66, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 10, 22, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 6, 0, 2, 0, 15, 34, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 12, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 5, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Afar/Latin/Eritrea
- { 4, 66, 216, 0, 0, 16, 16, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 86, 103, 0, 0, 285, 285, 342, 342, 369, 369, 2, 2, 45, 5, 22, 9, 0, 2, 9, 41, 50, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 20, 4, 6, 9, 11, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/South Africa
- { 4, 66, 162, 0, 0, 16, 16, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 103, 10, 22, 285, 285, 342, 342, 369, 369, 2, 2, 45, 5, 22, 10, 20, 2, 9, 41, 61, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 16, 4, 6, 9, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/Namibia
- { 5, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 382, 382, 453, 453, 480, 480, 5, 5, 0, 5, 22, 11, 36, 0, 0, 68, 73, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 71, 71, 27, 27, 13, 13, 3, 3, 4, 17, 23, 4, 14, 4, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Aghem/Latin/Cameroon
- { 6, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 10, 22, 493, 493, 541, 541, 568, 568, 8, 8, 0, 5, 22, 15, 50, 2, 0, 80, 84, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 48, 48, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 10, 4, 0, 4, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Akan/Latin/Ghana
- { 8, 66, 40, 0, 0, 24, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 11, 60, 15, 0, 89, 95, 6, 6, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 10, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Akoose/Latin/Cameroon
- { 9, 66, 3, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 29, 22, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 18, 70, 4, 20, 102, 107, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 7, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 4, 13, 5, 7, 5, 8, {65,76,76}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Albania
- { 9, 66, 126, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 0, 0, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 22, 83, 4, 20, 102, 115, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 1, 6, 5, 7, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Kosovo
- { 9, 66, 140, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 0, 0, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 23, 89, 4, 20, 102, 121, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 3, 16, 5, 7, 5, 18, {77,75,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Macedonia
- { 11, 33, 77, 38, 38, 44, 53, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 19, 20, 163, 186, 42, 54, 679, 679, 706, 706, 732, 732, 21, 20, 54, 57, 22, 26, 105, 2, 9, 139, 143, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 27, 27, 26, 26, 13, 13, 3, 4, 3, 23, 23, 2, 9, 4, 6, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Amharic/Ethiopic/Ethiopia
- { 14, 4, 71, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 28, 114, 27, 0, 148, 155, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {69,71,80}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Egypt
- { 14, 4, 4, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 33, 123, 33, 38, 148, 158, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Algeria
- { 14, 4, 19, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 38, 135, 27, 0, 148, 165, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 6, 0, 7, 7, {66,72,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Bahrain
- { 14, 4, 48, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 11, 147, 27, 0, 148, 172, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 4, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Chad
- { 14, 4, 55, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 0, 0, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 12, 162, 27, 0, 148, 176, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 10, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 2, 14, 6, 0, 7, 9, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Comoros
- { 14, 4, 67, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 3, 176, 27, 0, 148, 185, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 11, 6, 0, 7, 6, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Djibouti
- { 14, 4, 74, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 6, 187, 27, 0, 148, 191, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 12, 6, 0, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Eritrea
- { 14, 4, 113, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 43, 199, 27, 0, 148, 198, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Iraq
- { 14, 4, 116, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 1, 1, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 48, 210, 27, 0, 148, 204, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 9, 4, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 7, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Israel
- { 14, 4, 122, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 49, 228, 27, 0, 148, 211, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {74,79,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Jordan
- { 14, 4, 127, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 54, 239, 27, 0, 148, 217, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {75,87,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Kuwait
- { 14, 4, 132, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 59, 250, 27, 0, 148, 223, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 5, {76,66,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Lebanon
- { 14, 4, 135, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 64, 261, 33, 38, 148, 228, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 5, {76,89,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Libya
- { 14, 4, 149, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 69, 271, 27, 0, 148, 233, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 9, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Mauritania
- { 14, 4, 159, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 0, 0, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 73, 286, 33, 38, 148, 242, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 10, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Morocco
- { 14, 4, 176, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 78, 296, 27, 0, 148, 248, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {79,77,82}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Oman
- { 14, 4, 180, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 48, 210, 27, 0, 148, 253, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 18, {73,76,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Palestinian Territories
- { 14, 4, 190, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 83, 306, 27, 0, 148, 271, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {81,65,82}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Qatar
- { 14, 4, 205, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 88, 315, 27, 0, 148, 274, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 24, {83,65,82}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Saudi Arabia
- { 14, 4, 215, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 93, 325, 27, 0, 148, 298, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 10, 6, 0, 7, 7, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Somalia
- { 14, 4, 219, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 94, 335, 27, 0, 148, 305, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 17, 6, 0, 7, 12, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/South Sudan
- { 14, 4, 222, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 95, 352, 27, 0, 148, 317, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 11, 6, 0, 7, 7, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Sudan
- { 14, 4, 227, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 99, 363, 27, 0, 148, 324, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Syria
- { 14, 4, 238, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 104, 373, 33, 38, 148, 329, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 5, 7, 7, 4, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Tunisia
- { 14, 4, 245, 61, 61, 61, 61, 6, 0, 1, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 109, 384, 33, 38, 148, 333, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 24, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/United Arab Emirates
- { 14, 4, 257, 61, 61, 61, 61, 6, 0, 1, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 73, 286, 33, 38, 148, 357, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 15, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Western Sahara
- { 14, 4, 258, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 0, 0, 27, 0, 372, 394, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 0, 0, 6, 0, 22, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/world
- { 14, 4, 259, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 42, 54, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 114, 396, 27, 0, 148, 400, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 5, {89,69,82}, 0, 0, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Yemen
- { 15, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 15, 15, 223, 129, 1, 1, 809, 809, 860, 860, 887, 887, 0, 0, 0, 5, 22, 22, 405, 2, 9, 405, 413, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 9, 4, 51, 51, 27, 27, 16, 16, 2, 2, 4, 17, 23, 1, 4, 4, 6, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Aragonese/Latin/Spain
- { 17, 5, 12, 0, 0, 75, 75, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 245, 49, 0, 0, 903, 903, 964, 964, 991, 991, 0, 0, 121, 127, 22, 119, 409, 4, 0, 420, 427, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 8, 10, 5, 61, 61, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 13, 5, 0, 7, 8, {65,77,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Armenian/Armenian/Armenia
- { 18, 9, 110, 0, 0, 82, 82, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 283, 61, 61, 1004, 1004, 1061, 1061, 1092, 1092, 25, 25, 144, 148, 22, 120, 422, 2, 9, 435, 442, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 57, 57, 31, 31, 13, 13, 9, 7, 4, 37, 23, 1, 12, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Assamese/Bangla/India
- { 19, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 223, 129, 0, 0, 1105, 1105, 1158, 1158, 1185, 1185, 34, 32, 0, 5, 22, 22, 405, 4, 0, 446, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 10, 5, 53, 53, 27, 27, 13, 13, 12, 11, 5, 17, 23, 1, 4, 5, 0, 9, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Asturian/Latin/Spain
- { 20, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 1198, 1198, 1257, 1257, 1284, 1284, 46, 43, 0, 5, 22, 121, 434, 4, 0, 461, 467, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 27, 27, 13, 13, 9, 8, 4, 17, 23, 3, 21, 5, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Asu/Latin/Tanzania
- { 21, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 0, 0, 1297, 1297, 1383, 1383, 83, 83, 0, 0, 0, 5, 22, 124, 455, 15, 0, 475, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 86, 86, 33, 33, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Atsam/Latin/Nigeria
- { 25, 66, 17, 0, 0, 91, 91, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 291, 49, 0, 0, 1416, 1416, 1482, 1508, 96, 96, 0, 0, 185, 5, 22, 125, 459, 4, 0, 480, 490, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Latin/Azerbaijan
- { 25, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Azerbaijani/Arabic/Iran
- { 25, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Azerbaijani/Arabic/Iraq
- { 25, 4, 239, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 126, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 0, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Arabic/Turkey
- { 25, 27, 17, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 291, 49, 0, 0, 1534, 1534, 1600, 1600, 96, 96, 55, 51, 0, 5, 22, 125, 476, 4, 0, 506, 516, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 5, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Cyrillic/Azerbaijan
- { 26, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 16, 17, 113, 129, 0, 0, 1626, 1626, 1670, 1670, 1698, 1698, 57, 53, 0, 5, 22, 11, 481, 4, 0, 526, 531, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 44, 44, 28, 28, 13, 13, 6, 7, 4, 17, 23, 4, 4, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bafia/Latin/Cameroon
- { 28, 66, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 0, 0, 1711, 1711, 1754, 1754, 1781, 1781, 0, 0, 0, 5, 22, 127, 485, 2, 9, 538, 547, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 17, 4, 6, 9, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Latin/Mali
- { 28, 90, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 127, 0, 2, 9, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 4, 6, 0, 0, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Nko/Mali
- { 30, 9, 20, 0, 0, 99, 99, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 129, 42, 54, 1794, 1794, 1851, 1851, 1887, 1887, 0, 0, 144, 5, 22, 132, 502, 0, 45, 551, 556, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 14, 4, 6, 5, 8, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Bangla/Bangla/Bangladesh
- { 30, 9, 110, 0, 0, 99, 99, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 129, 42, 54, 1794, 1794, 1851, 1851, 1887, 1887, 0, 0, 144, 5, 22, 120, 516, 2, 9, 551, 564, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bangla/Bangla/India
- { 31, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 113, 129, 0, 0, 1904, 1904, 1973, 1973, 2000, 2000, 63, 60, 0, 5, 22, 11, 528, 4, 0, 568, 573, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 69, 69, 27, 27, 13, 13, 10, 9, 4, 17, 23, 4, 15, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Basaa/Latin/Cameroon
- { 32, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 581, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bashkir/Cyrillic/Russia
- { 33, 66, 220, 0, 0, 108, 108, 6, 1, 0, 2, 3, 48, 5, 10, 11, 12, 14, 15, 308, 344, 73, 0, 2013, 2013, 2080, 2080, 2107, 2107, 0, 0, 189, 5, 22, 22, 543, 4, 20, 593, 600, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 6, 12, 5, 67, 67, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 5, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Basque/Latin/Spain
- { 35, 27, 22, 0, 0, 117, 117, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 50, 85, 0, 2120, 2120, 2175, 2175, 2195, 2195, 0, 0, 196, 201, 22, 1, 548, 4, 0, 608, 618, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 7, 11, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 16, 5, 0, 10, 8, {66,89,78}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Belarusian/Cyrillic/Belarus
- { 36, 66, 260, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 2208, 2208, 2208, 2208, 83, 83, 73, 69, 0, 5, 22, 134, 0, 2, 9, 626, 635, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 79, 79, 79, 79, 13, 13, 8, 7, 4, 17, 23, 1, 0, 4, 6, 9, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bemba/Latin/Zambia
- { 37, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 2287, 2287, 2368, 2368, 2395, 2395, 81, 76, 0, 5, 22, 121, 564, 0, 0, 641, 647, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 81, 81, 27, 27, 13, 13, 7, 7, 4, 17, 23, 3, 22, 4, 0, 6, 10, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Bena/Latin/Tanzania
- { 38, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 42, 54, 2408, 2408, 2408, 2408, 83, 83, 88, 83, 0, 5, 22, 120, 0, 2, 0, 657, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 55, 55, 55, 55, 13, 13, 3, 4, 4, 17, 23, 1, 0, 4, 0, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Bhojpuri/Devanagari/India
- { 40, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 372, 78, 42, 54, 2463, 2463, 2505, 2505, 2530, 2530, 0, 0, 0, 5, 22, 6, 0, 2, 0, 668, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 12, 7, 42, 42, 25, 25, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 3, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Blin/Ethiopic/Eritrea
- { 41, 29, 110, 0, 0, 124, 134, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 291, 394, 96, 108, 2543, 2597, 2650, 2650, 2682, 2682, 91, 87, 0, 5, 22, 120, 586, 2, 9, 675, 664, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 10, 54, 53, 32, 32, 17, 17, 3, 6, 4, 17, 23, 1, 11, 4, 6, 3, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bodo/Devanagari/India
- { 42, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 16, 17, 404, 423, 0, 0, 2699, 2699, 2756, 2756, 2783, 2796, 94, 93, 218, 5, 22, 135, 597, 4, 0, 678, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 11, 10, 5, 57, 57, 27, 27, 13, 13, 10, 7, 7, 17, 23, 2, 40, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Latin/Bosnia and Herzegovina
- { 42, 27, 29, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 434, 454, 0, 0, 2809, 2809, 2864, 2864, 2891, 2891, 104, 100, 0, 5, 22, 137, 637, 4, 0, 705, 713, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 7, 10, 5, 55, 55, 27, 27, 13, 13, 11, 13, 4, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Cyrillic/Bosnia and Herzegovina
- { 43, 66, 84, 0, 0, 157, 157, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 186, 0, 0, 2904, 2904, 2946, 2946, 2978, 2978, 115, 113, 225, 232, 249, 22, 405, 4, 0, 732, 741, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 42, 42, 32, 32, 17, 17, 4, 4, 7, 17, 23, 1, 4, 5, 0, 9, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Breton/Latin/France
- { 45, 27, 36, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 13, 14, 350, 461, 118, 1, 2995, 2995, 3049, 3049, 3069, 3069, 119, 117, 272, 5, 22, 139, 656, 4, 20, 746, 755, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 12, 14, 4, 54, 54, 20, 20, 13, 13, 6, 6, 7, 17, 23, 3, 13, 5, 7, 9, 8, {66,71,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Bulgarian/Cyrillic/Bulgaria
- { 46, 86, 161, 165, 165, 172, 172, 182, 0, 1, 2, 50, 4, 5, 10, 14, 15, 16, 17, 473, 129, 132, 1, 3082, 3082, 3082, 3082, 3135, 3135, 125, 123, 279, 5, 22, 134, 669, 15, 0, 763, 763, 7, 7, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 4, 53, 53, 53, 53, 13, 13, 5, 3, 5, 17, 23, 1, 11, 5, 0, 6, 6, {77,77,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Burmese/Myanmar/Myanmar
- { 47, 137, 107, 183, 183, 188, 188, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 491, 505, 142, 27, 3148, 3148, 3148, 3148, 3175, 3175, 130, 126, 0, 5, 22, 142, 680, 2, 9, 769, 771, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 13, 6, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 2, 4, 6, 2, 14, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cantonese/Traditional Han/Hong Kong
- { 47, 118, 50, 183, 183, 188, 188, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 505, 132, 0, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 0, 5, 22, 145, 682, 2, 9, 785, 787, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 10, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 2, 7, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cantonese/Simplified Han/China
- { 48, 66, 220, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 74, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 413, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 11, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Spain
- { 48, 66, 6, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 74, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 800, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 11, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Andorra
- { 48, 66, 84, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 74, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 807, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 11, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/France
- { 48, 66, 117, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 74, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 813, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 11, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Italy
- { 49, 66, 185, 0, 0, 193, 202, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 3294, 3294, 3349, 3349, 3376, 3376, 0, 0, 284, 5, 22, 146, 685, 2, 9, 819, 826, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 55, 55, 27, 27, 13, 13, 2, 2, 8, 17, 23, 1, 15, 4, 6, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cebuano/Latin/Philippines
- { 50, 66, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 3389, 3389, 3436, 3436, 3463, 3463, 137, 133, 0, 5, 22, 0, 700, 4, 0, 835, 852, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 47, 47, 27, 27, 13, 13, 9, 10, 4, 17, 23, 0, 15, 5, 0, 17, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Central Atlas Tamazight/Latin/Morocco
- { 51, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 25, 55, 57, 59, 14, 15, 16, 17, 163, 103, 42, 54, 3476, 3476, 3476, 3476, 3533, 3533, 146, 143, 0, 5, 22, 43, 715, 4, 0, 858, 872, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 5, 13, 5, 0, 14, 5, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Central Kurdish/Arabic/Iraq
- { 51, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 25, 55, 57, 59, 14, 15, 16, 17, 163, 103, 0, 0, 3476, 3476, 3476, 3476, 3533, 3533, 146, 143, 0, 5, 22, 0, 728, 4, 0, 858, 877, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 0, 12, 5, 0, 14, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Central Kurdish/Arabic/Iran
- { 52, 21, 20, 0, 0, 210, 210, 6, 0, 1, 2, 61, 4, 5, 10, 14, 15, 16, 17, 265, 129, 42, 54, 3546, 3546, 3672, 3672, 3756, 3756, 0, 0, 292, 5, 22, 132, 740, 0, 45, 882, 894, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 21, 4, 6, 12, 14, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Chakma/Chakma/Bangladesh
- { 52, 21, 110, 0, 0, 210, 210, 6, 0, 1, 2, 61, 4, 5, 10, 14, 15, 16, 17, 265, 129, 42, 54, 3546, 3546, 3672, 3672, 3756, 3756, 0, 0, 292, 5, 22, 120, 761, 0, 45, 882, 908, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 27, 4, 6, 12, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Chakma/Chakma/India
- { 54, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 3794, 3794, 3838, 3838, 3862, 3838, 0, 0, 0, 5, 22, 133, 788, 4, 0, 918, 925, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 44, 44, 24, 24, 16, 24, 2, 2, 4, 17, 23, 1, 11, 5, 0, 7, 5, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chechen/Cyrillic/Russia
- { 55, 23, 248, 0, 0, 222, 231, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 42, 54, 3878, 3878, 3926, 3926, 3953, 3953, 149, 146, 300, 5, 22, 10, 799, 2, 9, 930, 933, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 27, 27, 13, 13, 3, 6, 6, 17, 23, 1, 6, 4, 6, 3, 15, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cherokee/Cherokee/United States
- { 56, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 3966, 3966, 3966, 3966, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 948, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 87, 87, 87, 87, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 16, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chickasaw/Latin/United States
- { 57, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 4053, 4053, 4126, 4126, 4153, 4153, 0, 0, 0, 5, 22, 147, 805, 2, 0, 977, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Chiga/Latin/Uganda
- { 58, 118, 50, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 505, 132, 0, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 150, 682, 2, 9, 989, 993, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 10, 5, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 3, 4, 6, 4, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/China
- { 58, 118, 107, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 129, 155, 27, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 142, 824, 2, 9, 989, 995, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 11, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Hong Kong
- { 58, 118, 139, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 129, 155, 27, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 151, 826, 2, 9, 989, 1004, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 11, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Macao
- { 58, 118, 210, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 78, 155, 27, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 10, 829, 2, 9, 989, 1013, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 11, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 4, 4, 6, 4, 3, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Singapore
- { 58, 137, 107, 183, 183, 244, 244, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 129, 142, 27, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 308, 5, 22, 142, 824, 2, 9, 1016, 1020, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Hong Kong
- { 58, 137, 139, 183, 183, 244, 244, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 129, 142, 27, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 308, 5, 22, 151, 833, 2, 9, 1016, 1029, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Macao
- { 58, 137, 228, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 491, 505, 142, 27, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 0, 5, 22, 10, 836, 2, 9, 1016, 1038, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 13, 6, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 4, 2, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Taiwan
- { 59, 27, 193, 0, 0, 249, 249, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 573, 596, 0, 0, 4186, 4186, 4253, 4253, 4289, 4289, 0, 0, 0, 5, 22, 133, 839, 4, 0, 1040, 1059, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 67, 67, 36, 36, 13, 13, 2, 2, 4, 17, 23, 1, 18, 5, 0, 19, 7, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Church/Cyrillic/Russia
- { 60, 27, 193, 0, 0, 257, 257, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 606, 49, 0, 0, 4302, 4302, 4367, 4367, 4399, 4399, 0, 0, 0, 5, 22, 133, 857, 4, 0, 1066, 1071, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 65, 65, 32, 32, 13, 13, 2, 2, 4, 17, 23, 1, 12, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chuvash/Cyrillic/Russia
- { 61, 66, 91, 0, 0, 267, 267, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 18, 16, 628, 423, 0, 0, 4412, 4412, 4483, 4483, 4510, 4510, 152, 152, 0, 5, 22, 22, 83, 4, 0, 1077, 1083, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 23, 10, 10, 5, 71, 71, 27, 27, 13, 13, 16, 16, 4, 17, 23, 1, 4, 5, 0, 6, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Colognian/Latin/Germany
- { 63, 66, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 0, 0, 4523, 4523, 4583, 4583, 83, 83, 168, 168, 0, 5, 22, 94, 0, 2, 0, 1094, 1102, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 60, 60, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 8, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cornish/Latin/United Kingdom
- { 64, 66, 84, 0, 0, 275, 275, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 651, 186, 0, 0, 4610, 4610, 4660, 4660, 4694, 4694, 0, 0, 0, 5, 22, 155, 405, 4, 51, 1116, 1121, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 10, 10, 5, 50, 50, 34, 34, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 7, 5, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Corsican/Latin/France
- { 66, 66, 60, 0, 0, 143, 143, 6, 1, 0, 2, 3, 48, 5, 10, 13, 14, 18, 16, 404, 676, 73, 0, 2699, 2699, 2756, 2756, 2783, 2796, 0, 0, 218, 5, 22, 22, 405, 4, 0, 1128, 1136, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 12, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 0, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Croatia
- { 66, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 48, 5, 10, 13, 14, 18, 16, 404, 689, 73, 0, 2699, 2699, 2756, 2756, 2796, 2796, 0, 0, 218, 5, 22, 135, 618, 4, 0, 1128, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 9, 12, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Bosnia and Herzegovina
- { 67, 66, 64, 0, 0, 282, 282, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 18, 16, 698, 49, 86, 1, 4707, 4707, 4755, 4755, 4775, 4775, 172, 172, 311, 5, 22, 158, 869, 4, 0, 1144, 1151, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 4, 48, 48, 20, 20, 13, 13, 4, 4, 5, 17, 23, 2, 12, 5, 0, 7, 5, {67,90,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Czech/Latin/Czechia
- { 68, 66, 65, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 715, 49, 166, 166, 4788, 4788, 4838, 4838, 4874, 4874, 0, 0, 0, 5, 22, 160, 881, 4, 0, 1156, 1161, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Denmark
- { 68, 66, 95, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 715, 49, 166, 166, 4788, 4788, 4838, 4838, 4874, 4874, 0, 0, 0, 5, 22, 160, 881, 4, 0, 1156, 1168, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 8, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Greenland
- { 69, 132, 144, 0, 0, 0, 0, 2, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 163, 0, 15, 0, 1176, 1186, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 10, 13, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // Divehi/Thaana/Maldives
- { 70, 29, 110, 0, 0, 297, 306, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 738, 129, 42, 54, 4887, 4887, 4937, 4937, 4966, 4988, 176, 176, 0, 5, 22, 120, 892, 2, 0, 1199, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 50, 50, 29, 29, 22, 24, 4, 9, 4, 17, 23, 1, 10, 4, 0, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Dogri/Devanagari/India
- { 71, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 16, 17, 113, 129, 0, 0, 5012, 5012, 5056, 5056, 5083, 5083, 180, 185, 0, 5, 22, 11, 0, 4, 0, 1204, 1209, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 44, 44, 27, 27, 13, 13, 5, 6, 4, 17, 23, 4, 0, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Duala/Latin/Cameroon
- { 72, 66, 165, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 0, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 22, 83, 15, 58, 1217, 1217, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Netherlands
- { 72, 66, 13, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 0, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 165, 902, 15, 58, 1217, 1227, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 16, 5, 7, 10, 5, {65,87,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Aruba
- { 72, 66, 23, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 187, 0, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 22, 83, 15, 58, 1232, 1238, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Belgium
- { 72, 66, 44, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 0, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 10, 918, 15, 58, 1217, 1244, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 18, 5, 7, 10, 19, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Caribbean Netherlands
- { 72, 66, 62, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 0, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 169, 936, 15, 58, 1217, 1263, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 7, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Curacao
- { 72, 66, 211, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 0, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 169, 936, 15, 58, 1217, 1270, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Sint Maarten
- { 72, 66, 223, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 0, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 10, 966, 15, 58, 1217, 1282, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 17, 5, 7, 10, 8, {83,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Suriname
- { 73, 134, 27, 314, 314, 314, 314, 6, 0, 1, 2, 67, 4, 5, 10, 14, 15, 16, 17, 756, 103, 176, 203, 5187, 5187, 5265, 5265, 5298, 5298, 185, 191, 0, 5, 22, 173, 983, 2, 0, 1290, 1296, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 10, 27, 22, 78, 78, 33, 33, 26, 26, 5, 6, 4, 17, 23, 3, 8, 4, 0, 6, 5, {66,84,78}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Dzongkha/Tibetan/Bhutan
- { 74, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 5324, 5324, 5387, 5387, 5414, 5414, 190, 197, 0, 5, 22, 176, 991, 2, 9, 1301, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 63, 63, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Embu/Latin/Kenya
- { 75, 66, 248, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1312, 964, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 16, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States
- { 75, 28, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 5427, 5427, 5511, 5511, 5559, 5559, 192, 199, 0, 5, 22, 10, 0, 15, 0, 1328, 1338, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 84, 84, 48, 48, 20, 20, 4, 4, 4, 17, 23, 1, 0, 5, 0, 10, 25, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Deseret/United States
- { 75, 66, 5, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1363, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/American Samoa
- { 75, 66, 8, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1377, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Anguilla
- { 75, 66, 10, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1385, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 17, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Antigua and Barbuda
- { 75, 66, 15, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 6, 14, 15, 16, 17, 113, 129, 10, 22, 0, 0, 56, 56, 83, 5579, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1402, 1402, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 56, 56, 27, 27, 13, 24, 2, 2, 5, 17, 23, 1, 17, 4, 6, 18, 9, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Australia
- { 75, 66, 16, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 15, 0, 1321, 1420, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Austria
- { 75, 66, 18, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1055, 2, 9, 1321, 1427, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {66,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Bahamas
- { 75, 66, 21, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1070, 2, 9, 1321, 1434, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 8, {66,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Barbados
- { 75, 66, 23, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 78, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1442, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Belgium
- { 75, 66, 24, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1086, 2, 9, 1321, 1449, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Belize
- { 75, 66, 26, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1099, 2, 9, 1321, 1455, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 7, {66,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Bermuda
- { 75, 66, 30, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 153, 1115, 2, 9, 1321, 1462, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 8, {66,87,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Botswana
- { 75, 66, 33, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1470, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 30, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Indian Ocean Territory
- { 75, 66, 34, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1500, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Virgin Islands
- { 75, 66, 38, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 0, 0, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 182, 1129, 2, 9, 1321, 1522, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Burundi
- { 75, 66, 40, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 11, 1144, 2, 9, 1321, 1529, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 25, 4, 6, 7, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cameroon
- { 75, 66, 41, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 103, 10, 22, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 10, 1169, 2, 9, 1537, 1553, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 12, 7, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 15, 4, 6, 16, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Canada
- { 75, 66, 45, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1184, 2, 9, 1321, 1559, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 14, {75,89,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cayman Islands
- { 75, 66, 51, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1573, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 16, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Christmas Island
- { 75, 66, 53, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1589, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 23, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cocos Islands
- { 75, 66, 58, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1612, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cook Islands
- { 75, 66, 63, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 2, 9, 1321, 1624, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cyprus
- { 75, 66, 65, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 166, 166, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 160, 1223, 4, 0, 1321, 1630, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 12, 5, 0, 7, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Denmark
- { 75, 66, 66, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1637, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 12, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Diego Garcia
- { 75, 66, 68, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1649, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Dominica
- { 75, 66, 74, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 6, 1235, 2, 9, 1321, 1657, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 14, 4, 6, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eritrea
- { 75, 66, 76, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 155, 1249, 2, 9, 1321, 1664, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 8, {83,90,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eswatini
- { 75, 66, 78, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 0, 4, 0, 1321, 1672, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 0, 7, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Europe
- { 75, 66, 80, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1264, 2, 9, 1321, 1678, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {70,75,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Falkland Islands
- { 75, 66, 82, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1286, 2, 9, 1321, 1694, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 4, {70,74,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Fiji
- { 75, 66, 83, 0, 0, 333, 333, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 167, 167, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1698, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 9, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Finland
- { 75, 66, 89, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 185, 1299, 2, 9, 1321, 1705, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gambia
- { 75, 66, 91, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1711, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Germany
- { 75, 66, 92, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 15, 1313, 2, 9, 1321, 1718, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 13, 4, 6, 7, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ghana
- { 75, 66, 93, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1326, 2, 9, 1321, 1723, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {71,73,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gibraltar
- { 75, 66, 96, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1732, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 7, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Grenada
- { 75, 66, 98, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1739, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 4, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Guam
- { 75, 66, 100, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1743, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 8, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guernsey
- { 75, 66, 103, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1349, 2, 9, 1321, 1751, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 6, {71,89,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guyana
- { 75, 66, 107, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 142, 1365, 2, 9, 1321, 1757, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 19, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Hong Kong
- { 75, 66, 110, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 78, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 120, 1381, 2, 9, 1321, 1478, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 12, 4, 6, 7, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // English/Latin/India
- { 75, 66, 111, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 166, 166, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 186, 1393, 2, 9, 1321, 1776, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Indonesia
- { 75, 66, 114, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 0, 0, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 22, 83, 2, 9, 1321, 1785, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 4, 4, 6, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ireland
- { 75, 66, 115, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1792, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 11, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Isle of Man
- { 75, 66, 116, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 1, 1, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 48, 1410, 2, 9, 1321, 1803, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 9, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 6, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // English/Latin/Israel
- { 75, 66, 119, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1428, 2, 9, 1321, 1809, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {74,77,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Jamaica
- { 75, 66, 121, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1816, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 6, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Jersey
- { 75, 66, 124, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 176, 1443, 2, 9, 1321, 1307, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Kenya
- { 75, 66, 125, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1822, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 8, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Kiribati
- { 75, 66, 133, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 9, 1458, 2, 9, 1321, 1830, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {90,65,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Lesotho
- { 75, 66, 134, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1476, 2, 9, 1321, 1837, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Liberia
- { 75, 66, 139, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 151, 1491, 2, 9, 1321, 1844, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 15, 4, 6, 7, 15, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Macao
- { 75, 66, 141, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 188, 1506, 2, 9, 1321, 1859, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Madagascar
- { 75, 66, 142, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 190, 1521, 2, 9, 1321, 1869, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 6, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malawi
- { 75, 66, 143, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 192, 1536, 2, 9, 1321, 1875, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malaysia
- { 75, 66, 144, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 194, 1553, 15, 0, 1321, 1883, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // English/Latin/Maldives
- { 75, 66, 146, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 2, 9, 1321, 1891, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Malta
- { 75, 66, 147, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1896, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 16, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Marshall Islands
- { 75, 66, 150, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 196, 1570, 2, 9, 1321, 1912, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 9, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Mauritius
- { 75, 66, 153, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1921, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 10, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Micronesia
- { 75, 66, 158, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1931, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 10, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Montserrat
- { 75, 66, 162, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1585, 2, 9, 1321, 1941, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Namibia
- { 75, 66, 163, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1948, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 5, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nauru
- { 75, 66, 165, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 15, 58, 1321, 1953, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Netherlands
- { 75, 66, 167, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1964, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 11, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/New Zealand
- { 75, 66, 169, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 124, 1600, 2, 9, 1321, 1975, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 7, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nigeria
- { 75, 66, 171, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1982, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 4, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Niue
- { 75, 66, 172, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1986, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 14, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Norfolk Island
- { 75, 66, 173, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2000, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 24, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Northern Mariana Islands
- { 75, 66, 178, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 196, 1614, 2, 9, 1321, 2024, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 8, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Pakistan
- { 75, 66, 179, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2032, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 5, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Palau
- { 75, 66, 182, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 134, 1629, 2, 9, 1321, 2037, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Papua New Guinea
- { 75, 66, 185, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 685, 2, 9, 1321, 2053, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 11, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Philippines
- { 75, 66, 186, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 2064, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 16, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Pitcairn
- { 75, 66, 189, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2080, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Puerto Rico
- { 75, 66, 194, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 198, 1651, 2, 9, 1321, 2091, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 4, 6, 7, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Rwanda
- { 75, 66, 196, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1664, 2, 9, 1321, 2097, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {83,72,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Helena
- { 75, 66, 197, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2106, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 16, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Kitts and Nevis
- { 75, 66, 198, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2122, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Lucia
- { 75, 66, 201, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2130, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 27, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Vincent and Grenadines
- { 75, 66, 202, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 200, 1679, 2, 9, 1321, 1372, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 11, 4, 6, 7, 5, {87,83,84}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Samoa
- { 75, 66, 208, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 203, 1690, 2, 9, 1321, 2157, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Seychelles
- { 75, 66, 209, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 18, 1707, 2, 9, 1321, 2167, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 20, 4, 6, 7, 12, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sierra Leone
- { 75, 66, 210, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1727, 2, 9, 1321, 2179, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Singapore
- { 75, 66, 211, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 169, 1743, 2, 9, 1321, 2188, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 29, 4, 6, 7, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sint Maarten
- { 75, 66, 213, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 6, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 20, 1321, 2200, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Slovenia
- { 75, 66, 214, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1772, 2, 9, 1321, 2208, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 15, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Solomon Islands
- { 75, 66, 216, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 821, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 9, 1458, 2, 9, 1321, 2223, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/South Africa
- { 75, 66, 219, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1794, 2, 9, 1321, 2235, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 11, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/South Sudan
- { 75, 66, 222, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 1814, 2, 9, 1321, 2246, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 14, 4, 6, 7, 5, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // English/Latin/Sudan
- { 75, 66, 225, 0, 0, 333, 333, 6, 1, 9, 2, 3, 4, 5, 63, 14, 15, 16, 17, 0, 103, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 160, 1828, 4, 0, 1321, 2251, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 5, 0, 7, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sweden
- { 75, 66, 226, 0, 0, 333, 333, 6, 0, 17, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 49, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 1841, 15, 65, 1321, 2257, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 11, 5, 5, 7, 11, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Switzerland
- { 75, 66, 230, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 121, 1852, 2, 9, 1321, 2268, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 18, 4, 6, 7, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tanzania
- { 75, 66, 234, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 2276, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tokelau
- { 75, 66, 235, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 205, 1870, 2, 9, 1321, 2283, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 14, 4, 6, 7, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tonga
- { 75, 66, 236, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1884, 2, 9, 1321, 2288, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 24, 4, 6, 7, 17, {84,84,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Trinidad and Tobago
- { 75, 66, 241, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2305, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Turks and Caicos Islands
- { 75, 66, 242, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 2327, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 6, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tuvalu
- { 75, 66, 243, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 147, 1908, 2, 9, 1321, 983, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // English/Latin/Uganda
- { 75, 66, 245, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 1924, 2, 9, 1321, 2333, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 27, 4, 6, 7, 20, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // English/Latin/United Arab Emirates
- { 75, 66, 246, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1951, 2, 9, 2353, 2368, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 15, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/United Kingdom
- { 75, 66, 247, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2382, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 21, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Outlying Islands
- { 75, 66, 249, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2403, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Virgin Islands
- { 75, 66, 252, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 207, 1964, 2, 9, 1321, 2422, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 12, 4, 6, 7, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Vanuatu
- { 75, 66, 258, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 0, 2, 9, 1321, 2429, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 4, 6, 7, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/world
- { 75, 66, 260, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 134, 1976, 2, 9, 1321, 635, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Zambia
- { 75, 66, 261, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 129, 0, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2434, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Zimbabwe
- { 75, 115, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 5603, 5603, 5690, 5690, 5731, 5731, 196, 205, 0, 5, 22, 94, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 87, 87, 41, 41, 20, 20, 4, 4, 4, 17, 23, 1, 0, 5, 0, 0, 0, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Shavian/United Kingdom
- { 76, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 5751, 5811, 5892, 5892, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 2442, 2453, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 60, 81, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 11, 13, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Erzya/Cyrillic/Russia
- { 77, 66, 258, 0, 0, 342, 342, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 831, 105, 0, 0, 5919, 5919, 5969, 5969, 5989, 5989, 200, 209, 316, 5, 22, 0, 0, 4, 0, 2466, 2475, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 8, 10, 5, 50, 50, 20, 20, 13, 13, 3, 3, 6, 17, 23, 0, 0, 5, 0, 9, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Esperanto/Latin/world
- { 78, 66, 75, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 18, 16, 404, 49, 0, 0, 6002, 6002, 6064, 6064, 6064, 6064, 0, 0, 322, 5, 22, 22, 405, 4, 20, 2480, 2485, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 13, 13, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Estonian/Latin/Estonia
- { 79, 66, 92, 0, 0, 359, 370, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 862, 567, 225, 225, 6077, 6077, 6120, 6120, 6147, 6147, 203, 212, 0, 5, 22, 15, 1990, 2, 9, 2490, 2496, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 17, 12, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 3, 10, 4, 6, 6, 12, {71,72,83}, 2, 1, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Ghana
- { 79, 66, 233, 0, 0, 359, 370, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 862, 567, 0, 0, 6077, 6077, 6120, 6120, 6147, 6147, 203, 212, 0, 5, 22, 127, 2000, 2, 9, 2490, 2508, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 10, 5, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 5, 33, 4, 6, 6, 11, {88,79,70}, 0, 0, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Togo
- { 80, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 0, 0, 6160, 6160, 6244, 6244, 6273, 6273, 206, 217, 0, 5, 22, 11, 2033, 4, 0, 2519, 2525, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 84, 84, 29, 29, 13, 13, 7, 9, 4, 17, 23, 4, 16, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ewondo/Latin/Cameroon
- { 81, 66, 81, 0, 0, 380, 289, 6, 1, 0, 2, 3, 48, 5, 10, 14, 15, 16, 17, 404, 49, 0, 0, 6286, 6286, 6359, 6386, 6420, 6420, 0, 0, 328, 5, 22, 160, 2049, 4, 20, 2532, 2540, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 2, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Faroe Islands
- { 81, 66, 65, 0, 0, 380, 289, 6, 1, 0, 2, 3, 48, 5, 10, 14, 15, 16, 17, 404, 49, 0, 0, 6286, 6286, 6359, 6386, 6420, 6420, 0, 0, 328, 5, 22, 160, 2049, 4, 20, 2532, 1161, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 3, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Denmark
- { 83, 66, 185, 0, 0, 389, 398, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 6433, 6433, 6487, 6487, 6487, 6487, 0, 0, 0, 5, 22, 146, 2060, 2, 9, 2547, 826, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 54, 54, 27, 27, 27, 27, 2, 2, 5, 17, 23, 1, 17, 4, 6, 8, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Filipino/Latin/Philippines
- { 84, 66, 83, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 10, 15, 15, 17, 17, 698, 885, 167, 167, 6514, 6580, 6660, 6660, 6680, 6680, 213, 226, 331, 336, 353, 22, 405, 4, 0, 2555, 2560, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 9, 4, 66, 80, 20, 20, 13, 13, 3, 3, 5, 17, 23, 1, 4, 5, 0, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Finnish/Latin/Finland
- { 85, 66, 84, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2573, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/France
- { 85, 66, 4, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 22, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 209, 2077, 4, 20, 2565, 2579, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // French/Latin/Algeria
- { 85, 66, 23, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 79, 242, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2586, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 7, 23, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Belgium
- { 85, 66, 25, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2594, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Benin
- { 85, 66, 37, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2599, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burkina Faso
- { 85, 66, 38, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 182, 2108, 4, 20, 2565, 1522, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 15, 5, 7, 8, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burundi
- { 85, 66, 40, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 216, 229, 376, 232, 249, 11, 2123, 4, 20, 2565, 1209, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 5, 4, 6, 17, 23, 4, 16, 5, 7, 8, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Cameroon
- { 85, 66, 41, 0, 0, 406, 406, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 15, 14, 113, 103, 265, 265, 6693, 6693, 6744, 6744, 6778, 6778, 168, 168, 376, 232, 249, 10, 2139, 4, 20, 2611, 1553, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 24, 9, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 1, 15, 5, 7, 17, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // French/Latin/Canada
- { 85, 66, 46, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2628, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 25, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Central African Republic
- { 85, 66, 48, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 22, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2653, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Chad
- { 85, 66, 55, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 12, 2154, 4, 20, 2565, 2658, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Comoros
- { 85, 66, 56, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2665, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 17, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo - Brazzaville
- { 85, 66, 57, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2168, 4, 20, 2565, 2682, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 14, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo - Kinshasa
- { 85, 66, 67, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 22, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 3, 2183, 4, 20, 2565, 2696, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 16, 5, 7, 8, 8, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // French/Latin/Djibouti
- { 85, 66, 73, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2704, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 18, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Equatorial Guinea
- { 85, 66, 85, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2722, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Guiana
- { 85, 66, 86, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2738, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 19, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Polynesia
- { 85, 66, 88, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2757, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Gabon
- { 85, 66, 97, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2762, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guadeloupe
- { 85, 66, 102, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 215, 2208, 4, 20, 2565, 2704, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 13, 5, 7, 8, 6, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guinea
- { 85, 66, 104, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 15, 2221, 4, 20, 2565, 2772, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 16, 5, 7, 8, 5, {72,84,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Haiti
- { 85, 66, 118, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2777, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 13, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Ivory Coast
- { 85, 66, 138, 0, 0, 406, 406, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2790, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Luxembourg
- { 85, 66, 141, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 188, 2237, 4, 20, 2565, 1859, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Madagascar
- { 85, 66, 145, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 547, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mali
- { 85, 66, 148, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2800, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Martinique
- { 85, 66, 149, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 22, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 217, 2252, 4, 20, 2565, 2810, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 19, 5, 7, 8, 10, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritania
- { 85, 66, 150, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 196, 2271, 4, 20, 2565, 2820, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 18, 5, 7, 8, 7, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritius
- { 85, 66, 151, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2827, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mayotte
- { 85, 66, 155, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2834, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Monaco
- { 85, 66, 159, 0, 0, 406, 406, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 168, 168, 376, 232, 249, 0, 2289, 4, 20, 2565, 2840, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 0, 15, 5, 7, 8, 5, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Morocco
- { 85, 66, 166, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2845, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 18, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/New Caledonia
- { 85, 66, 170, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 1975, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Niger
- { 85, 66, 191, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2863, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Reunion
- { 85, 66, 194, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 198, 2304, 4, 20, 2565, 2091, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Rwanda
- { 85, 66, 195, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2873, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Barthelemy
- { 85, 66, 199, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2889, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Martin
- { 85, 66, 200, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2901, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 24, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Pierre and Miquelon
- { 85, 66, 206, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2925, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Senegal
- { 85, 66, 208, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 203, 2318, 4, 20, 2565, 2157, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 21, 5, 7, 8, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Seychelles
- { 85, 66, 226, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 19, 20, 0, 49, 289, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 0, 2339, 4, 20, 2932, 2947, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 14, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 0, 12, 5, 7, 15, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Switzerland
- { 85, 66, 227, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 22, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 219, 2351, 4, 20, 2565, 2953, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // French/Latin/Syria
- { 85, 66, 233, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2508, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Togo
- { 85, 66, 238, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 22, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 221, 2365, 4, 20, 2565, 2958, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Tunisia
- { 85, 66, 252, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 22, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 207, 2379, 4, 20, 2565, 2422, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Vanuatu
- { 85, 66, 256, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 0, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2965, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 16, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Wallis and Futuna
- { 86, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 14, 15, 893, 78, 0, 0, 6791, 6791, 6840, 6840, 6778, 6778, 5, 128, 0, 5, 22, 22, 405, 15, 0, 2981, 2987, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Friulian/Latin/Italy
- { 87, 66, 206, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 2999, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Senegal
- { 87, 1, 37, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 0, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3017, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 25, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Burkina Faso
- { 87, 1, 40, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 0, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 229, 2463, 15, 0, 3007, 3042, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 8, 44, 5, 0, 10, 16, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Cameroon
- { 87, 1, 89, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 42, 54, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 185, 2507, 15, 0, 3007, 3058, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 29, 5, 0, 10, 14, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Gambia
- { 87, 1, 92, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 42, 54, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 15, 2536, 15, 0, 3007, 3072, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 3, 23, 5, 0, 10, 8, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Ghana
- { 87, 1, 101, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 0, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3080, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 23, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea-Bissau
- { 87, 1, 102, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 0, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 215, 2559, 15, 0, 3007, 3080, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 25, 5, 0, 10, 8, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea
- { 87, 1, 134, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 42, 54, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 10, 2584, 15, 0, 3007, 3103, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 31, 5, 0, 10, 18, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Liberia
- { 87, 1, 149, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 42, 54, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 217, 2615, 15, 0, 3007, 3121, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 37, 5, 0, 10, 16, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Mauritania
- { 87, 1, 169, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 0, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 124, 2652, 15, 0, 3007, 3137, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 33, 5, 0, 10, 18, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Nigeria
- { 87, 1, 170, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 0, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3155, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Niger
- { 87, 1, 206, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 0, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3167, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 16, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Senegal
- { 87, 1, 209, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 42, 54, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 18, 2685, 15, 0, 3007, 3183, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 33, 5, 0, 10, 14, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Sierra Leone
- { 87, 66, 37, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3197, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 14, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Burkina Faso
- { 87, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 11, 2718, 4, 0, 2993, 3211, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 4, 18, 5, 0, 6, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Cameroon
- { 87, 66, 89, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 22, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 185, 2736, 4, 0, 2993, 3219, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 13, 5, 0, 6, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Gambia
- { 87, 66, 92, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 22, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 15, 0, 4, 0, 2993, 3225, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 3, 0, 5, 0, 6, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Ghana
- { 87, 66, 101, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3230, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea-Bissau
- { 87, 66, 102, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 215, 0, 4, 0, 2993, 3230, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 0, 5, 0, 6, 4, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea
- { 87, 66, 134, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 22, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 10, 2749, 4, 0, 2993, 3242, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Liberia
- { 87, 66, 149, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 22, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 217, 2765, 4, 0, 2993, 3251, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 15, 5, 0, 6, 8, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Mauritania
- { 87, 66, 169, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 124, 2780, 4, 0, 2993, 3259, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Nigeria
- { 87, 66, 170, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 0, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Niger
- { 87, 66, 209, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 22, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 18, 2796, 4, 0, 2993, 3274, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 18, 5, 0, 6, 11, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Sierra Leone
- { 88, 66, 246, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 937, 186, 0, 0, 7157, 7157, 7225, 7225, 7252, 7252, 3, 135, 421, 5, 22, 94, 2814, 2, 9, 3285, 3293, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 10, 10, 5, 68, 68, 27, 27, 13, 13, 1, 1, 6, 17, 23, 1, 15, 4, 6, 8, 22, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Gaelic/Latin/United Kingdom
- { 89, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22, 7265, 7265, 7297, 7297, 7323, 7323, 0, 0, 0, 5, 22, 15, 50, 2, 9, 3315, 1718, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 32, 32, 26, 26, 13, 13, 2, 2, 4, 17, 23, 3, 10, 4, 6, 2, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ga/Latin/Ghana
- { 90, 66, 220, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 78, 0, 0, 7336, 7336, 7384, 7384, 1185, 7418, 168, 168, 0, 5, 22, 22, 405, 4, 0, 3317, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 48, 48, 34, 34, 13, 20, 4, 4, 5, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Galician/Latin/Spain
- { 91, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 7438, 7438, 7503, 7503, 7530, 7530, 0, 0, 0, 5, 22, 147, 2829, 0, 0, 3323, 3330, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Ganda/Latin/Uganda
- { 92, 33, 77, 0, 0, 0, 0, 6, 0, 74, 2, 3, 4, 5, 10, 14, 15, 16, 17, 985, 78, 42, 54, 7543, 7543, 7543, 7543, 7571, 7571, 0, 0, 0, 5, 22, 0, 105, 15, 0, 3337, 143, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 12, 7, 28, 28, 28, 28, 13, 13, 2, 2, 4, 17, 23, 0, 9, 5, 0, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Geez/Ethiopic/Ethiopia
- { 92, 33, 74, 0, 0, 0, 0, 6, 0, 74, 2, 3, 4, 5, 10, 14, 15, 16, 17, 985, 78, 42, 54, 7543, 7543, 7543, 7543, 7571, 7571, 0, 0, 0, 5, 22, 6, 0, 15, 0, 3337, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 12, 7, 28, 28, 28, 28, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 4, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Geez/Ethiopic/Eritrea
- { 93, 35, 90, 0, 0, 455, 455, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 11, 12, 1008, 49, 0, 0, 7584, 7584, 7645, 7645, 7672, 7672, 0, 0, 427, 432, 22, 0, 2848, 4, 0, 3341, 3348, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 10, 5, 61, 61, 27, 27, 13, 13, 2, 2, 5, 29, 23, 1, 12, 5, 0, 7, 10, {71,69,76}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Georgian/Georgian/Georgia
- { 94, 66, 91, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3365, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Germany
- { 94, 66, 16, 0, 0, 463, 463, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 15, 0, 3376, 3376, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 24, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Austria
- { 94, 66, 23, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3400, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Belgium
- { 94, 66, 117, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3407, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Italy
- { 94, 66, 136, 0, 0, 463, 463, 6, 0, 17, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 0, 2860, 15, 0, 3358, 3414, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 0, 17, 5, 0, 7, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Liechtenstein
- { 94, 66, 138, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3427, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Luxembourg
- { 94, 66, 226, 0, 0, 463, 463, 6, 0, 17, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 0, 2860, 15, 65, 3436, 3436, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 0, 17, 5, 5, 21, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Switzerland
- { 96, 39, 94, 0, 0, 472, 472, 6, 1, 0, 2, 3, 4, 5, 6, 11, 12, 14, 15, 113, 129, 10, 22, 7791, 7791, 7845, 7845, 7872, 7872, 231, 244, 0, 5, 22, 22, 2877, 4, 0, 3457, 3465, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Greece
- { 96, 39, 63, 0, 0, 472, 472, 6, 1, 0, 2, 3, 4, 5, 6, 11, 12, 14, 15, 113, 129, 10, 22, 7791, 7791, 7845, 7845, 7872, 7872, 231, 244, 0, 5, 22, 22, 2877, 4, 0, 3457, 3471, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Cyprus
- { 97, 66, 183, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 7885, 7885, 7885, 7885, 83, 83, 0, 0, 0, 5, 22, 237, 0, 15, 0, 3477, 3484, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 53, 53, 53, 53, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 8, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Guarani/Latin/Paraguay
- { 98, 40, 110, 0, 0, 481, 481, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 303, 316, 7938, 7938, 7990, 7990, 8021, 8021, 0, 0, 466, 5, 22, 120, 2881, 2, 9, 3492, 3499, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 8, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 13, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Gujarati/Gujarati/India
- { 99, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 8039, 8039, 8100, 8100, 8127, 8127, 235, 248, 0, 5, 22, 176, 991, 2, 9, 3503, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 6, 3, 4, 17, 23, 3, 17, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Gusii/Latin/Kenya
- { 101, 66, 169, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 0, 0, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 124, 2894, 15, 0, 3511, 3259, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 1, 15, 5, 0, 5, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Nigeria
- { 101, 4, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 8231, 8231, 8287, 8287, 83, 83, 0, 0, 0, 5, 22, 124, 2909, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 30, 30, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 0, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Arabic/Nigeria
- { 101, 4, 222, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 8231, 8231, 8287, 8287, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 30, 30, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Hausa/Arabic/Sudan
- { 101, 66, 92, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 10, 22, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 15, 2915, 15, 0, 3511, 3225, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 3, 13, 5, 0, 5, 4, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Ghana
- { 101, 66, 170, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 0, 0, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 127, 2928, 15, 0, 3511, 3516, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 5, 29, 5, 0, 5, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Niger
- { 102, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 10, 22, 8317, 8317, 8373, 8373, 83, 83, 0, 0, 0, 5, 22, 10, 0, 2, 9, 3521, 3535, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 14, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Hawaiian/Latin/United States
- { 103, 47, 116, 0, 0, 507, 507, 6, 0, 1, 2, 3, 35, 37, 10, 15, 15, 17, 17, 1027, 885, 1, 1, 8393, 8393, 8457, 8457, 8502, 8502, 247, 256, 558, 5, 22, 48, 2957, 70, 77, 3554, 3559, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 8, 9, 4, 64, 64, 45, 45, 20, 20, 6, 5, 4, 17, 23, 1, 7, 7, 9, 5, 5, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Hebrew/Hebrew/Israel
- { 105, 29, 110, 0, 0, 513, 522, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 42, 54, 8522, 8522, 8574, 8574, 8605, 8605, 82, 203, 562, 5, 22, 120, 2964, 2, 0, 3564, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Devanagari/India
- { 105, 66, 110, 0, 0, 530, 540, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 186, 10, 22, 8623, 8623, 8689, 8689, 8727, 8727, 0, 0, 0, 5, 22, 120, 1381, 2, 0, 3570, 1478, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 66, 66, 38, 38, 21, 21, 2, 2, 5, 17, 23, 1, 12, 4, 0, 13, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Latin/India
- { 107, 66, 108, 0, 0, 549, 549, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 12, 11, 1045, 1064, 1, 1, 8748, 8748, 8799, 8799, 8817, 8817, 253, 261, 566, 5, 22, 238, 2976, 4, 0, 3583, 3589, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 9, 4, 51, 51, 18, 18, 16, 16, 3, 3, 4, 17, 23, 2, 13, 5, 0, 6, 12, {72,85,70}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Hungarian/Latin/Hungary
- { 108, 66, 109, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 885, 0, 0, 8833, 8833, 8913, 8913, 8947, 8947, 256, 264, 570, 5, 22, 160, 2989, 4, 0, 3601, 3609, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 80, 80, 34, 34, 13, 13, 4, 4, 4, 17, 23, 3, 13, 5, 0, 8, 6, {73,83,75}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Icelandic/Latin/Iceland
- { 109, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 3615, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 3, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ido/Latin/world
- { 110, 66, 169, 0, 0, 557, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 0, 0, 8960, 8960, 9013, 9013, 83, 83, 260, 268, 0, 5, 22, 124, 3002, 2, 9, 3618, 3622, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 53, 53, 28, 28, 13, 13, 7, 7, 4, 17, 23, 1, 5, 4, 6, 4, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Igbo/Latin/Nigeria
- { 111, 66, 83, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1077, 885, 167, 167, 9041, 9110, 9182, 9182, 83, 9209, 267, 275, 0, 5, 22, 22, 405, 4, 0, 3630, 3641, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 9, 4, 69, 72, 27, 27, 13, 13, 3, 3, 4, 17, 23, 1, 4, 5, 0, 11, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Inari Sami/Latin/Finland
- { 112, 66, 111, 0, 0, 574, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 166, 166, 9222, 9222, 9264, 9264, 9291, 9291, 0, 0, 0, 5, 22, 186, 3007, 2, 0, 1776, 1776, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 42, 42, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 16, 4, 0, 9, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Indonesian/Latin/Indonesia
- { 114, 66, 258, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 14, 15, 1095, 394, 0, 0, 9304, 9304, 9360, 9360, 9387, 9387, 0, 0, 0, 5, 22, 0, 0, 15, 58, 3646, 3657, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 7, 11, 5, {0,0,0}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Interlingua/Latin/world
- { 115, 66, 75, 0, 0, 0, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 180, 0, 0, 9400, 9400, 9451, 9451, 9485, 9485, 270, 278, 574, 232, 249, 22, 405, 15, 86, 3662, 3673, 6, 6, 6, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 10, 5, 51, 51, 34, 34, 13, 13, 9, 8, 7, 17, 23, 1, 4, 5, 6, 11, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Interlingue/Latin/Estonia
- { 116, 18, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 1121, 42, 54, 9498, 9498, 9498, 9498, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 3680, 3686, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 12, 7, 54, 54, 54, 54, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 6, 4, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Canadian Aboriginal/Canada
- { 116, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Latin/Canada
- { 118, 66, 114, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 0, 0, 9552, 9552, 9626, 9626, 9662, 9662, 279, 286, 581, 5, 22, 22, 83, 2, 9, 3690, 3697, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 4, 4, 6, 7, 4, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/Ireland
- { 118, 66, 246, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 0, 0, 9552, 9552, 9626, 9626, 9662, 9662, 279, 286, 581, 5, 22, 94, 3023, 2, 9, 3690, 3701, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 14, 4, 6, 7, 19, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/United Kingdom
- { 119, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 0, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Italy
- { 119, 66, 203, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 0, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3734, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/San Marino
- { 119, 66, 226, 0, 0, 414, 414, 6, 0, 17, 2, 3, 4, 5, 10, 11, 12, 19, 20, 0, 49, 0, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 0, 3037, 15, 65, 3720, 3744, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 15, 5, 5, 8, 8, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Switzerland
- { 119, 66, 253, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 0, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3752, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 18, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Vatican City
- { 120, 53, 120, 183, 183, 183, 183, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 821, 324, 1, 9758, 9758, 9785, 9785, 9785, 9785, 283, 290, 587, 590, 22, 145, 3052, 2, 9, 3770, 3770, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 10, 10, 4, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 3, 4, 6, 3, 2, {74,80,89}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Japanese/Japanese/Japan
- { 121, 66, 111, 0, 0, 593, 603, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 0, 0, 9798, 9798, 9838, 9838, 9866, 9866, 285, 292, 607, 5, 22, 186, 3007, 15, 0, 3773, 3777, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 40, 40, 28, 28, 13, 13, 4, 5, 4, 17, 23, 2, 16, 5, 0, 4, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Javanese/Latin/Indonesia
- { 122, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 0, 0, 9879, 9879, 9922, 9922, 83, 83, 0, 0, 0, 5, 22, 124, 3055, 15, 0, 3786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 7, 5, 0, 4, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Jju/Latin/Nigeria
- { 123, 66, 206, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 0, 0, 9949, 9949, 9998, 9998,10025,10025, 0, 0, 0, 5, 22, 127, 3062, 4, 0, 3790, 3795, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 16, 5, 0, 5, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Jola-Fonyi/Latin/Senegal
- { 124, 66, 43, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1131, 186, 0, 0,10038,10038,10110,10110,10137,10137, 82, 203, 0, 5, 22, 243, 3078, 4, 20, 3802, 3814, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 10, 5, 72, 72, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 18, 5, 7, 12, 10, {67,86,69}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kabuverdianu/Latin/Cape Verde
- { 125, 66, 4, 0, 0, 612, 620, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 22,10150,10183,10233,10260,10289,10302, 289, 297, 611, 618, 22, 209, 3096, 0, 0, 3824, 3833, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 33, 50, 27, 29, 13, 13, 7, 9, 7, 21, 23, 2, 14, 4, 0, 9, 8, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Kabyle/Latin/Algeria
- { 126, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 86, 1158, 0, 0,10315,10315,10315,10315,10368,10368, 0, 0, 0, 5, 22, 11, 3110, 15, 0, 3841, 3845, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 53, 53, 53, 53, 20, 20, 2, 2, 4, 17, 23, 4, 9, 5, 0, 4, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kako/Latin/Cameroon
- { 127, 66, 95, 0, 0, 627, 627, 6, 1, 0, 2, 3, 48, 5, 63, 12, 11, 20, 19, 86, 103, 166, 166,10388,10388,10485,10485,10512,10512, 0, 0, 0, 5, 22, 160, 3119, 2, 92, 3852, 3863, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 97, 97, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 5, 11, 16, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Kalaallisut/Latin/Greenland
- { 128, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,10525,10525,10577,10577,10604,10604, 296, 306, 0, 5, 22, 176, 3138, 2, 9, 3879, 3887, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 52, 52, 27, 27, 13, 13, 6, 10, 4, 17, 23, 3, 19, 4, 6, 8, 12, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kalenjin/Latin/Kenya
- { 129, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,10617,10617,10690,10690,10717,10717, 302, 316, 0, 5, 22, 176, 3157, 2, 9, 3899, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 73, 73, 27, 27, 13, 13, 9, 7, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kamba/Latin/Kenya
- { 130, 56, 110, 0, 0, 638, 650, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 129, 303, 316,10730,10730,10783,10783,10815,10815, 311, 323, 639, 647, 22, 120, 3173, 2, 9, 3906, 3911, 6, 6, 12, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 8, 53, 53, 32, 32, 19, 19, 9, 7, 8, 35, 23, 1, 13, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kannada/Kannada/India
- { 132, 4, 110, 661, 661, 667, 677, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 549, 567, 42, 54,10834,10834,10885,10885,10934,10934, 320, 330, 0, 5, 22, 120, 3186, 2, 0, 3915, 3920, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 12, 7, 51, 51, 49, 49, 13, 13, 6, 6, 4, 17, 23, 1, 16, 4, 0, 5, 9, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Arabic/India
- { 132, 29, 110, 0, 0, 686, 695, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 96, 96,10947,10996,10947,11045,11092,11092, 326, 336, 0, 5, 22, 120, 3202, 15, 0, 3929, 3934, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 49, 49, 49, 47, 13, 13, 5, 5, 4, 17, 23, 1, 11, 5, 0, 5, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Devanagari/India
- { 133, 27, 123, 0, 0, 0, 703, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1168, 49, 0, 0,11105,11105,11160,11160,11180,11180, 0, 0, 196, 682, 699, 244, 3213, 4, 0, 3944, 3954, 6, 6, 6, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 10, 5, 55, 55, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kazakh/Cyrillic/Kazakhstan
- { 134, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 11, 0, 15, 0, 3963, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 0, 5, 0, 6, 0, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kenyang/Latin/Cameroon
- { 135, 60, 39, 0, 0, 713, 722, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 42, 54,11193,11238,11284,11284,11323,11323, 0, 0, 722, 5, 22, 245, 3230, 0, 45, 3969, 3974, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 45, 46, 39, 39, 13, 13, 2, 2, 2, 17, 23, 1, 11, 4, 6, 5, 7, {75,72,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Khmer/Khmer/Cambodia
- { 136, 66, 99, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 246, 0, 15, 0, 3981, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 0, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kiche/Latin/Guatemala
- { 137, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,11336,11336,11398,11398,11425,11425, 331, 341, 0, 5, 22, 176, 3241, 2, 9, 3988, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 27, 27, 13, 13, 6, 8, 4, 17, 23, 3, 16, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kikuyu/Latin/Kenya
- { 138, 66, 194, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 16, 17, 163, 103, 0, 0,11438,11438,11521,11521, 83, 83, 0, 0, 0, 5, 22, 198, 0, 15, 0, 3994, 4005, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 83, 83, 34, 34, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 11, 8, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kinyarwanda/Latin/Rwanda
- { 141, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 42, 54,11555,11555,11555,11555,11605,11623, 337, 349, 724, 5, 22, 120, 2964, 2, 9, 4013, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 50, 50, 50, 50, 18, 19, 4, 4, 4, 17, 23, 1, 12, 4, 6, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Konkani/Devanagari/India
- { 142, 63, 218, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 334, 96,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 247, 3257, 2, 9, 4019, 4022, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 13, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 6, 4, 6, 3, 4, {75,82,87}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Korean/Korean/South Korea
- { 142, 63, 50, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 132, 0,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 248, 3263, 2, 9, 4019, 4026, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 10, 5, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 3, 6, 4, 6, 3, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Korean/Korean/China
- { 142, 63, 174, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 334, 96,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 247, 3269, 2, 9, 4019, 4028, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 13, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 16, 4, 6, 3, 11, {75,80,87}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Korean/Korean/North Korea
- { 144, 66, 145, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,11682,11682,11735,11735,11762,11762, 343, 355, 0, 5, 22, 127, 3285, 0, 0, 4039, 4054, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 53, 53, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 15, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyraboro Senni/Latin/Mali
- { 145, 66, 145, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,11775,11775,11827,11827,11762,11762, 343, 355, 0, 5, 22, 127, 3285, 0, 0, 4059, 4054, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 52, 52, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 11, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyra Chiini/Latin/Mali
- { 146, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 22, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4070, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 0, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kpelle/Latin/Liberia
- { 146, 66, 102, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 215, 0, 15, 0, 4070, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 6, 0, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kpelle/Latin/Guinea
- { 148, 66, 239, 0, 0, 738, 738, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1217, 49, 0, 0,11854,11854,11896,11896,11923,11923, 349, 361, 0, 5, 22, 126, 3301, 4, 20, 4076, 4092, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 10, 5, 42, 42, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 12, 5, 7, 16, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kurdish/Latin/Turkey
- { 149, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 11, 12, 113, 129, 0, 0,11936,11936,12024,12024,12053,12053, 351, 363, 0, 5, 22, 11, 3313, 4, 0, 4099, 4105, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 88, 88, 29, 29, 13, 13, 4, 4, 4, 17, 23, 4, 13, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kwasio/Latin/Cameroon
- { 150, 27, 128, 0, 0, 745, 745, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1244, 129, 0, 0,12066,12066,12122,12122,12159,12159, 355, 367, 196, 731, 22, 251, 3326, 4, 0, 4112, 4120, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 10, 5, 56, 56, 37, 37, 13, 13, 5, 14, 4, 18, 23, 3, 15, 5, 0, 8, 10, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kyrgyz/Cyrillic/Kyrgyzstan
- { 151, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22,12172,12172,12172,12172, 83,12258, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4130, 4142, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 86, 86, 86, 86, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 22, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Lakota/Latin/United States
- { 152, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 0, 186, 0, 0,12271,12271,12333,12333,12368,12368, 360, 381, 0, 5, 22, 121, 3341, 15, 0, 4164, 4172, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 35, 35, 13, 13, 3, 3, 4, 17, 23, 3, 22, 5, 0, 8, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Langi/Latin/Tanzania
- { 153, 65, 129, 0, 0, 0, 755, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1267, 129, 347, 1,12381,12381,12437,12437,12472,12472, 363, 384, 0, 5, 22, 254, 3363, 2, 65, 4181, 4181, 6, 6, 6, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 24, 4, 56, 56, 35, 35, 16, 16, 8, 8, 4, 17, 23, 1, 7, 4, 5, 3, 3, {76,65,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Lao/Lao/Laos
- { 154, 66, 253, 0, 0, 406, 406, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1286, 1309, 0, 0,12488,12488,12572,12572, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 0, 4184, 4190, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 10, 5, 84, 84, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 6, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Latin/Latin/Vatican City
- { 155, 66, 131, 0, 0, 267, 267, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1317, 49, 0, 0,12599,12670,12741,12791,12841,12841, 371, 392, 749, 5, 22, 22, 3370, 4, 0, 4206, 4214, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 8, 10, 5, 71, 71, 50, 50, 13, 13, 14, 11, 5, 17, 23, 1, 4, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Latvian/Latin/Latvia
- { 158, 66, 57, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3374, 4, 0, 4221, 4228, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 30, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo - Kinshasa
- { 158, 66, 7, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 255, 3390, 4, 0, 4221, 4258, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Angola
- { 158, 66, 46, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3406, 4, 0, 4221, 4264, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 26, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Central African Republic
- { 158, 66, 56, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3406, 4, 0, 4221, 4290, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo - Brazzaville
- { 160, 66, 137, 0, 0, 773, 773, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 13, 14, 1343, 103, 0, 0,12993,12993,13081,13081,13101,13101, 393, 409, 754, 5, 22, 22, 3422, 4, 0, 4295, 4303, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 27, 10, 10, 5, 88, 88, 20, 20, 13, 13, 9, 6, 6, 17, 23, 1, 5, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lithuanian/Latin/Lithuania
- { 161, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 4310, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lojban/Latin/world
- { 162, 66, 91, 0, 0, 781, 781, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 180, 1, 1,13114,13114,13166,13166,13193,13193, 402, 415, 0, 5, 22, 22, 405, 4, 0, 4321, 4335, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 9, 4, 52, 52, 27, 27, 13, 13, 9, 10, 4, 17, 23, 1, 4, 5, 0, 14, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lower Sorbian/Latin/Germany
- { 163, 66, 91, 0, 0, 267, 267, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 1370, 50, 371, 390,13206,13206,13270,13270, 4510, 4510, 0, 0, 0, 5, 22, 22, 83, 4, 0, 4341, 4355, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 19, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Germany
- { 163, 66, 165, 0, 0, 267, 267, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 1370, 50, 371, 390,13206,13206,13270,13270, 4510, 4510, 0, 0, 0, 5, 22, 22, 83, 4, 0, 4341, 4366, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 19, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Netherlands
- { 164, 66, 57, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,13297,13297,13346,13346,13373,13373, 411, 425, 0, 5, 22, 11, 3427, 0, 0, 4378, 4386, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 49, 49, 27, 27, 13, 13, 5, 6, 4, 17, 23, 2, 17, 4, 0, 8, 16, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luba-Katanga/Latin/Congo - Kinshasa
- { 165, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 4402, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 15, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Lule Sami/Latin/Sweden
- { 165, 66, 175, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 4402, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 15, 0, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Lule Sami/Latin/Norway
- { 166, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,13386,13386,13454,13454,13481,13481, 416, 431, 0, 5, 22, 176, 3444, 0, 0, 4417, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 68, 68, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 16, 4, 0, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luo/Latin/Kenya
- { 167, 66, 138, 0, 0, 788, 788, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 0, 0,13494,13494,13558,13585, 4510, 4510, 418, 433, 461, 5, 22, 22, 83, 4, 0, 4423, 4423, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 64, 64, 27, 34, 13, 13, 5, 8, 5, 17, 23, 1, 4, 5, 0, 14, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luxembourgish/Latin/Luxembourg
- { 168, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 13, 14, 18, 16, 0, 186, 0, 0,13619,13619,13693,13693, 83, 83, 168, 168, 0, 5, 22, 176, 3460, 2, 97, 4437, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 74, 74, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luyia/Latin/Kenya
- { 169, 27, 140, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 0, 180, 0, 0,13713,13713,13766,13766, 3069, 3069, 423, 441, 760, 5, 22, 257, 3476, 4, 0, 4444, 4454, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 53, 53, 34, 34, 13, 13, 7, 5, 5, 17, 23, 4, 16, 5, 0, 10, 18, {77,75,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Macedonian/Cyrillic/Macedonia
- { 170, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 2, 0, 4472, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Machame/Latin/Tanzania
- { 171, 29, 110, 0, 0, 513, 522, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 42, 54,13888,13888, 8574, 8574, 8605, 8605, 88, 83, 0, 5, 22, 120, 2964, 15, 0, 4481, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 63, 63, 31, 31, 18, 18, 3, 4, 4, 17, 23, 1, 12, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Maithili/Devanagari/India
- { 172, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,13951,13951,14009,14009,14036,14036, 435, 455, 0, 5, 22, 261, 0, 15, 0, 4487, 4492, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 58, 58, 27, 27, 13, 13, 8, 10, 4, 17, 23, 3, 0, 5, 0, 5, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Makhuwa-Meetto/Latin/Mozambique
- { 173, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,14049,14049,14181,14181,14208,14208, 443, 465, 0, 5, 22, 121, 3492, 2, 9, 4502, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5,132,132, 27, 27, 13, 13, 4, 5, 4, 17, 23, 3, 20, 4, 6, 10, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Makonde/Latin/Tanzania
- { 174, 66, 141, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 103, 0, 0,14221,14221,14280,14280,14313,14313, 0, 0, 0, 5, 22, 188, 1515, 2, 0, 4512, 4520, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 59, 59, 33, 33, 13, 13, 2, 2, 4, 17, 23, 2, 6, 4, 0, 8, 12, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Malagasy/Latin/Madagascar
- { 175, 74, 110, 0, 0, 798, 811, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1393, 129, 42, 54,14326,14402,14477,14477,14517,14538, 0, 0, 765, 771, 22, 120, 3512, 2, 9, 4532, 4538, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 76, 75, 40, 40, 21, 20, 2, 2, 6, 27, 23, 1, 11, 4, 6, 6, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Malayalam/Malayalam/India
- { 176, 66, 143, 0, 0, 584, 584, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 79, 10, 22,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 192, 3523, 2, 9, 4544, 1875, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 12, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 6, 6, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Malaysia
- { 176, 4, 35, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 15, 14, 17, 16, 91, 79, 42, 54,14640,14640,14640,14640, 83, 83, 0, 0, 0, 5, 22, 10, 3539, 2, 9, 4550, 4560, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 7, 12, 7, 34, 34, 34, 34, 13, 13, 2, 2, 4, 17, 23, 1, 10, 4, 6, 10, 5, {66,78,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Arabic/Brunei
- { 176, 4, 143, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 196, 79, 42, 54,14640,14640,14640,14640, 83, 83, 0, 0, 0, 5, 22, 192, 3549, 2, 9, 4550, 4565, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 12, 7, 34, 34, 34, 34, 13, 13, 2, 2, 4, 17, 23, 2, 13, 4, 6, 10, 6, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Arabic/Malaysia
- { 176, 66, 35, 0, 0, 584, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 91, 79, 10, 22,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 10, 3562, 2, 9, 4544, 4571, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 7, 12, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 12, 4, 6, 6, 6, {66,78,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Brunei
- { 176, 66, 111, 0, 0, 584, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 166, 166,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 186, 3007, 2, 0, 4544, 1776, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 0, 6, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Indonesia
- { 176, 66, 210, 0, 0, 584, 584, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 79, 10, 22,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 10, 3574, 2, 9, 4544, 4577, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 12, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 15, 4, 6, 6, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Singapore
- { 177, 66, 146, 0, 0, 823, 831, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1411, 186, 0, 0,14674,14674,14736,14736,14763,14783, 0, 0, 0, 5, 22, 22, 3589, 2, 0, 4586, 1891, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 62, 62, 27, 27, 20, 19, 2, 2, 4, 17, 23, 1, 4, 4, 0, 5, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Maltese/Latin/Malta
- { 179, 9, 110, 0, 0, 838, 838, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 1434, 129, 42, 54,14802,14802,14802,14802,14860,14885, 449, 473, 0, 5, 22, 120, 3593, 15, 0, 4591, 4599, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 58, 58, 58, 58, 25, 29, 4, 5, 4, 17, 23, 1, 14, 5, 0, 8, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Bangla/India
- { 179, 78, 110, 0, 0, 0, 0, 6, 0, 1, 2, 75, 4, 5, 10, 14, 15, 16, 17, 265, 283, 400, 412, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 120, 0, 15, 0, 4607, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 8, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Meitei Mayek/India
- { 180, 66, 115, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 86, 78, 0, 0,14914,14914,14970,14970, 83, 83, 168, 168, 0, 5, 22, 94, 0, 2, 0, 4614, 4619, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 56, 56, 29, 29, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 5, 12, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Manx/Latin/Isle of Man
- { 181, 66, 167, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 10, 22,14999,14999,15046,15046,15073,15073, 0, 0, 0, 5, 22, 10, 3607, 15, 0, 4631, 4636, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 47, 47, 27, 27, 15, 15, 2, 2, 4, 17, 23, 1, 15, 5, 0, 5, 8, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Maori/Latin/New Zealand
- { 182, 66, 49, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4644, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 10, 0, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mapuche/Latin/Chile
- { 183, 29, 110, 0, 0, 849, 849, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 265, 129, 42, 54,15088,15088,15140,15140, 8605, 8605, 0, 0, 562, 5, 22, 120, 2964, 2, 9, 4654, 664, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Marathi/Devanagari/India
- { 185, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,15171,15171,13861,13861,14208,14208, 453, 478, 0, 5, 22, 176, 3622, 2, 9, 1275, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 18, 4, 6, 3, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Masai/Latin/Kenya
- { 185, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,15171,15171,13861,13861,14208,14208, 453, 478, 0, 5, 22, 121, 3640, 2, 9, 1275, 4659, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 3, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Masai/Latin/Tanzania
- { 186, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 798, 802, 22, 0, 3661, 15, 0, 4667, 4674, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 39, 23, 0, 10, 5, 0, 7, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Mazanderani/Arabic/Iran
- { 188, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,15228,15228,15278,15278,15305,15305, 462, 484, 0, 5, 22, 176, 991, 2, 9, 4679, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 50, 50, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Meru/Latin/Kenya
- { 189, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 103, 0, 0,15318,15318,15318,15318,15366,15366, 0, 0, 0, 5, 22, 11, 3671, 15, 0, 4685, 4690, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 48, 48, 48, 48, 20, 20, 2, 2, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Meta/Latin/Cameroon
- { 190, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 22, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 4697, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 11, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Mohawk/Latin/Canada
- { 191, 27, 156, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1452, 596, 73, 0,15386,15428,15470,15470,15470,15470, 464, 486, 196, 841, 22, 264, 3676, 15, 0, 4708, 4714, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 35, 10, 12, 5, 42, 42, 20, 20, 20, 20, 4, 4, 4, 17, 23, 1, 13, 5, 0, 6, 6, {77,78,84}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Mongolian/Cyrillic/Mongolia
- { 191, 83, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 248, 3689, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 0, 0, 0, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Mongolian/Mongolian/China
- { 191, 83, 156, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1487, 596, 73, 0,15490,15490,15532,15555,15578,15578, 468, 490, 0, 5, 22, 264, 3693, 2, 0, 4720, 4720, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 10, 12, 5, 42, 42, 23, 23, 23, 22, 4, 5, 4, 17, 23, 1, 8, 4, 0, 6, 6, {77,78,84}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Mongolian/Mongolian/Mongolia
- { 192, 66, 150, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,15601,15601,15648,15648,15674,15674, 0, 0, 0, 5, 22, 196, 3701, 15, 0, 4726, 4740, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 47, 47, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 14, 5, 0, 14, 5, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Morisyen/Latin/Mauritius
- { 193, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 0, 0,15687,15687,15760,15760,15787,15787, 472, 495, 0, 5, 22, 11, 3715, 2, 9, 4745, 4751, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 73, 73, 27, 27, 13, 13, 5, 5, 4, 17, 23, 4, 10, 4, 6, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mundang/Latin/Cameroon
- { 194, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 22,15800,15800,15800,15800, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4758, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7,106,106,106,106, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Muscogee/Latin/United States
- { 195, 66, 162, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22,15906,15906,15997,15997,16019,16019, 477, 500, 0, 5, 22, 10, 3725, 2, 0, 4765, 4778, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 91, 91, 22, 22, 13, 13, 7, 5, 4, 17, 23, 1, 15, 4, 0, 13, 8, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nama/Latin/Namibia
- { 197, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 179, 0, 15, 0, 4786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 11, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Navajo/Latin/United States
- { 199, 29, 164, 858, 0, 863, 863, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 344, 0, 0,16032,16032,16085,16085,16117,16117, 484, 505, 562, 858, 22, 265, 3740, 15, 0, 4797, 4797, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 4, 14, 5, 0, 6, 5, {78,80,82}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Nepali/Devanagari/Nepal
- { 199, 29, 110, 858, 0, 863, 863, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 344, 42, 54,16032,16032,16085,16085,16117,16117, 484, 505, 562, 858, 22, 120, 3754, 15, 0, 4797, 664, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 1, 14, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Nepali/Devanagari/India
- { 201, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1523, 78, 0, 0,16134,16134,16134,16134, 83, 83, 493, 512, 0, 5, 22, 11, 3768, 15, 0, 4803, 4819, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 8, 10, 5,110,110,110,110, 13, 13, 9, 8, 4, 17, 23, 4, 9, 5, 0, 16, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngiemboon/Latin/Cameroon
- { 202, 66, 40, 870, 870, 881, 897, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 137, 103, 0, 0,16244,16244,16244,16244,16303,16303, 502, 520, 0, 5, 22, 11, 3777, 15, 0, 4826, 4831, 11, 11, 16, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 59, 59, 59, 59, 24, 24, 8, 13, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngomba/Latin/Cameroon
- { 203, 66, 169, 0, 0, 906, 915, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,16327,16327,16378,16378, 83, 83, 510, 533, 877, 5, 22, 124, 3782, 2, 0, 4838, 4852, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 51, 51, 32, 32, 13, 13, 9, 8, 8, 17, 23, 1, 14, 4, 0, 14, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nigerian Pidgin/Latin/Nigeria
- { 204, 90, 102, 0, 0, 0, 0, 6, 0, 76, 2, 77, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0,16410,16410,16470,16502,16536,16536, 519, 541, 0, 5, 22, 269, 3796, 15, 0, 4860, 4863, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 60, 60, 32, 34, 13, 13, 1, 1, 4, 17, 23, 1, 22, 5, 0, 3, 6, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Nko/Nko/Guinea
- { 205, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 4869, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Northern Luri/Arabic/Iran
- { 205, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 42, 54, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 43, 0, 15, 0, 4869, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 12, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 5, 0, 11, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Northern Luri/Arabic/Iraq
- { 206, 66, 175, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 163, 103, 0, 0,16549,16549,16623,16623,16655,16655, 520, 542, 0, 5, 22, 160, 3818, 4, 0, 4880, 4895, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Norway
- { 206, 66, 83, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 113, 49, 0, 0,16668,16668,16737,16737,16757,16757, 531, 185, 0, 5, 22, 22, 405, 4, 0, 4880, 4900, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 69, 69, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Finland
- { 206, 66, 225, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 163, 103, 0, 0,16549,16549,16623,16623,16655,16655, 520, 542, 0, 5, 22, 160, 3832, 4, 0, 4880, 4906, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Sweden
- { 207, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,16770,16770,16833,16833,16859,16859, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 4928, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 63, 63, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 16, 12, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Northern Sotho/Latin/South Africa
- { 208, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,16872,16872,16921,16921,16948,16948, 0, 0, 0, 5, 22, 179, 3846, 2, 9, 4940, 2434, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 10, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // North Ndebele/Latin/Zimbabwe
- { 209, 66, 175, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 0, 0, 4788, 4788,16961,16961, 4874, 4874, 168, 168, 0, 5, 22, 160, 3863, 15, 58, 4950, 4962, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Norway
- { 209, 66, 224, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 0, 0, 4788, 4788,16961,16961, 4874, 4874, 168, 168, 0, 5, 22, 160, 3863, 15, 58, 4950, 4967, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 21, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Svalbard and Jan Mayen
- { 210, 66, 175, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 420, 0,16995,16995,17045,17072, 4874, 4874, 533, 555, 0, 5, 22, 160, 3863, 4, 0, 4988, 5001, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 16, 5, 50, 50, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 0, 13, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Nynorsk/Latin/Norway
- { 211, 66, 219, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 187, 436, 22,17099,17099,17177,17177,17214,17214, 537, 559, 0, 5, 22, 94, 0, 2, 9, 5006, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 12, 7, 78, 78, 37, 37, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 9, 0, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nuer/Latin/South Sudan
- { 212, 66, 142, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 22,17227,17227,17293,17293, 83, 83, 0, 0, 0, 5, 22, 0, 1521, 15, 0, 5015, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 66, 66, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 15, 5, 0, 6, 0, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nyanja/Latin/Malawi
- { 213, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 4053, 4053, 4126, 4126, 4153, 4153, 0, 0, 0, 5, 22, 147, 805, 2, 0, 5021, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 10, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Nyankole/Latin/Uganda
- { 214, 66, 84, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 1555, 79, 0, 448,17320,17320,17320,17320,17376,17376, 0, 0, 376, 232, 249, 22, 405, 0, 45, 5031, 807, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 7, 10, 6, 56, 56, 56, 56, 20, 20, 2, 2, 6, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Occitan/Latin/France
- { 214, 66, 220, 0, 0, 414, 414, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 79, 74, 1,17396,17396,17453,17453,17480,17480, 0, 0, 376, 232, 249, 22, 405, 0, 0, 5031, 5038, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 11, 4, 57, 57, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 4, 4, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Occitan/Latin/Spain
- { 215, 91, 110, 0, 0, 923, 931, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 42, 54,17493,17493,17546,17546,17578,17578, 0, 0, 885, 5, 22, 120, 3876, 2, 9, 5045, 5050, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 53, 53, 32, 32, 17, 17, 2, 2, 5, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Odia/Odia/India
- { 220, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 22,17595,17595,17649,17649, 83, 83, 539, 561, 0, 5, 22, 1, 3888, 2, 0, 5054, 5060, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 17, 4, 0, 6, 10, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Ethiopia
- { 220, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 0, 0,17595,17595,17649,17649,17676,17676, 539, 561, 0, 5, 22, 176, 0, 2, 0, 5054, 5070, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 6, 8, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Kenya
- { 221, 101, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 42, 54,17689,17689,17689,17689, 83,17869, 0, 0, 0, 5, 22, 10, 0, 15, 0, 5078, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7,180,180,180,180, 13, 20, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Osage/Osage/United States
- { 222, 27, 90, 0, 0, 938, 938, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1576, 49, 0, 0,17889,17949,18009,18036,18063,18063, 541, 563, 0, 5, 22, 0, 3905, 15, 0, 5090, 5094, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 10, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 11, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Georgia
- { 222, 27, 193, 0, 0, 938, 938, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1576, 49, 0, 0,17889,17949,18009,18036,18063,18063, 541, 563, 0, 5, 22, 133, 3908, 15, 0, 5090, 5105, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 10, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Russia
- { 226, 66, 62, 0, 0, 143, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 0, 0,18076,18076,18076,18076,18138,18138, 0, 0, 0, 5, 22, 0, 3911, 15, 0, 5111, 5121, 6, 6, 7, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 62, 62, 20, 20, 2, 2, 4, 17, 23, 0, 6, 5, 0, 10, 6, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Papiamento/Latin/Curacao
- { 226, 66, 13, 0, 0, 143, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 0, 0,18076,18076,18076,18076,18138,18138, 0, 0, 0, 5, 22, 0, 3917, 15, 0, 5111, 1227, 6, 6, 7, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 62, 62, 20, 20, 2, 2, 4, 17, 23, 0, 15, 5, 0, 10, 5, {65,87,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Papiamento/Latin/Aruba
- { 227, 4, 1, 661, 661, 947, 956, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1599, 505, 74, 1,18158,18158,18158,18158, 83, 83, 556, 578, 890, 5, 22, 270, 3932, 2, 9, 5127, 5131, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 11, 4, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 1, 6, 4, 6, 4, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Pashto/Arabic/Afghanistan
- { 227, 4, 178, 661, 661, 947, 956, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1599, 505, 42, 54,18158,18158,18158,18158, 83, 83, 556, 578, 890, 5, 22, 196, 3938, 2, 9, 5127, 5140, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 12, 7, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 2, 15, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Pashto/Arabic/Pakistan
- { 228, 4, 112, 964, 964, 971, 979, 67, 21, 22, 23, 40, 82, 37, 44, 11, 12, 19, 20, 113, 505, 74, 1,18196,18196,18196,18196,18244,18244, 560, 582, 798, 5, 22, 271, 3953, 103, 109, 5147, 4674, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 11, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 4, 10, 6, 8, 5, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Persian/Arabic/Iran
- { 228, 4, 1, 964, 964, 971, 979, 67, 21, 22, 23, 40, 82, 37, 44, 11, 12, 19, 20, 113, 505, 74, 1,18196,18196,18196,18196,18244,18244, 560, 582, 798, 5, 22, 270, 3963, 15, 109, 5152, 5131, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 11, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 1, 16, 5, 8, 3, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Persian/Arabic/Afghanistan
- { 230, 66, 187, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 50, 0, 0,18257,18257,18315,18315,18348,18361, 0, 0, 311, 5, 22, 275, 3979, 4, 20, 5155, 5161, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 9, 10, 5, 58, 58, 33, 33, 13, 13, 2, 2, 5, 17, 23, 2, 12, 5, 7, 6, 6, {80,76,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Polish/Latin/Poland
- { 231, 66, 32, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 186, 0, 0,18374,18374,18452,18452,18486,18486, 0, 0, 0, 5, 22, 9, 3991, 15, 0, 5167, 5176, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 10, 5, 78, 78, 34, 34, 13, 13, 2, 2, 5, 17, 23, 2, 15, 5, 0, 9, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Brazil
- { 231, 66, 7, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 255, 4006, 4, 20, 5167, 5182, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 15, 5, 7, 9, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Angola
- { 231, 66, 43, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 243, 4021, 4, 20, 5167, 5188, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 20, 5, 7, 9, 10, {67,86,69}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Cape Verde
- { 231, 66, 73, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 11, 4041, 4, 20, 5167, 5198, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 17, 5, 7, 9, 16, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Equatorial Guinea
- { 231, 66, 101, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 127, 4058, 4, 20, 5167, 5214, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 5, 18, 5, 7, 9, 12, {88,79,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Guinea-Bissau
- { 231, 66, 138, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 22, 405, 4, 20, 5167, 5226, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 9, 10, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Luxembourg
- { 231, 66, 139, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 22,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 151, 4076, 4, 20, 5167, 5236, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 15, 5, 7, 9, 19, {77,79,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Macao
- { 231, 66, 160, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 261, 4091, 4, 20, 5167, 5255, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 19, 5, 7, 9, 10, {77,90,78}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Mozambique
- { 231, 66, 188, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 22, 405, 4, 20, 5265, 5282, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 17, 8, {69,85,82}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Portugal
- { 231, 66, 204, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 277, 4110, 4, 20, 5167, 5290, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 28, 5, 7, 9, 19, {83,84,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Sao Tome and Principe
- { 231, 66, 226, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 0, 4138, 4, 20, 5167, 5309, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 0, 12, 5, 7, 9, 5, {67,72,70}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Switzerland
- { 231, 66, 232, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 0, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 179, 4150, 4, 20, 5167, 5314, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 24, 5, 7, 9, 11, {85,83,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Timor-Leste
- { 232, 66, 187, 0, 0, 986, 986, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 13, 14, 1619, 49, 0, 0,18547,18547,18615,18615,18642,18642, 577, 598, 0, 5, 22, 275, 0, 4, 0, 5325, 5334, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 68, 68, 27, 27, 13, 13, 10, 14, 4, 17, 23, 2, 0, 5, 0, 9, 4, {80,76,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Prussian/Latin/Poland
- { 233, 41, 110, 0, 0, 994, 994, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 42, 54,18655,18655,18711,18711,18746,18746, 587, 612, 895, 5, 22, 120, 4174, 15, 0, 5338, 5344, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 35, 35, 22, 22, 6, 6, 4, 17, 23, 1, 11, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Punjabi/Gurmukhi/India
- { 233, 4, 178, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 786, 186, 42, 54,18768,18768,18768,18768, 83, 83, 0, 0, 0, 5, 22, 78, 4185, 15, 0, 5348, 5140, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 10, 12, 7, 36, 36, 36, 36, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Punjabi/Arabic/Pakistan
- { 234, 66, 184, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 10, 22,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 279, 4191, 15, 0, 5354, 5362, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 11, 5, 0, 8, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Quechua/Latin/Peru
- { 234, 66, 28, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 10, 22,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 281, 4202, 15, 0, 5354, 5366, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 9, 5, 0, 8, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Bolivia
- { 234, 66, 70, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 10, 22,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 10, 4211, 15, 0, 5354, 5373, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 15, 5, 0, 8, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Ecuador
- { 235, 66, 192, 0, 0, 1003, 1003, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 49, 0, 0,18896,18896,18943,18943, 6778, 6778, 168, 168, 899, 5, 22, 283, 4226, 4, 20, 5380, 5386, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 47, 47, 33, 33, 13, 13, 4, 4, 4, 17, 23, 3, 12, 5, 7, 6, 7, {82,79,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Romania
- { 235, 66, 154, 0, 0, 1003, 1003, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 49, 0, 0,18896,18896,18976,18976,19003,19003, 168, 168, 899, 5, 22, 18, 4238, 4, 20, 5380, 5393, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 47, 47, 27, 27, 15, 15, 4, 4, 4, 17, 23, 1, 15, 5, 7, 6, 17, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Moldova
- { 236, 66, 226, 0, 0, 414, 414, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 1646, 394, 0, 0,19018,19018,19073,19073,19095,19095, 0, 0, 0, 5, 22, 0, 4253, 4, 0, 5410, 5419, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 10, 5, 55, 55, 22, 22, 13, 13, 2, 2, 5, 17, 23, 0, 13, 5, 0, 9, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Romansh/Latin/Switzerland
- { 237, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,19108,19108,19172,19172,14208,14208, 593, 618, 0, 5, 22, 121, 4266, 2, 0, 5425, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 64, 64, 28, 28, 13, 13, 8, 7, 4, 17, 23, 3, 18, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rombo/Latin/Tanzania
- { 238, 66, 38, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 15, 15, 17, 17, 113, 129, 0, 0,19200,19200,19288,19288, 83, 83, 601, 625, 0, 5, 22, 182, 4284, 0, 0, 5434, 5442, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 88, 88, 33, 33, 13, 13, 5, 5, 4, 17, 23, 3, 20, 4, 0, 8, 8, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Rundi/Latin/Burundi
- { 239, 27, 193, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 0, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 133, 4304, 4, 0, 5450, 5457, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 16, 5, 0, 7, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Russia
- { 239, 27, 22, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 0, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 1, 4320, 4, 0, 5450, 618, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {66,89,78}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Belarus
- { 239, 27, 123, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 0, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 244, 4337, 4, 0, 5450, 5463, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 15, 5, 0, 7, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kazakhstan
- { 239, 27, 128, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 0, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 251, 4352, 4, 0, 5450, 5472, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 3, 14, 5, 0, 7, 8, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kyrgyzstan
- { 239, 27, 154, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 0, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 18, 4366, 4, 0, 5450, 5480, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 14, 5, 0, 7, 7, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Moldova
- { 239, 27, 244, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 0, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 286, 4380, 4, 0, 5450, 5487, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 7, 7, {85,65,72}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Russian/Cyrillic/Ukraine
- { 240, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 0, 0, 5494, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rwa/Latin/Tanzania
- { 241, 66, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 10, 22,19415,19415,19470,19470,19497,19497, 0, 0, 0, 5, 22, 6, 0, 2, 0, 5500, 34, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 12, 7, 55, 55, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 4, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Saho/Latin/Eritrea
- { 242, 27, 193, 0, 0, 1011, 1011, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1669, 344, 0, 0,19510,19510,19580,19580,19600,19600, 606, 630, 903, 908, 22, 133, 4397, 4, 0, 5504, 5513, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 6, 10, 5, 70, 70, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 20, 5, 0, 9, 9, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sakha/Cyrillic/Russia
- { 243, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,19613,19613,19717,19717,19744,19744, 608, 632, 0, 5, 22, 176, 4417, 2, 9, 5522, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5,104,104, 27, 27, 13, 13, 7, 5, 4, 17, 23, 3, 18, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Samburu/Latin/Kenya
- { 245, 66, 46, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 0, 0,19757,19757,19822,19822,19849,19849, 615, 637, 0, 5, 22, 11, 4435, 2, 65, 5530, 5535, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 18, 4, 5, 5, 22, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Sango/Latin/Central African Republic
- { 246, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,19862,19862,19921,19921,19948,19948, 617, 639, 0, 5, 22, 121, 4453, 0, 0, 5557, 5566, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 27, 27, 13, 13, 9, 9, 4, 17, 23, 3, 18, 4, 0, 9, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Sangu/Latin/Tanzania
- { 247, 29, 110, 0, 0, 1022, 1032, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 0, 129, 42, 54,19961,19961, 8574, 8574, 8605, 8605, 484, 505, 0, 5, 22, 120, 4471, 15, 0, 5575, 5587, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 66, 66, 31, 31, 18, 18, 9, 7, 4, 17, 23, 1, 15, 5, 0, 12, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Sanskrit/Devanagari/India
- { 248, 93, 110, 0, 0, 0, 0, 6, 0, 1, 2, 84, 4, 5, 10, 14, 15, 16, 17, 0, 129, 42, 54,20027,20027,20068,20068,20093,20093, 626, 648, 0, 5, 22, 120, 4486, 15, 0, 5592, 5599, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 41, 41, 25, 25, 13, 13, 5, 5, 4, 17, 23, 1, 16, 5, 0, 7, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Ol Chiki/India
- { 248, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 0, 129, 42, 54, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 120, 0, 15, 0, 5605, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 8, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Devanagari/India
- { 249, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1699, 186, 0, 0,20106,20106,20160,20160,20187,20187, 0, 0, 0, 5, 22, 22, 4502, 4, 0, 5613, 813, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 10, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sardinian/Latin/Italy
- { 251, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 0, 0,20200,20200,20254,20254,20281,20281, 0, 0, 0, 5, 22, 261, 4506, 0, 0, 5618, 5255, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 21, 4, 0, 4, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sena/Latin/Mozambique
- { 252, 27, 207, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0,20294,20294,20345,20345, 2891, 2891, 0, 0, 925, 5, 22, 0, 4527, 4, 20, 5622, 5628, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 0, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Serbia
- { 252, 27, 29, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0, 2809, 2809, 2864, 2864, 2891, 2891, 104, 653, 925, 5, 22, 137, 4539, 4, 20, 5622, 713, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 55, 55, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Bosnia and Herzegovina
- { 252, 27, 126, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0,20294,20294,20345,20345, 2891, 2891, 0, 0, 925, 5, 22, 22, 4579, 4, 20, 5622, 5634, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Kosovo
- { 252, 27, 157, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0,20372,20372,20345,20345, 2891, 2891, 104, 653, 925, 5, 22, 22, 4579, 4, 20, 5622, 5640, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 54, 54, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Montenegro
- { 252, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0, 2699, 2699, 2756, 2756, 2783, 2783, 631, 661, 218, 5, 22, 135, 597, 4, 20, 5649, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 57, 57, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Bosnia and Herzegovina
- { 252, 66, 126, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0,20426,20426,20479,20479, 2783, 2783, 0, 0, 218, 5, 22, 22, 4583, 4, 20, 5649, 5655, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Kosovo
- { 252, 66, 157, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0,20506,20506,20479,20479, 2783, 2783, 631, 661, 218, 5, 22, 22, 4583, 4, 20, 5649, 5661, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 56, 56, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Montenegro
- { 252, 66, 207, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 0, 0,20426,20426,20479,20479, 2783, 2783, 0, 0, 218, 5, 22, 0, 4587, 4, 20, 5649, 5670, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 0, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Serbia
- { 253, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,20562,20562,20624,20624,20651,20651, 642, 669, 0, 5, 22, 121, 4599, 0, 0, 5676, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 27, 27, 13, 13, 5, 8, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Shambala/Latin/Tanzania
- { 254, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 163, 103, 0, 0,20664,20664,20718,20718,20745,20745, 0, 0, 0, 5, 22, 179, 4619, 2, 9, 5685, 2434, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 15, 4, 6, 8, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Shona/Latin/Zimbabwe
- { 255, 141, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0,20758,20758,20785,20785,20805,20805, 647, 677, 0, 5, 22, 150, 0, 15, 0, 5693, 5696, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 3, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sichuan Yi/Yi/China
- { 256, 66, 117, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0,20818,20818,20818,20818, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 5698, 3728, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 62, 62, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 9, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sicilian/Latin/Italy
- { 257, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 10, 22,20880,20880,20930,20930,20957,20957, 0, 0, 0, 5, 22, 1, 0, 2, 0, 5707, 5718, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 12, 7, 50, 50, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 4, 0, 11, 11, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sidamo/Latin/Ethiopia
- { 258, 66, 187, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 12, 11, 0, 49, 0, 0,20970,20970,21030,21030,13193,13193, 649, 679, 311, 5, 22, 275, 0, 15, 0, 5729, 5161, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 60, 60, 27, 27, 13, 13, 11, 11, 5, 17, 23, 2, 0, 5, 0, 7, 6, {80,76,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Silesian/Latin/Poland
- { 259, 4, 178, 0, 0, 1041, 1049, 67, 21, 22, 23, 25, 26, 28, 59, 14, 15, 16, 17, 549, 103, 42, 54,21057,21057,21057,21057,21091,21091, 660, 690, 932, 938, 22, 196, 4634, 4, 0, 5736, 5740, 6, 6, 8, 7, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 18, 10, 12, 7, 34, 34, 34, 34, 30, 30, 11, 11, 6, 25, 23, 2, 12, 5, 0, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sindhi/Arabic/Pakistan
- { 259, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 42, 54,21121,21148,21189,21211,21239,21239, 671, 701, 0, 5, 22, 120, 4646, 15, 0, 5747, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 27, 41, 22, 28, 20, 20, 8, 6, 4, 17, 23, 1, 17, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Sindhi/Devanagari/India
- { 260, 119, 221, 0, 0, 1056, 1065, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 166, 166,21259,21259,21320,21320,21358,21358, 679, 707, 963, 968, 22, 287, 4663, 2, 9, 5753, 5758, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 38, 38, 18, 18, 5, 4, 5, 42, 23, 3, 17, 4, 6, 5, 11, {76,75,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sinhala/Sinhala/Sri Lanka
- { 261, 66, 83, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 5769, 5779, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 10, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Skolt Sami/Latin/Finland
- { 262, 66, 212, 0, 0, 781, 282, 6, 1, 9, 2, 3, 4, 5, 6, 13, 14, 18, 16, 698, 423, 1, 1,21376,21376,21427,21427,21447,21447, 0, 0, 311, 5, 22, 22, 405, 4, 20, 5791, 5801, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 9, 4, 51, 51, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovak/Latin/Slovakia
- { 263, 66, 213, 0, 0, 1073, 1073, 6, 1, 0, 2, 3, 48, 5, 6, 13, 14, 18, 16, 404, 423, 0, 0,21460,21460,21511,21511,21545,21545, 172, 711, 50, 5, 22, 22, 4680, 4, 20, 5810, 5821, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 51, 51, 34, 34, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 11, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovenian/Latin/Slovenia
- { 264, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,21558,21558,21622,21622,21656,21656, 684, 715, 0, 5, 22, 147, 2829, 4, 0, 5830, 3330, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 64, 64, 34, 34, 13, 13, 6, 6, 4, 17, 23, 3, 19, 5, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Soga/Latin/Uganda
- { 265, 66, 215, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 22,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 93, 4684, 2, 9, 5837, 5845, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 1, 20, 4, 6, 8, 10, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Somali/Latin/Somalia
- { 265, 66, 67, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 22,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 3, 4704, 2, 9, 5837, 5855, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 13, 4, 6, 8, 7, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Somali/Latin/Djibouti
- { 265, 66, 77, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 22,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 1, 4717, 2, 9, 5837, 5862, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 2, 15, 4, 6, 8, 8, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Ethiopia
- { 265, 66, 124, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 0, 0,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 176, 4732, 2, 9, 5837, 1307, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 15, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Kenya
- { 266, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 25, 26, 28, 59, 11, 12, 19, 20, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 5870, 0, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Southern Kurdish/Arabic/Iran
- { 266, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 25, 26, 28, 59, 11, 12, 19, 20, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 5870, 0, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Southern Kurdish/Arabic/Iraq
- { 267, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 5881, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 19, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Southern Sami/Latin/Sweden
- { 267, 66, 175, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 5881, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 19, 0, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Southern Sami/Latin/Norway
- { 268, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,21760,21760,21820,21820, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 60, 60, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Southern Sotho/Latin/South Africa
- { 268, 66, 133, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 22,21760,21760,21820,21820, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 60, 60, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Southern Sotho/Latin/Lesotho
- { 269, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,21846,21846,21911,21911, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4940, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 65, 65, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 10, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // South Ndebele/Latin/South Africa
- { 270, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 74, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 17, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Spain
- { 270, 66, 11, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4747, 15, 58, 5900, 5917, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 14, 5, 7, 7, 9, {65,82,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Argentina
- { 270, 66, 24, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 0, 0,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4761, 2, 0, 5900, 5926, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 14, 4, 0, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Belize
- { 270, 66, 28, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 281, 4775, 2, 0, 5900, 5366, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 9, 4, 0, 7, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Bolivia
- { 270, 66, 32, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 0, 0,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 9, 4784, 2, 0, 5900, 5176, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 2, 14, 4, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Brazil
- { 270, 66, 42, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 74, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 5932, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Canary Islands
- { 270, 66, 47, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 74, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 5940, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 15, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Ceuta and Melilla
- { 270, 66, 49, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 394, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4798, 2, 65, 5900, 5955, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 12, 4, 5, 7, 5, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Chile
- { 270, 66, 54, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 10, 22,21937,21937,21989,21989, 9387,22016, 132, 128, 0, 5, 22, 10, 4810, 15, 0, 5900, 5960, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 15, 5, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Colombia
- { 270, 66, 59, 0, 0, 68, 68, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 290, 4825, 2, 0, 5900, 5968, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 19, 4, 0, 7, 10, {67,82,67}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Costa Rica
- { 270, 66, 61, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4844, 2, 0, 5900, 5978, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 11, 4, 0, 7, 4, {67,85,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Cuba
- { 270, 66, 69, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 291, 4855, 2, 9, 5900, 5982, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 6, 7, 20, {68,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Dominican Republic
- { 270, 66, 70, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 65, 5900, 5373, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 5, 7, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Ecuador
- { 270, 66, 72, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 0, 5900, 6002, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/El Salvador
- { 270, 66, 73, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 74, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 11, 4890, 2, 0, 5900, 6013, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 28, 4, 0, 7, 17, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Equatorial Guinea
- { 270, 66, 99, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 246, 4918, 2, 0, 5900, 6030, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 7, 4, 0, 7, 9, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Guatemala
- { 270, 66, 106, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1730, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 18, 4925, 2, 0, 5900, 6039, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 17, 4, 0, 7, 8, {72,78,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Honduras
- { 270, 66, 130, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 0, 0, 2, 0, 6047, 6070, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 0, 0, 4, 0, 23, 13, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Latin America
- { 270, 66, 152, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 78, 10, 22,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4942, 2, 0, 6083, 6100, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 13, 4, 0, 17, 6, {77,88,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Mexico
- { 270, 66, 168, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 294, 4955, 2, 0, 5900, 6106, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 20, 4, 0, 7, 9, {78,73,79}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Nicaragua
- { 270, 66, 181, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 1121, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 296, 4975, 2, 0, 5900, 6115, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 0, 7, 6, {80,65,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Panama
- { 270, 66, 183, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 299, 4990, 15, 86, 5900, 6121, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 17, 5, 6, 7, 8, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Paraguay
- { 270, 66, 184, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 279, 5007, 15, 0, 5900, 5362, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 11, 5, 0, 7, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Peru
- { 270, 66, 185, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 146, 5018, 4, 0, 5900, 6129, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 0, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Spanish/Latin/Philippines
- { 270, 66, 189, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 1121, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 0, 5900, 2080, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Puerto Rico
- { 270, 66, 248, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4870, 2, 0, 5900, 6138, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 20, 4, 0, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/United States
- { 270, 66, 250, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 5031, 15, 58, 5900, 6152, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 7, 7, 7, {85,89,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Uruguay
- { 270, 66, 254, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 22,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 302, 5044, 2, 65, 5900, 6159, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 16, 4, 5, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Venezuela
- { 271, 135, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 0, 0,22029,22029,22076,22076, 83, 83, 692, 723, 0, 5, 22, 0, 5060, 0, 0, 6168, 6176, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 8, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Standard Moroccan Tamazight/Tifinagh/Morocco
- { 272, 66, 111, 0, 0, 1090, 1103, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 167, 167,22105,22105,22148,22148, 9291, 9291, 0, 0, 0, 5, 22, 186, 5074, 2, 0, 6182, 1776, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 9, 4, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 15, 4, 0, 10, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sundanese/Latin/Indonesia
- { 273, 66, 230, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 121, 3492, 15, 0, 6192, 2268, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 20, 5, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Tanzania
- { 273, 66, 57, 0, 0, 566, 566, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 11, 5089, 15, 0, 6192, 6201, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 2, 16, 5, 0, 9, 32, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Congo - Kinshasa
- { 273, 66, 124, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 176, 991, 15, 0, 6192, 1307, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 17, 5, 0, 9, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swahili/Latin/Kenya
- { 273, 66, 243, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 147, 5105, 15, 0, 6192, 983, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 18, 5, 0, 9, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Swahili/Latin/Uganda
- { 274, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,22175,22175,22242,22242, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6233, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 67, 67, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swati/Latin/South Africa
- { 274, 66, 76, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 22,22175,22175,22242,22242, 83, 83, 0, 0, 0, 5, 22, 155, 0, 2, 0, 6233, 6240, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 67, 67, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 8, {83,90,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swati/Latin/Eswatini
- { 275, 66, 225, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 0, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 160, 5123, 4, 0, 6248, 6255, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 2, 12, 5, 0, 7, 7, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Sweden
- { 275, 66, 2, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 0, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 22, 405, 4, 0, 6248, 6262, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Aland Islands
- { 275, 66, 83, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 0, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 22, 405, 4, 0, 6248, 1698, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Finland
- { 276, 66, 226, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 0, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 0, 5135, 4, 0, 6267, 6267, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 0, 16, 5, 0, 16, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Switzerland
- { 276, 66, 84, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 0, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 22, 83, 4, 0, 6267, 6283, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 1, 4, 5, 0, 16, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/France
- { 276, 66, 136, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 0, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 0, 5135, 4, 0, 6267, 6293, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 0, 16, 5, 0, 16, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Liechtenstein
- { 277, 123, 113, 1124, 1124, 1124, 1124, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 1757, 395, 42, 54,22434,22434,22486,22486,22515,22515, 712, 744, 1084, 5, 22, 0, 0, 15, 0, 6306, 6312, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 12, 7, 52, 52, 29, 29, 13, 13, 4, 4, 4, 17, 23, 0, 0, 5, 0, 6, 4, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Syriac/Syriac/Iraq
- { 277, 123, 227, 1124, 1124, 1124, 1124, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 1757, 395, 42, 54,22434,22434,22486,22486,22515,22515, 712, 744, 1084, 5, 22, 99, 0, 15, 0, 6306, 6316, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 12, 7, 52, 52, 29, 29, 13, 13, 4, 4, 4, 17, 23, 5, 0, 5, 0, 6, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Syriac/Syriac/Syria
- { 278, 135, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 0, 0,22528,22528,22076,22076, 83, 83, 692, 723, 0, 5, 22, 0, 5060, 0, 0, 6321, 6176, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 46, 46, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Tifinagh/Morocco
- { 278, 66, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 0, 0,22574,22574,22621,22621, 83, 83, 716, 748, 0, 5, 22, 0, 5151, 0, 0, 6328, 6338, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 10, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Latin/Morocco
- { 280, 127, 255, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 306, 0, 15, 0, 6344, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 4, 0, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tai Dam/Tai Viet/Vietnam
- { 281, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,22650,22650,22754,22754,22781,22781, 722, 756, 0, 5, 22, 176, 991, 2, 9, 6348, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5,104,104, 27, 27, 13, 13, 10, 10, 4, 17, 23, 3, 17, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Taita/Latin/Kenya
- { 282, 27, 229, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 12, 11, 16, 17, 786, 78, 0, 0,22794,22794,22848,22848,22875,22875, 0, 0, 0, 5, 22, 307, 5165, 4, 0, 6355, 6361, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 6, 5, 0, 6, 10, {84,74,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tajik/Cyrillic/Tajikistan
- { 283, 129, 110, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 96, 96,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 120, 5171, 2, 9, 6371, 6376, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 1, 13, 4, 6, 5, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Tamil/Tamil/India
- { 283, 129, 143, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 96, 96,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 192, 5184, 2, 9, 6371, 6383, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 2, 17, 4, 6, 5, 7, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Malaysia
- { 283, 129, 210, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 96, 96,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 10, 5201, 2, 9, 6371, 6390, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 1, 17, 4, 6, 5, 11, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Singapore
- { 283, 129, 221, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 0, 0,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 311, 5218, 2, 9, 6371, 6401, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 3, 13, 4, 6, 5, 6, {76,75,82}, 2, 1, 1, 6, 7, 1, 2, 3 }, // Tamil/Tamil/Sri Lanka
- { 284, 66, 228, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 103, 10, 22,22993,22993,23164,23164,23191,23191, 0, 0, 0, 5, 22, 314, 5231, 15, 0, 6407, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 12, 7,171,171, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 11, 5, 0, 12, 0, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Taroko/Latin/Taiwan
- { 285, 66, 170, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,11682,11682,11735,11735,11762,11762, 732, 774, 0, 5, 22, 127, 3285, 0, 0, 6419, 6432, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 53, 53, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 13, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tasawaq/Latin/Niger
- { 286, 27, 193, 0, 0, 1143, 1143, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1775, 49, 1, 1,23204,23204,23259,23259,23294,23294, 0, 0, 0, 5, 22, 133, 5242, 4, 0, 6437, 5457, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 9, 4, 55, 55, 35, 35, 13, 13, 2, 2, 4, 17, 23, 1, 11, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tatar/Cyrillic/Russia
- { 287, 131, 110, 0, 0, 1152, 1152, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1798, 394, 42, 54,23307,23307,23366,23366,23397,23397, 0, 0, 1095, 1102, 22, 120, 5253, 2, 9, 6442, 6448, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 59, 59, 31, 31, 17, 17, 2, 2, 7, 29, 23, 1, 14, 4, 6, 6, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Telugu/Telugu/India
- { 288, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,23414,23414,23482,23482,23509,23509, 740, 784, 0, 5, 22, 147, 5267, 2, 9, 6456, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Teso/Latin/Uganda
- { 288, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,23414,23414,23482,23482,23509,23509, 740, 784, 0, 5, 22, 176, 5288, 2, 9, 6456, 6462, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 20, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Teso/Latin/Kenya
- { 289, 133, 231, 24, 24, 1163, 1171, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1816, 129, 454, 0,23522,23522,23589,23589,23611,23611, 749, 790, 1131, 5, 22, 317, 5308, 2, 9, 6467, 6467, 5, 5, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 6, 28, 5, 67, 67, 22, 22, 15, 15, 10, 10, 4, 17, 23, 1, 3, 4, 6, 3, 3, {84,72,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Thai/Thai/Thailand
- { 290, 134, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1835, 103, 0, 0,23626,23626,23704,23704,23754,23754, 759, 800, 0, 5, 22, 150, 5311, 15, 0, 6470, 6478, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 6, 5, 0, 8, 6, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tibetan/Tibetan/China
- { 290, 134, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1835, 103, 42, 54,23626,23626,23704,23704,23754,23754, 759, 800, 0, 5, 22, 120, 5317, 15, 0, 6470, 6484, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 12, 7, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 12, 5, 0, 8, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Tibetan/Tibetan/India
- { 291, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1858, 78, 42, 54,23780,23780,23820,23820,23846,23846, 0, 0, 0, 5, 22, 6, 0, 2, 0, 6491, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 8, 12, 7, 40, 40, 26, 26, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 3, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigre/Ethiopic/Eritrea
- { 292, 33, 77, 38, 38, 1178, 1178, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1879, 78, 42, 54,23859,23859,23887,23887,23907,23907, 766, 808, 0, 5, 22, 1, 112, 2, 0, 6494, 143, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 2, 2, 4, 0, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Ethiopia
- { 292, 33, 74, 38, 38, 1178, 1178, 6, 0, 1, 2, 3, 4, 5, 10, 16, 17, 14, 15, 1879, 78, 42, 54,23859,23859,23887,23887,23907,23907, 766, 808, 0, 5, 22, 6, 5329, 2, 0, 6494, 671, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 3, 4, 0, 4, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Eritrea
- { 294, 66, 182, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 787, 78, 482, 495,23920,23920,23964,23964, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 6498, 6507, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 8, 44, 44, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 9, 13, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tok Pisin/Latin/Papua New Guinea
- { 295, 66, 235, 1185, 1185, 1185, 1185, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 22,23991,23991,24050,24050,24078,24078, 770, 812, 1135, 1140, 1199, 205, 5332, 15, 0, 6520, 2283, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 59, 59, 28, 28, 13, 13, 10, 6, 5, 59, 65, 2, 17, 5, 0, 13, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tongan/Latin/Tonga
- { 296, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,24091,24091,24162,24162, 83, 83, 0, 0, 0, 5, 22, 9, 0, 15, 0, 6533, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 71, 71, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 8, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tsonga/Latin/South Africa
- { 297, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,24188,24188,24251,24251, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6541, 6549, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 63, 63, 31, 31, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 8, 13, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tswana/Latin/South Africa
- { 297, 66, 30, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,24188,24188,24251,24251, 83, 83, 0, 0, 0, 5, 22, 153, 0, 2, 0, 6541, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 63, 63, 31, 31, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 8, 0, {66,87,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tswana/Latin/Botswana
- { 298, 66, 239, 0, 0, 1193, 1193, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1896, 50, 0, 0,24282,24282,24335,24335,24362,24362, 780, 818, 185, 5, 22, 126, 5349, 2, 9, 6562, 6568, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 10, 5, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 11, 4, 6, 6, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Turkey
- { 298, 66, 63, 0, 0, 1193, 1193, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1896, 50, 10, 22,24282,24282,24335,24335,24362,24362, 780, 818, 185, 5, 22, 22, 83, 2, 9, 6562, 6575, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 12, 7, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 4, 6, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Cyprus
- { 299, 66, 240, 0, 0, 1201, 1201, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 14, 15, 1896, 49, 0, 0,24375,24428,24481,24508,24535,24535, 782, 820, 1264, 5, 22, 0, 5360, 4, 0, 6581, 6593, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 53, 53, 27, 27, 13, 13, 13, 14, 4, 17, 23, 0, 14, 5, 0, 12, 12, {84,77,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkmen/Latin/Turkmenistan
- { 301, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 0, 0,24548,24548,24589,24589, 83, 83, 0, 0, 0, 5, 22, 124, 5374, 15, 0, 6605, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 41, 41, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tyap/Latin/Nigeria
- { 303, 27, 244, 0, 0, 117, 117, 6, 1, 9, 2, 3, 4, 5, 85, 11, 12, 13, 14, 1912, 49, 0, 0,24616,24671, 3049, 3049, 4289, 4289, 795, 834, 1268, 841, 22, 286, 5378, 4, 0, 6610, 6620, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 10, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 10, 7, {85,65,72}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ukrainian/Cyrillic/Ukraine
- { 304, 66, 91, 0, 0, 781, 781, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 180, 1, 503,24726,24726,24778,24778,24805,24805, 402, 836, 1273, 5, 22, 22, 405, 4, 0, 6627, 6642, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 9, 12, 52, 52, 27, 27, 13, 13, 9, 9, 5, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Upper Sorbian/Latin/Germany
- { 305, 4, 178, 661, 661, 1209, 1219, 6, 0, 1, 2, 3, 35, 37, 10, 15, 14, 17, 16, 1934, 129, 42, 54,24818,24818,24818,24818, 83, 83, 0, 0, 1278, 1282, 22, 196, 5395, 2, 9, 6648, 5140, 6, 6, 10, 9, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 6, 12, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 2, 14, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Urdu/Arabic/Pakistan
- { 305, 4, 110, 661, 661, 1209, 1219, 6, 21, 22, 2, 40, 35, 41, 44, 15, 14, 17, 16, 1934, 129, 42, 54,24818,24818,24818,24818, 83, 83, 0, 0, 1278, 1282, 22, 120, 5409, 2, 9, 6648, 6652, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 12, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 1, 12, 4, 6, 4, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Urdu/Arabic/India
- { 306, 4, 50, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 12, 11, 20, 19, 1952, 103, 0, 0,24853,24853,24907,24907,24927,24927, 797, 845, 0, 5, 22, 145, 5421, 2, 9, 6657, 6665, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 54, 54, 20, 20, 13, 13, 12, 12, 4, 17, 23, 1, 11, 4, 6, 8, 5, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Uyghur/Arabic/China
- { 307, 66, 251, 0, 0, 1228, 1228, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 17, 16, 1969, 78, 74, 0,24940,24940,25000,25000,25031,25031, 360, 857, 185, 5, 22, 318, 5432, 2, 9, 6670, 6676, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 11, 5, 60, 60, 31, 31, 13, 13, 2, 2, 4, 17, 23, 4, 17, 4, 6, 6, 11, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Latin/Uzbekistan
- { 307, 4, 1, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1987, 505, 74, 1,18196,18196,25044,25044, 83, 83, 0, 0, 0, 5, 22, 270, 3963, 4, 0, 6687, 5131, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 33, 8, 11, 4, 48, 48, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Uzbek/Arabic/Afghanistan
- { 307, 27, 251, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1008, 78, 73, 0,25064,25064,25116,25116,25143,25143, 809, 859, 0, 5, 22, 322, 5449, 4, 0, 6693, 6700, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 12, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 14, 5, 0, 7, 10, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Cyrillic/Uzbekistan
- { 308, 139, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 42, 54,25156,25156,25156,25156, 83, 83, 0, 0, 0, 5, 22, 10, 5463, 2, 9, 6710, 6712, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 29, 29, 29, 29, 13, 13, 2, 2, 4, 17, 23, 1, 8, 4, 6, 2, 4, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Vai/Liberia
- { 308, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22,25185,25185,25185,25185, 83, 83, 0, 0, 0, 5, 22, 10, 5471, 2, 9, 6716, 6719, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 47, 47, 47, 47, 13, 13, 2, 2, 4, 17, 23, 1, 13, 4, 6, 3, 8, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Latin/Liberia
- { 309, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 0, 0,25232,25232,25301,25301, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6727, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 69, 69, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 9, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Venda/Latin/South Africa
- { 310, 66, 255, 0, 0, 1236, 1236, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 0, 0,25327,25327,25381,25381,25413,25413, 811, 861, 0, 5, 22, 306, 5484, 4, 0, 6736, 6746, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 54, 54, 32, 32, 20, 20, 2, 2, 4, 17, 23, 1, 13, 5, 0, 10, 8, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Vietnamese/Latin/Vietnam
- { 311, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2020, 103, 0, 0,25433,25433,25475,25495,25522,25522, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6754, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 42, 42, 20, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 7, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Volapuk/Latin/world
- { 312, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 2, 0, 6761, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 8, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Vunjo/Latin/Tanzania
- { 313, 66, 23, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 6769, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Walloon/Latin/Belgium
- { 314, 66, 226, 0, 0, 463, 463, 6, 1, 17, 2, 3, 4, 5, 10, 11, 12, 19, 20, 404, 103, 0, 0,25535,25535,25587,25587,25614,25614, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6774, 6780, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Walser/Latin/Switzerland
- { 315, 66, 15, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 241, 0, 15, 0, 6786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 8, 0, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Warlpiri/Latin/Australia
- { 316, 66, 246, 0, 0, 1244, 1255, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 78, 0, 0,25627,25627,25703,25731,25760,25760, 813, 863, 1302, 5, 22, 94, 5497, 2, 9, 6794, 6801, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 76, 76, 28, 29, 14, 14, 2, 2, 7, 17, 23, 1, 12, 4, 6, 7, 16, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Welsh/Latin/United Kingdom
- { 317, 4, 178, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 196, 5509, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 13, 5, 0, 14, 0, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Western Balochi/Arabic/Pakistan
- { 317, 4, 1, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 270, 5522, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 14, 0, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Western Balochi/Arabic/Afghanistan
- { 317, 4, 112, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 271, 5539, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 11, 5, 0, 14, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Western Balochi/Arabic/Iran
- { 317, 4, 176, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6817, 6831, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 14, 5, {79,77,82}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Western Balochi/Arabic/Oman
- { 317, 4, 245, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6817, 6836, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 14, 19, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // Western Balochi/Arabic/United Arab Emirates
- { 318, 66, 165, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 394, 0, 0,25774,25774,25827,25827, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 58, 6855, 6860, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 53, 53, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 7, 5, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Western Frisian/Latin/Netherlands
- { 319, 33, 77, 0, 0, 0, 0, 6, 0, 17, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2043, 78, 42, 54,25847,25847,25847,25847,25873,25873, 0, 0, 0, 5, 22, 1, 105, 2, 0, 6868, 143, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 12, 7, 26, 26, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 9, 4, 0, 5, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Wolaytta/Ethiopic/Ethiopia
- { 320, 66, 206, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2065, 394, 0, 0,25886,25886,25935,25935,25935,25935, 732, 865, 0, 5, 22, 127, 5550, 15, 0, 6873, 2999, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 49, 49, 27, 27, 27, 27, 3, 3, 4, 17, 23, 5, 29, 5, 0, 5, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Wolof/Latin/Senegal
- { 321, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 0, 0,25962,25962,26022,26049,26078,26098, 0, 0, 0, 5, 22, 9, 5579, 2, 0, 6878, 6886, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 60, 60, 27, 29, 20, 21, 2, 2, 4, 17, 23, 1, 25, 4, 0, 8, 15, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Xhosa/Latin/South Africa
- { 322, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 129, 0, 0,26119,26119,26189,26189,26209,26209, 815, 868, 0, 5, 22, 11, 0, 4, 20, 6901, 6907, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 70, 70, 20, 20, 13, 13, 8, 8, 4, 17, 23, 4, 0, 5, 7, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yangben/Latin/Cameroon
- { 323, 47, 244, 0, 0, 1265, 1265, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 2082, 78, 0, 0,26222,26222,26222,26222, 83, 83, 823, 876, 0, 5, 22, 286, 0, 15, 0, 6914, 6920, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 10, 5, 53, 53, 53, 53, 13, 13, 11, 10, 4, 17, 23, 1, 0, 5, 0, 6, 9, {85,65,72}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yiddish/Hebrew/Ukraine
- { 324, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2101, 129, 0, 1,26275,26318,26386,26386,26418,26418, 834, 886, 1309, 1320, 22, 124, 5604, 2, 9, 6929, 6939, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 1, 14, 4, 6, 10, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Nigeria
- { 324, 66, 25, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2101, 129, 0, 1,26431,26474,26542,26542,26574,26574, 839, 891, 1357, 1320, 22, 127, 5618, 2, 9, 6929, 6947, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 5, 26, 4, 6, 10, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Benin
- { 325, 66, 170, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 0, 0,26587,26587,11735,11735,26639,26639, 732, 774, 0, 5, 22, 127, 3285, 0, 0, 6953, 6432, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 52, 52, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 10, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Zarma/Latin/Niger
- { 326, 66, 50, 0, 0, 1274, 1274, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0,26652,26652,26652,26652, 83, 83, 844, 896, 0, 5, 22, 150, 5644, 15, 0, 6963, 6972, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 89, 89, 89, 89, 13, 13, 7, 12, 4, 17, 23, 1, 10, 5, 0, 9, 8, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Zhuang/Latin/China
- { 327, 66, 216, 0, 0, 1285, 1294, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 0, 0,26741,26741,26814,26814,26841,26841, 0, 0, 0, 5, 22, 9, 5654, 2, 9, 6980, 6987, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 73, 73, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 17, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Zulu/Latin/South Africa
- { 328, 66, 32, 0, 0, 1302, 1302, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2117, 186, 0, 0,26854,26854,26940,26940,26974,26974, 0, 0, 1368, 5, 22, 9, 5674, 15, 0, 7004, 7011, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 86, 86, 34, 34, 20, 20, 2, 2, 7, 17, 23, 2, 12, 5, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kaingang/Latin/Brazil
- { 329, 66, 32, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 0, 0,26994,26994,27058,27058,27085,27085, 0, 0, 1375, 5, 22, 9, 5686, 15, 0, 7017, 7025, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 64, 64, 27, 27, 13, 13, 2, 2, 8, 17, 23, 2, 15, 5, 0, 8, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Brazil
- { 329, 66, 54, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22,26994,26994,27058,27058,27085,27085, 132, 128, 1375, 5, 22, 10, 5701, 15, 0, 7031, 7038, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 1, 17, 5, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Colombia
- { 329, 66, 254, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 22,26994,26994,27058,27058,27085,27085, 132, 128, 1375, 5, 22, 302, 5718, 15, 0, 7031, 7046, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 4, 22, 5, 0, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Venezuela
- { 330, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 42, 54,27098,27098,27098,27098, 83, 83, 851, 83, 0, 5, 22, 120, 0, 15, 0, 7055, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 54, 54, 54, 54, 13, 13, 4, 4, 4, 17, 23, 1, 0, 5, 0, 8, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Haryanvi/Devanagari/India
- { 331, 66, 91, 0, 0, 915, 915, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 404, 78, 0, 0,27152,27152,27208,27208, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 0, 7063, 7073, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Frisian/Latin/Germany
- { 332, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 42, 54, 8522, 8522, 8522, 8522, 83, 83, 855, 908, 0, 5, 22, 120, 0, 15, 0, 7082, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 52, 52, 52, 52, 13, 13, 5, 4, 4, 17, 23, 1, 0, 5, 0, 9, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Rajasthani/Devanagari/India
- { 333, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 7091, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Moksha/Cyrillic/Russia
- { 334, 66, 258, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0,27235,27235,27235,27235, 83, 83, 860, 912, 0, 5, 22, 0, 0, 2, 0, 7103, 7112, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 90, 90, 90, 90, 13, 13, 12, 12, 4, 17, 23, 0, 0, 4, 0, 9, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 2, 2 }, // Toki Pona/Latin/world
- { 335, 66, 214, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0,27325,27325,27325,27325, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 7118, 7123, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 46, 46, 46, 46, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 13, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Pijin/Latin/Solomon Islands
- { 336, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 124, 0, 15, 0, 7136, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Obolo/Latin/Nigeria
- { 337, 4, 178, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 303, 316,27371,27371,27417,27417, 83, 83, 0, 0, 0, 5, 22, 196, 5395, 15, 0, 7141, 5140, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 8, 46, 46, 24, 24, 13, 13, 2, 2, 4, 17, 23, 2, 13, 5, 0, 5, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Baluchi/Arabic/Pakistan
- { 337, 66, 178, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 482, 495,27441,27441,27511,27511, 83, 83, 0, 0, 0, 5, 22, 196, 5740, 15, 0, 7146, 7153, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 8, 70, 70, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 14, 5, 0, 7, 8, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Baluchi/Latin/Pakistan
- { 338, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 2140, 78, 0, 0,27537,27537,27591,27591,27625,27625, 0, 0, 0, 5, 22, 22, 405, 4, 20, 7161, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 8, 10, 5, 54, 54, 34, 34, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ligurian/Latin/Italy
- { 339, 142, 161, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 0, 1, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 134, 0, 15, 0, 7167, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 4, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 18, 0, {77,77,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Rohingya/Hanifi/Myanmar
- { 339, 142, 20, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 42, 54, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 132, 0, 15, 0, 7167, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 18, 0, {66,68,84}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Rohingya/Hanifi/Bangladesh
- { 340, 4, 178, 1321, 1321, 1326, 1335, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1934, 129, 42, 54,27638,27638,27638,27638,27695,27695, 0, 0, 1278, 1282, 22, 196, 5395, 15, 0, 7185, 5140, 5, 5, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 57, 57, 57, 57, 13, 13, 2, 2, 4, 20, 23, 2, 14, 5, 0, 7, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Torwali/Arabic/Pakistan
- { 341, 66, 25, 0, 0, 566, 566, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 2161, 2178, 0, 0,27708,27708,27766,27766,27800,27800, 872, 924, 0, 5, 22, 127, 5754, 15, 86, 7192, 7203, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 58, 58, 34, 34, 20, 20, 13, 13, 4, 17, 23, 5, 33, 5, 6, 11, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Anii/Latin/Benin
- { 342, 29, 110, 0, 0, 1343, 1353, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 42, 54,27820,27820,27872,27872,27905,27905, 885, 937, 0, 5, 22, 120, 5787, 2, 0, 7208, 664, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 52, 52, 33, 33, 18, 18, 6, 11, 4, 17, 23, 1, 14, 4, 0, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Kangri/Devanagari/India
- { 343, 66, 117, 0, 0, 414, 414, 6, 1, 68, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 78, 0, 0,27923,27923,27967,27967,27625,27625, 0, 0, 0, 5, 22, 155, 405, 117, 0, 7215, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 44, 44, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Venetian/Latin/Italy
+ { 2, 27, 90, 0, 0, 7, 7, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 27, 49, 10, 0, 109, 109, 157, 157, 179, 179, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 6, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 48, 48, 22, 22, 15, 15, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 9, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Abkhazian/Cyrillic/Georgia
+ { 3, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 1, 0, 2, 0, 15, 20, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 4, 0, 5, 7, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afar/Latin/Ethiopia
+ { 3, 66, 67, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 3, 0, 2, 0, 15, 27, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 5, 7, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Afar/Latin/Djibouti
+ { 3, 66, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 6, 0, 2, 0, 15, 34, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 5, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Afar/Latin/Eritrea
+ { 4, 66, 216, 0, 0, 16, 16, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 86, 103, 10, 0, 285, 285, 342, 342, 369, 369, 2, 2, 45, 5, 22, 9, 0, 2, 9, 41, 50, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 20, 4, 6, 9, 11, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/South Africa
+ { 4, 66, 162, 0, 0, 16, 16, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 103, 23, 38, 285, 285, 342, 342, 369, 369, 2, 2, 45, 5, 22, 10, 20, 2, 9, 41, 61, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 16, 4, 6, 9, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/Namibia
+ { 5, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 382, 382, 453, 453, 480, 480, 5, 5, 0, 5, 22, 11, 36, 0, 0, 68, 73, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 71, 71, 27, 27, 13, 13, 3, 3, 4, 17, 23, 4, 14, 4, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Aghem/Latin/Cameroon
+ { 6, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 23, 38, 493, 493, 541, 541, 568, 568, 8, 8, 0, 5, 22, 15, 50, 2, 0, 80, 84, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 48, 48, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 10, 4, 0, 4, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Akan/Latin/Ghana
+ { 8, 66, 40, 0, 0, 24, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 11, 60, 15, 0, 89, 95, 6, 6, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 10, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Akoose/Latin/Cameroon
+ { 9, 66, 3, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 45, 38, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 18, 70, 4, 20, 102, 107, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 16, 7, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 4, 13, 5, 7, 5, 8, {65,76,76}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Albania
+ { 9, 66, 126, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 10, 0, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 22, 83, 4, 20, 102, 115, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 1, 6, 5, 7, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Kosovo
+ { 9, 66, 140, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 10, 0, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 23, 89, 4, 20, 102, 121, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 3, 16, 5, 7, 5, 18, {77,75,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Macedonia
+ { 11, 33, 77, 38, 38, 44, 53, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 19, 20, 163, 186, 61, 76, 679, 679, 706, 706, 732, 732, 21, 20, 54, 57, 22, 26, 105, 2, 9, 139, 143, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 26, 26, 13, 13, 3, 4, 3, 23, 23, 2, 9, 4, 6, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Amharic/Ethiopic/Ethiopia
+ { 14, 4, 71, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 28, 114, 27, 0, 148, 155, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {69,71,80}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Egypt
+ { 14, 4, 4, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 33, 123, 33, 38, 148, 158, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Algeria
+ { 14, 4, 19, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 38, 135, 27, 0, 148, 165, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 6, 0, 7, 7, {66,72,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Bahrain
+ { 14, 4, 48, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 11, 147, 27, 0, 148, 172, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 4, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Chad
+ { 14, 4, 55, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 10, 0, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 12, 162, 27, 0, 148, 176, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 2, 14, 6, 0, 7, 9, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Comoros
+ { 14, 4, 67, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 3, 176, 27, 0, 148, 185, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 11, 6, 0, 7, 6, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Djibouti
+ { 14, 4, 74, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 6, 187, 27, 0, 148, 191, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 12, 6, 0, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Eritrea
+ { 14, 4, 113, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 43, 199, 27, 0, 148, 198, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Iraq
+ { 14, 4, 116, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 11, 1, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 48, 210, 27, 0, 148, 204, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 4, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 7, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Israel
+ { 14, 4, 122, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 49, 228, 27, 0, 148, 211, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {74,79,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Jordan
+ { 14, 4, 127, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 54, 239, 27, 0, 148, 217, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {75,87,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Kuwait
+ { 14, 4, 132, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 59, 250, 27, 0, 148, 223, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 5, {76,66,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Lebanon
+ { 14, 4, 135, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 64, 261, 33, 38, 148, 228, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 5, {76,89,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Libya
+ { 14, 4, 149, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 69, 271, 27, 0, 148, 233, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 9, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Mauritania
+ { 14, 4, 159, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 10, 0, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 73, 286, 33, 38, 148, 242, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 13, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Morocco
+ { 14, 4, 176, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 78, 296, 27, 0, 148, 248, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {79,77,82}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Oman
+ { 14, 4, 180, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 48, 210, 27, 0, 148, 253, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 18, {73,76,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Palestinian Territories
+ { 14, 4, 190, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 83, 306, 27, 0, 148, 271, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {81,65,82}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Qatar
+ { 14, 4, 205, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 88, 315, 27, 0, 148, 274, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 24, {83,65,82}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Saudi Arabia
+ { 14, 4, 215, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 93, 325, 27, 0, 148, 298, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 10, 6, 0, 7, 7, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Somalia
+ { 14, 4, 219, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 94, 335, 27, 0, 148, 305, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 17, 6, 0, 7, 12, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/South Sudan
+ { 14, 4, 222, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 95, 352, 27, 0, 148, 317, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 11, 6, 0, 7, 7, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Sudan
+ { 14, 4, 227, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 99, 363, 27, 0, 148, 324, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Syria
+ { 14, 4, 238, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 104, 373, 33, 38, 148, 329, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 5, 7, 7, 4, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Tunisia
+ { 14, 4, 245, 61, 61, 61, 61, 6, 0, 1, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 109, 384, 33, 38, 148, 333, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 24, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/United Arab Emirates
+ { 14, 4, 257, 61, 61, 61, 61, 6, 0, 1, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 73, 286, 33, 38, 148, 357, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 15, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Western Sahara
+ { 14, 4, 258, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 0, 0, 27, 0, 372, 394, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 0, 0, 6, 0, 22, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/world
+ { 14, 4, 259, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 114, 396, 27, 0, 148, 400, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 5, {89,69,82}, 0, 0, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Yemen
+ { 15, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 15, 15, 223, 129, 11, 1, 809, 809, 860, 860, 887, 887, 0, 0, 0, 5, 22, 22, 405, 2, 9, 405, 413, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 12, 4, 51, 51, 27, 27, 16, 16, 2, 2, 4, 17, 23, 1, 4, 4, 6, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Aragonese/Latin/Spain
+ { 17, 5, 12, 0, 0, 75, 75, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 245, 49, 10, 0, 903, 903, 964, 964, 991, 991, 0, 0, 121, 127, 22, 119, 409, 4, 0, 420, 427, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 8, 13, 5, 61, 61, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 13, 5, 0, 7, 8, {65,77,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Armenian/Armenian/Armenia
+ { 18, 9, 110, 0, 0, 82, 82, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 283, 83, 83, 1004, 1004, 1061, 1061, 1092, 1092, 25, 25, 144, 148, 22, 120, 422, 2, 9, 435, 442, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 57, 57, 31, 31, 13, 13, 9, 7, 4, 37, 23, 1, 12, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Assamese/Bangla/India
+ { 19, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 223, 129, 10, 0, 1105, 1105, 1158, 1158, 1185, 1185, 34, 32, 0, 5, 22, 22, 405, 4, 0, 446, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 13, 5, 53, 53, 27, 27, 13, 13, 12, 11, 5, 17, 23, 1, 4, 5, 0, 9, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Asturian/Latin/Spain
+ { 20, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1257, 1257, 1284, 1284, 46, 43, 0, 5, 22, 121, 434, 4, 0, 461, 467, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 27, 27, 13, 13, 9, 8, 4, 17, 23, 3, 21, 5, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Asu/Latin/Tanzania
+ { 21, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 10, 0, 1297, 1297, 1383, 1383, 83, 83, 0, 0, 0, 5, 22, 124, 455, 15, 0, 475, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 86, 86, 33, 33, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Atsam/Latin/Nigeria
+ { 25, 66, 17, 0, 0, 91, 91, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 291, 49, 10, 0, 1416, 1416, 1482, 1508, 96, 96, 0, 0, 185, 5, 22, 125, 459, 4, 0, 480, 490, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Latin/Azerbaijan
+ { 25, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Azerbaijani/Arabic/Iran
+ { 25, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Azerbaijani/Arabic/Iraq
+ { 25, 4, 239, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 126, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 0, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Arabic/Turkey
+ { 25, 27, 17, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 291, 49, 10, 0, 1534, 1534, 1600, 1600, 96, 96, 55, 51, 0, 5, 22, 125, 476, 4, 0, 506, 516, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 5, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Cyrillic/Azerbaijan
+ { 26, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 16, 17, 113, 129, 10, 0, 1626, 1626, 1670, 1670, 1698, 1698, 57, 53, 0, 5, 22, 11, 481, 4, 0, 526, 531, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 44, 44, 28, 28, 13, 13, 6, 7, 4, 17, 23, 4, 4, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bafia/Latin/Cameroon
+ { 28, 66, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0, 1711, 1711, 1754, 1754, 1781, 1781, 0, 0, 0, 5, 22, 127, 485, 2, 9, 538, 547, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 17, 4, 6, 9, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Latin/Mali
+ { 28, 90, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 127, 0, 2, 9, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 4, 6, 0, 0, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Nko/Mali
+ { 30, 9, 20, 0, 0, 99, 99, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 1794, 1794, 1851, 1851, 1887, 1887, 0, 0, 144, 5, 22, 132, 502, 0, 45, 551, 556, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 14, 4, 6, 5, 8, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Bangla/Bangla/Bangladesh
+ { 30, 9, 110, 0, 0, 99, 99, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 1794, 1794, 1851, 1851, 1887, 1887, 0, 0, 144, 5, 22, 120, 516, 2, 9, 551, 564, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bangla/Bangla/India
+ { 31, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 113, 129, 10, 0, 1904, 1904, 1973, 1973, 2000, 2000, 63, 60, 0, 5, 22, 11, 528, 4, 0, 568, 573, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 69, 69, 27, 27, 13, 13, 10, 9, 4, 17, 23, 4, 15, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Basaa/Latin/Cameroon
+ { 32, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 581, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bashkir/Cyrillic/Russia
+ { 33, 66, 220, 0, 0, 108, 108, 6, 1, 0, 2, 3, 48, 5, 10, 11, 12, 14, 15, 308, 344, 98, 0, 2013, 2013, 2080, 2080, 2107, 2107, 0, 0, 189, 5, 22, 22, 543, 4, 20, 593, 600, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 6, 15, 5, 67, 67, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 5, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Basque/Latin/Spain
+ { 35, 27, 22, 0, 0, 117, 117, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 50, 113, 0, 2120, 2120, 2175, 2175, 2195, 2195, 0, 0, 196, 201, 22, 1, 548, 4, 0, 608, 618, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 7, 14, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 16, 5, 0, 10, 8, {66,89,78}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Belarusian/Cyrillic/Belarus
+ { 36, 66, 260, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 2208, 2208, 2208, 2208, 83, 83, 73, 69, 0, 5, 22, 134, 0, 2, 9, 626, 635, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 79, 79, 79, 79, 13, 13, 8, 7, 4, 17, 23, 1, 0, 4, 6, 9, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bemba/Latin/Zambia
+ { 37, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 2287, 2287, 2368, 2368, 2395, 2395, 81, 76, 0, 5, 22, 121, 564, 0, 0, 641, 647, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 81, 81, 27, 27, 13, 13, 7, 7, 4, 17, 23, 3, 22, 4, 0, 6, 10, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Bena/Latin/Tanzania
+ { 38, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76, 2408, 2408, 2408, 2408, 83, 83, 88, 83, 0, 5, 22, 120, 0, 2, 0, 657, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 55, 55, 55, 55, 13, 13, 3, 4, 4, 17, 23, 1, 0, 4, 0, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Bhojpuri/Devanagari/India
+ { 40, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 372, 78, 61, 76, 2463, 2463, 2505, 2505, 2530, 2530, 0, 0, 0, 5, 22, 6, 0, 2, 0, 668, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 15, 7, 42, 42, 25, 25, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 3, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Blin/Ethiopic/Eritrea
+ { 41, 29, 110, 0, 0, 124, 134, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 291, 394, 127, 142, 2543, 2597, 2650, 2650, 2682, 2682, 91, 87, 0, 5, 22, 120, 586, 2, 9, 675, 664, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 10, 54, 53, 32, 32, 17, 17, 3, 6, 4, 17, 23, 1, 11, 4, 6, 3, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bodo/Devanagari/India
+ { 42, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 16, 17, 404, 423, 10, 0, 2699, 2699, 2756, 2756, 2783, 2796, 94, 93, 218, 5, 22, 135, 597, 4, 0, 678, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 11, 13, 5, 57, 57, 27, 27, 13, 13, 10, 7, 7, 17, 23, 2, 40, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Latin/Bosnia and Herzegovina
+ { 42, 27, 29, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 434, 454, 10, 0, 2809, 2809, 2864, 2864, 2891, 2891, 104, 100, 0, 5, 22, 137, 637, 4, 0, 705, 713, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 7, 13, 5, 55, 55, 27, 27, 13, 13, 11, 13, 4, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Cyrillic/Bosnia and Herzegovina
+ { 43, 66, 84, 0, 0, 157, 157, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 186, 10, 0, 2904, 2904, 2946, 2946, 2978, 2978, 115, 113, 225, 232, 249, 22, 405, 4, 0, 732, 741, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 42, 42, 32, 32, 17, 17, 4, 4, 7, 17, 23, 1, 4, 5, 0, 9, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Breton/Latin/France
+ { 45, 27, 36, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 13, 14, 350, 461, 152, 1, 2995, 2995, 3049, 3049, 3069, 3069, 119, 117, 272, 5, 22, 139, 656, 4, 20, 746, 755, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 12, 17, 4, 54, 54, 20, 20, 13, 13, 6, 6, 7, 17, 23, 3, 13, 5, 7, 9, 8, {66,71,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Bulgarian/Cyrillic/Bulgaria
+ { 46, 86, 161, 165, 165, 172, 172, 182, 0, 1, 2, 50, 4, 5, 10, 14, 15, 16, 17, 473, 129, 169, 1, 3082, 3082, 3082, 3082, 3135, 3135, 125, 123, 279, 5, 22, 134, 669, 15, 0, 763, 763, 7, 7, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 4, 53, 53, 53, 53, 13, 13, 5, 3, 5, 17, 23, 1, 11, 5, 0, 6, 6, {77,77,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Burmese/Myanmar/Myanmar
+ { 47, 137, 107, 183, 183, 188, 188, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 491, 505, 182, 43, 3148, 3148, 3148, 3148, 3175, 3175, 130, 126, 0, 5, 22, 142, 680, 2, 9, 769, 771, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 16, 6, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 2, 4, 6, 2, 14, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cantonese/Traditional Han/Hong Kong
+ { 47, 118, 50, 183, 183, 188, 188, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 505, 169, 0, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 0, 5, 22, 145, 682, 2, 9, 785, 787, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 2, 7, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cantonese/Simplified Han/China
+ { 48, 66, 220, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 413, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Spain
+ { 48, 66, 6, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 800, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Andorra
+ { 48, 66, 84, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 807, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/France
+ { 48, 66, 117, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 813, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Italy
+ { 49, 66, 185, 0, 0, 193, 202, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 3294, 3294, 3349, 3349, 3376, 3376, 0, 0, 284, 5, 22, 146, 685, 2, 9, 819, 826, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 55, 55, 27, 27, 13, 13, 2, 2, 8, 17, 23, 1, 15, 4, 6, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cebuano/Latin/Philippines
+ { 50, 66, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 3389, 3389, 3436, 3436, 3463, 3463, 137, 133, 0, 5, 22, 0, 700, 4, 0, 835, 852, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 47, 47, 27, 27, 13, 13, 9, 10, 4, 17, 23, 0, 15, 5, 0, 17, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Central Atlas Tamazight/Latin/Morocco
+ { 51, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 25, 55, 57, 59, 14, 15, 16, 17, 163, 103, 61, 76, 3476, 3476, 3476, 3476, 3533, 3533, 146, 143, 0, 5, 22, 43, 715, 4, 0, 858, 872, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 5, 13, 5, 0, 14, 5, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Central Kurdish/Arabic/Iraq
+ { 51, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 25, 55, 57, 59, 14, 15, 16, 17, 163, 103, 10, 0, 3476, 3476, 3476, 3476, 3533, 3533, 146, 143, 0, 5, 22, 0, 728, 4, 0, 858, 877, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 0, 12, 5, 0, 14, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Central Kurdish/Arabic/Iran
+ { 52, 21, 20, 0, 0, 210, 210, 6, 0, 1, 2, 61, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 3546, 3546, 3672, 3672, 3756, 3756, 0, 0, 292, 5, 22, 132, 740, 0, 45, 882, 894, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 21, 4, 6, 12, 14, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Chakma/Chakma/Bangladesh
+ { 52, 21, 110, 0, 0, 210, 210, 6, 0, 1, 2, 61, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 3546, 3546, 3672, 3672, 3756, 3756, 0, 0, 292, 5, 22, 120, 761, 0, 45, 882, 908, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 27, 4, 6, 12, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Chakma/Chakma/India
+ { 54, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 3794, 3794, 3838, 3838, 3862, 3838, 0, 0, 0, 5, 22, 133, 788, 4, 0, 918, 925, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 44, 44, 24, 24, 16, 24, 2, 2, 4, 17, 23, 1, 11, 5, 0, 7, 5, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chechen/Cyrillic/Russia
+ { 55, 23, 248, 0, 0, 222, 231, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76, 3878, 3878, 3926, 3926, 3953, 3953, 149, 146, 300, 5, 22, 10, 799, 2, 9, 930, 933, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 27, 27, 13, 13, 3, 6, 6, 17, 23, 1, 6, 4, 6, 3, 15, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cherokee/Cherokee/United States
+ { 56, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 3966, 3966, 3966, 3966, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 948, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 87, 87, 87, 87, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 16, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chickasaw/Latin/United States
+ { 57, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 4053, 4053, 4126, 4126, 4153, 4153, 0, 0, 0, 5, 22, 147, 805, 2, 0, 977, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Chiga/Latin/Uganda
+ { 58, 118, 50, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 505, 169, 0, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 150, 682, 2, 9, 989, 993, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 5, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 3, 4, 6, 4, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/China
+ { 58, 118, 107, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 129, 198, 43, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 142, 824, 2, 9, 989, 995, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 14, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Hong Kong
+ { 58, 118, 139, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 129, 198, 43, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 151, 826, 2, 9, 989, 1004, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 14, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Macao
+ { 58, 118, 210, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 78, 198, 43, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 10, 829, 2, 9, 989, 1013, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 14, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 4, 4, 6, 4, 3, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Singapore
+ { 58, 137, 107, 183, 183, 244, 244, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 129, 182, 43, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 308, 5, 22, 142, 824, 2, 9, 1016, 1020, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 16, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Hong Kong
+ { 58, 137, 139, 183, 183, 244, 244, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 129, 182, 43, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 308, 5, 22, 151, 833, 2, 9, 1016, 1029, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 16, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Macao
+ { 58, 137, 228, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 491, 505, 182, 43, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 0, 5, 22, 10, 836, 2, 9, 1016, 1038, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 16, 6, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 4, 2, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Taiwan
+ { 59, 27, 193, 0, 0, 249, 249, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 573, 596, 10, 0, 4186, 4186, 4253, 4253, 4289, 4289, 0, 0, 0, 5, 22, 133, 839, 4, 0, 1040, 1059, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 67, 67, 36, 36, 13, 13, 2, 2, 4, 17, 23, 1, 18, 5, 0, 19, 7, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Church/Cyrillic/Russia
+ { 60, 27, 193, 0, 0, 257, 257, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 606, 49, 10, 0, 4302, 4302, 4367, 4367, 4399, 4399, 0, 0, 0, 5, 22, 133, 857, 4, 0, 1066, 1071, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 65, 65, 32, 32, 13, 13, 2, 2, 4, 17, 23, 1, 12, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chuvash/Cyrillic/Russia
+ { 61, 66, 91, 0, 0, 267, 267, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 18, 16, 628, 423, 10, 0, 4412, 4412, 4483, 4483, 4510, 4510, 152, 152, 0, 5, 22, 22, 83, 4, 0, 1077, 1083, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 23, 10, 13, 5, 71, 71, 27, 27, 13, 13, 16, 16, 4, 17, 23, 1, 4, 5, 0, 6, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Colognian/Latin/Germany
+ { 63, 66, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 4523, 4523, 4583, 4583, 83, 83, 168, 168, 0, 5, 22, 94, 0, 2, 0, 1094, 1102, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 60, 60, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 8, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cornish/Latin/United Kingdom
+ { 64, 66, 84, 0, 0, 275, 275, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 651, 186, 10, 0, 4610, 4610, 4660, 4660, 4694, 4694, 0, 0, 0, 5, 22, 155, 405, 4, 51, 1116, 1121, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 10, 13, 5, 50, 50, 34, 34, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 7, 5, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Corsican/Latin/France
+ { 66, 66, 60, 0, 0, 143, 143, 6, 1, 0, 2, 3, 48, 5, 10, 13, 14, 18, 16, 404, 676, 98, 0, 2699, 2699, 2756, 2756, 2783, 2796, 0, 0, 218, 5, 22, 22, 405, 4, 0, 1128, 1136, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 15, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 0, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Croatia
+ { 66, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 48, 5, 10, 13, 14, 18, 16, 404, 689, 98, 0, 2699, 2699, 2756, 2756, 2796, 2796, 0, 0, 218, 5, 22, 135, 618, 4, 0, 1128, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 9, 15, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Bosnia and Herzegovina
+ { 67, 66, 64, 0, 0, 282, 282, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 18, 16, 698, 49, 114, 1, 4707, 4707, 4755, 4755, 4775, 4775, 172, 172, 311, 5, 22, 158, 869, 4, 0, 1144, 1151, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 4, 48, 48, 20, 20, 13, 13, 4, 4, 5, 17, 23, 2, 12, 5, 0, 7, 5, {67,90,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Czech/Latin/Czechia
+ { 68, 66, 65, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 715, 49, 212, 212, 4788, 4788, 4838, 4838, 4874, 4874, 0, 0, 0, 5, 22, 160, 881, 4, 0, 1156, 1161, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Denmark
+ { 68, 66, 95, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 715, 49, 212, 212, 4788, 4788, 4838, 4838, 4874, 4874, 0, 0, 0, 5, 22, 160, 881, 4, 0, 1156, 1168, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 8, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Greenland
+ { 69, 132, 144, 0, 0, 0, 0, 2, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 163, 0, 15, 0, 1176, 1186, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 10, 13, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // Divehi/Thaana/Maldives
+ { 70, 29, 110, 0, 0, 297, 306, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 738, 129, 61, 76, 4887, 4887, 4937, 4937, 4966, 4988, 176, 176, 0, 5, 22, 120, 892, 2, 0, 1199, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 50, 50, 29, 29, 22, 24, 4, 9, 4, 17, 23, 1, 10, 4, 0, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Dogri/Devanagari/India
+ { 71, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 16, 17, 113, 129, 10, 0, 5012, 5012, 5056, 5056, 5083, 5083, 180, 185, 0, 5, 22, 11, 0, 4, 0, 1204, 1209, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 44, 44, 27, 27, 13, 13, 5, 6, 4, 17, 23, 4, 0, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Duala/Latin/Cameroon
+ { 72, 66, 165, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 22, 83, 15, 58, 1217, 1217, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Netherlands
+ { 72, 66, 13, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 165, 902, 15, 58, 1217, 1227, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 16, 5, 7, 10, 5, {65,87,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Aruba
+ { 72, 66, 23, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 187, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 22, 83, 15, 58, 1232, 1238, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Belgium
+ { 72, 66, 44, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 10, 918, 15, 58, 1217, 1244, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 18, 5, 7, 10, 19, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Caribbean Netherlands
+ { 72, 66, 62, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 169, 936, 15, 58, 1217, 1263, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 7, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Curacao
+ { 72, 66, 211, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 169, 936, 15, 58, 1217, 1270, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Sint Maarten
+ { 72, 66, 223, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 10, 966, 15, 58, 1217, 1282, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 17, 5, 7, 10, 8, {83,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Suriname
+ { 73, 134, 27, 314, 314, 314, 314, 6, 0, 1, 2, 67, 4, 5, 10, 14, 15, 16, 17, 756, 103, 225, 255, 5187, 5187, 5265, 5265, 5298, 5298, 185, 191, 0, 5, 22, 173, 983, 2, 0, 1290, 1296, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 10, 30, 22, 78, 78, 33, 33, 26, 26, 5, 6, 4, 17, 23, 3, 8, 4, 0, 6, 5, {66,84,78}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Dzongkha/Tibetan/Bhutan
+ { 74, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 5324, 5324, 5387, 5387, 5414, 5414, 190, 197, 0, 5, 22, 176, 991, 2, 9, 1301, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Embu/Latin/Kenya
+ { 75, 66, 248, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1312, 964, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 16, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States
+ { 75, 28, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 5427, 5427, 5511, 5511, 5559, 5559, 192, 199, 0, 5, 22, 10, 0, 15, 0, 1328, 1338, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 84, 84, 48, 48, 20, 20, 4, 4, 4, 17, 23, 1, 0, 5, 0, 10, 25, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Deseret/United States
+ { 75, 66, 5, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1363, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/American Samoa
+ { 75, 66, 8, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1377, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Anguilla
+ { 75, 66, 10, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1385, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 17, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Antigua and Barbuda
+ { 75, 66, 15, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 6, 14, 15, 16, 17, 113, 129, 23, 38, 0, 0, 56, 56, 83, 5579, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1402, 1402, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 56, 56, 27, 27, 13, 24, 2, 2, 5, 17, 23, 1, 17, 4, 6, 18, 9, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Australia
+ { 75, 66, 16, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 15, 0, 1321, 1420, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Austria
+ { 75, 66, 18, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1055, 2, 9, 1321, 1427, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {66,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Bahamas
+ { 75, 66, 21, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1070, 2, 9, 1321, 1434, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 8, {66,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Barbados
+ { 75, 66, 23, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 78, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1442, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Belgium
+ { 75, 66, 24, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1086, 2, 9, 1321, 1449, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Belize
+ { 75, 66, 26, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1099, 2, 9, 1321, 1455, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 7, {66,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Bermuda
+ { 75, 66, 30, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 153, 1115, 2, 9, 1321, 1462, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 8, {66,87,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Botswana
+ { 75, 66, 33, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1470, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 30, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Indian Ocean Territory
+ { 75, 66, 34, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1500, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Virgin Islands
+ { 75, 66, 38, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 0, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 182, 1129, 2, 9, 1321, 1522, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Burundi
+ { 75, 66, 40, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 11, 1144, 2, 9, 1321, 1529, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 25, 4, 6, 7, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cameroon
+ { 75, 66, 41, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 103, 23, 38, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 10, 1169, 2, 9, 1537, 1553, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 15, 7, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 15, 4, 6, 16, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Canada
+ { 75, 66, 45, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1184, 2, 9, 1321, 1559, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 14, {75,89,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cayman Islands
+ { 75, 66, 51, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1573, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 16, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Christmas Island
+ { 75, 66, 53, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1589, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 23, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cocos Islands
+ { 75, 66, 58, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1612, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cook Islands
+ { 75, 66, 63, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 2, 9, 1321, 1624, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cyprus
+ { 75, 66, 65, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 212, 212, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 160, 1223, 4, 0, 1321, 1630, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 12, 5, 0, 7, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Denmark
+ { 75, 66, 66, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1637, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 12, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Diego Garcia
+ { 75, 66, 68, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1649, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Dominica
+ { 75, 66, 74, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 6, 1235, 2, 9, 1321, 1657, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 14, 4, 6, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eritrea
+ { 75, 66, 76, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 155, 1249, 2, 9, 1321, 1664, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 8, {83,90,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eswatini
+ { 75, 66, 78, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 0, 4, 0, 1321, 1672, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 0, 7, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Europe
+ { 75, 66, 80, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1264, 2, 9, 1321, 1678, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {70,75,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Falkland Islands
+ { 75, 66, 82, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1286, 2, 9, 1321, 1694, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 4, {70,74,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Fiji
+ { 75, 66, 83, 0, 0, 333, 333, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 213, 213, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1698, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Finland
+ { 75, 66, 89, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 185, 1299, 2, 9, 1321, 1705, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gambia
+ { 75, 66, 91, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1711, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Germany
+ { 75, 66, 92, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 15, 1313, 2, 9, 1321, 1718, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 13, 4, 6, 7, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ghana
+ { 75, 66, 93, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1326, 2, 9, 1321, 1723, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {71,73,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gibraltar
+ { 75, 66, 96, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1732, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 7, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Grenada
+ { 75, 66, 98, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1739, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 4, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Guam
+ { 75, 66, 100, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1743, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 8, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guernsey
+ { 75, 66, 103, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1349, 2, 9, 1321, 1751, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 6, {71,89,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guyana
+ { 75, 66, 107, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 142, 1365, 2, 9, 1321, 1757, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 19, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Hong Kong
+ { 75, 66, 110, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 78, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 120, 1381, 2, 9, 1321, 1478, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 12, 4, 6, 7, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // English/Latin/India
+ { 75, 66, 111, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 212, 212, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 186, 1393, 2, 9, 1321, 1776, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Indonesia
+ { 75, 66, 114, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 22, 83, 2, 9, 1321, 1785, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 4, 4, 6, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ireland
+ { 75, 66, 115, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1792, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 11, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Isle of Man
+ { 75, 66, 116, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 11, 1, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 48, 1410, 2, 9, 1321, 1803, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 6, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // English/Latin/Israel
+ { 75, 66, 119, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1428, 2, 9, 1321, 1809, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {74,77,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Jamaica
+ { 75, 66, 121, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1816, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 6, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Jersey
+ { 75, 66, 124, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 176, 1443, 2, 9, 1321, 1307, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Kenya
+ { 75, 66, 125, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1822, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 8, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Kiribati
+ { 75, 66, 133, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 9, 1458, 2, 9, 1321, 1830, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {90,65,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Lesotho
+ { 75, 66, 134, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1476, 2, 9, 1321, 1837, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Liberia
+ { 75, 66, 139, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 151, 1491, 2, 9, 1321, 1844, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 15, 4, 6, 7, 15, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Macao
+ { 75, 66, 141, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 188, 1506, 2, 9, 1321, 1859, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Madagascar
+ { 75, 66, 142, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 190, 1521, 2, 9, 1321, 1869, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 6, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malawi
+ { 75, 66, 143, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 192, 1536, 2, 9, 1321, 1875, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malaysia
+ { 75, 66, 144, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 194, 1553, 15, 0, 1321, 1883, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // English/Latin/Maldives
+ { 75, 66, 146, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 2, 9, 1321, 1891, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Malta
+ { 75, 66, 147, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1896, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 16, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Marshall Islands
+ { 75, 66, 150, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 196, 1570, 2, 9, 1321, 1912, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 9, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Mauritius
+ { 75, 66, 153, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1921, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 10, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Micronesia
+ { 75, 66, 158, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1931, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 10, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Montserrat
+ { 75, 66, 162, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1585, 2, 9, 1321, 1941, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Namibia
+ { 75, 66, 163, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1948, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 5, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nauru
+ { 75, 66, 165, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 15, 58, 1321, 1953, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Netherlands
+ { 75, 66, 167, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1964, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 11, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/New Zealand
+ { 75, 66, 169, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 124, 1600, 2, 9, 1321, 1975, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 7, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nigeria
+ { 75, 66, 171, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1982, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 4, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Niue
+ { 75, 66, 172, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1986, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 14, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Norfolk Island
+ { 75, 66, 173, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2000, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 24, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Northern Mariana Islands
+ { 75, 66, 178, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 196, 1614, 2, 9, 1321, 2024, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 8, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Pakistan
+ { 75, 66, 179, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2032, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 5, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Palau
+ { 75, 66, 182, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 134, 1629, 2, 9, 1321, 2037, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Papua New Guinea
+ { 75, 66, 185, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 685, 2, 9, 1321, 2053, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 11, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Philippines
+ { 75, 66, 186, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 2064, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 16, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Pitcairn
+ { 75, 66, 189, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2080, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Puerto Rico
+ { 75, 66, 194, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 198, 1651, 2, 9, 1321, 2091, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 4, 6, 7, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Rwanda
+ { 75, 66, 196, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1664, 2, 9, 1321, 2097, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {83,72,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Helena
+ { 75, 66, 197, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2106, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 16, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Kitts and Nevis
+ { 75, 66, 198, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2122, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Lucia
+ { 75, 66, 201, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2130, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 27, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Vincent and Grenadines
+ { 75, 66, 202, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 200, 1679, 2, 9, 1321, 1372, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 11, 4, 6, 7, 5, {87,83,84}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Samoa
+ { 75, 66, 208, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 203, 1690, 2, 9, 1321, 2157, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Seychelles
+ { 75, 66, 209, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 18, 1707, 2, 9, 1321, 2167, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 20, 4, 6, 7, 12, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sierra Leone
+ { 75, 66, 210, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1727, 2, 9, 1321, 2179, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Singapore
+ { 75, 66, 211, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 169, 1743, 2, 9, 1321, 2188, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 29, 4, 6, 7, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sint Maarten
+ { 75, 66, 213, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 6, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 20, 1321, 2200, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Slovenia
+ { 75, 66, 214, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1772, 2, 9, 1321, 2208, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 15, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Solomon Islands
+ { 75, 66, 216, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 821, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 9, 1458, 2, 9, 1321, 2223, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/South Africa
+ { 75, 66, 219, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1794, 2, 9, 1321, 2235, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 11, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/South Sudan
+ { 75, 66, 222, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 1814, 2, 9, 1321, 2246, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 14, 4, 6, 7, 5, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // English/Latin/Sudan
+ { 75, 66, 225, 0, 0, 333, 333, 6, 1, 9, 2, 3, 4, 5, 63, 14, 15, 16, 17, 0, 103, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 160, 1828, 4, 0, 1321, 2251, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 5, 0, 7, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sweden
+ { 75, 66, 226, 0, 0, 333, 333, 6, 0, 17, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 49, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 1841, 15, 65, 1321, 2257, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 11, 5, 5, 7, 11, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Switzerland
+ { 75, 66, 230, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 121, 1852, 2, 9, 1321, 2268, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 18, 4, 6, 7, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tanzania
+ { 75, 66, 234, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 2276, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tokelau
+ { 75, 66, 235, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 205, 1870, 2, 9, 1321, 2283, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 14, 4, 6, 7, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tonga
+ { 75, 66, 236, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1884, 2, 9, 1321, 2288, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 24, 4, 6, 7, 17, {84,84,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Trinidad and Tobago
+ { 75, 66, 241, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2305, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Turks and Caicos Islands
+ { 75, 66, 242, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 2327, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 6, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tuvalu
+ { 75, 66, 243, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 147, 1908, 2, 9, 1321, 983, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // English/Latin/Uganda
+ { 75, 66, 245, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 1924, 2, 9, 1321, 2333, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 27, 4, 6, 7, 20, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // English/Latin/United Arab Emirates
+ { 75, 66, 246, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1951, 2, 9, 2353, 2368, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 15, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/United Kingdom
+ { 75, 66, 247, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2382, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 21, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Outlying Islands
+ { 75, 66, 249, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2403, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Virgin Islands
+ { 75, 66, 252, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 207, 1964, 2, 9, 1321, 2422, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 12, 4, 6, 7, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Vanuatu
+ { 75, 66, 258, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 0, 2, 9, 1321, 2429, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 4, 6, 7, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/world
+ { 75, 66, 260, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 134, 1976, 2, 9, 1321, 635, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Zambia
+ { 75, 66, 261, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 129, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2434, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Zimbabwe
+ { 75, 115, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 5603, 5603, 5690, 5690, 5731, 5731, 196, 205, 0, 5, 22, 94, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 87, 87, 41, 41, 20, 20, 4, 4, 4, 17, 23, 1, 0, 5, 0, 0, 0, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Shavian/United Kingdom
+ { 76, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 5751, 5811, 5892, 5892, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 2442, 2453, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 81, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 11, 13, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Erzya/Cyrillic/Russia
+ { 77, 66, 258, 0, 0, 342, 342, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 831, 105, 10, 0, 5919, 5919, 5969, 5969, 5989, 5989, 200, 209, 316, 5, 22, 0, 0, 4, 0, 2466, 2475, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 8, 13, 5, 50, 50, 20, 20, 13, 13, 3, 3, 6, 17, 23, 0, 0, 5, 0, 9, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Esperanto/Latin/world
+ { 78, 66, 75, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 18, 16, 404, 49, 10, 0, 6002, 6002, 6064, 6064, 6064, 6064, 0, 0, 322, 5, 22, 22, 405, 4, 20, 2480, 2485, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 13, 13, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Estonian/Latin/Estonia
+ { 79, 66, 92, 0, 0, 359, 370, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 862, 567, 277, 277, 6077, 6077, 6120, 6120, 6147, 6147, 203, 212, 0, 5, 22, 15, 1990, 2, 9, 2490, 2496, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 20, 12, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 3, 10, 4, 6, 6, 12, {71,72,83}, 2, 1, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Ghana
+ { 79, 66, 233, 0, 0, 359, 370, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 862, 567, 10, 0, 6077, 6077, 6120, 6120, 6147, 6147, 203, 212, 0, 5, 22, 127, 2000, 2, 9, 2490, 2508, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 13, 5, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 5, 33, 4, 6, 6, 11, {88,79,70}, 0, 0, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Togo
+ { 80, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0, 6160, 6160, 6244, 6244, 6273, 6273, 206, 217, 0, 5, 22, 11, 2033, 4, 0, 2519, 2525, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 84, 84, 29, 29, 13, 13, 7, 9, 4, 17, 23, 4, 16, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ewondo/Latin/Cameroon
+ { 81, 66, 81, 0, 0, 380, 289, 6, 1, 0, 2, 3, 48, 5, 10, 14, 15, 16, 17, 404, 49, 10, 0, 6286, 6286, 6359, 6386, 6420, 6420, 0, 0, 328, 5, 22, 160, 2049, 4, 20, 2532, 2540, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 2, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Faroe Islands
+ { 81, 66, 65, 0, 0, 380, 289, 6, 1, 0, 2, 3, 48, 5, 10, 14, 15, 16, 17, 404, 49, 10, 0, 6286, 6286, 6359, 6386, 6420, 6420, 0, 0, 328, 5, 22, 160, 2049, 4, 20, 2532, 1161, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 3, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Denmark
+ { 83, 66, 185, 0, 0, 389, 398, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 6433, 6433, 6487, 6487, 6487, 6487, 0, 0, 0, 5, 22, 146, 2060, 2, 9, 2547, 826, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 54, 54, 27, 27, 27, 27, 2, 2, 5, 17, 23, 1, 17, 4, 6, 8, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Filipino/Latin/Philippines
+ { 84, 66, 83, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 10, 15, 15, 17, 17, 698, 885, 213, 213, 6514, 6580, 6660, 6660, 6680, 6680, 213, 226, 331, 336, 353, 22, 405, 4, 0, 2555, 2560, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 4, 66, 80, 20, 20, 13, 13, 3, 3, 5, 17, 23, 1, 4, 5, 0, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Finnish/Latin/Finland
+ { 85, 66, 84, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2573, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/France
+ { 85, 66, 4, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 209, 2077, 4, 20, 2565, 2579, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // French/Latin/Algeria
+ { 85, 66, 23, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 79, 297, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2586, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 7, 26, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Belgium
+ { 85, 66, 25, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2594, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Benin
+ { 85, 66, 37, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2599, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burkina Faso
+ { 85, 66, 38, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 182, 2108, 4, 20, 2565, 1522, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 15, 5, 7, 8, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burundi
+ { 85, 66, 40, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 216, 229, 376, 232, 249, 11, 2123, 4, 20, 2565, 1209, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 5, 4, 6, 17, 23, 4, 16, 5, 7, 8, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Cameroon
+ { 85, 66, 41, 0, 0, 406, 406, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 15, 14, 113, 103, 323, 323, 6693, 6693, 6744, 6744, 6778, 6778, 168, 168, 376, 232, 249, 10, 2139, 4, 20, 2611, 1553, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 27, 9, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 1, 15, 5, 7, 17, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // French/Latin/Canada
+ { 85, 66, 46, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2628, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 25, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Central African Republic
+ { 85, 66, 48, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2653, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Chad
+ { 85, 66, 55, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 12, 2154, 4, 20, 2565, 2658, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Comoros
+ { 85, 66, 56, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2665, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 17, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo - Brazzaville
+ { 85, 66, 57, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2168, 4, 20, 2565, 2682, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 14, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo - Kinshasa
+ { 85, 66, 67, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 3, 2183, 4, 20, 2565, 2696, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 16, 5, 7, 8, 8, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // French/Latin/Djibouti
+ { 85, 66, 73, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2704, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 18, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Equatorial Guinea
+ { 85, 66, 85, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2722, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Guiana
+ { 85, 66, 86, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2738, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 19, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Polynesia
+ { 85, 66, 88, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2757, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Gabon
+ { 85, 66, 97, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2762, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guadeloupe
+ { 85, 66, 102, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 215, 2208, 4, 20, 2565, 2704, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 13, 5, 7, 8, 6, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guinea
+ { 85, 66, 104, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 15, 2221, 4, 20, 2565, 2772, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 16, 5, 7, 8, 5, {72,84,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Haiti
+ { 85, 66, 118, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2777, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 13, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Ivory Coast
+ { 85, 66, 138, 0, 0, 406, 406, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2790, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Luxembourg
+ { 85, 66, 141, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 188, 2237, 4, 20, 2565, 1859, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Madagascar
+ { 85, 66, 145, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 547, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mali
+ { 85, 66, 148, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2800, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Martinique
+ { 85, 66, 149, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 217, 2252, 4, 20, 2565, 2810, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 19, 5, 7, 8, 10, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritania
+ { 85, 66, 150, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 196, 2271, 4, 20, 2565, 2820, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 18, 5, 7, 8, 7, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritius
+ { 85, 66, 151, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2827, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mayotte
+ { 85, 66, 155, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2834, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Monaco
+ { 85, 66, 159, 0, 0, 406, 406, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 168, 168, 376, 232, 249, 0, 2289, 4, 20, 2565, 2840, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 0, 15, 5, 7, 8, 5, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Morocco
+ { 85, 66, 166, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2845, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 18, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/New Caledonia
+ { 85, 66, 170, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 1975, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Niger
+ { 85, 66, 191, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2863, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Reunion
+ { 85, 66, 194, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 198, 2304, 4, 20, 2565, 2091, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Rwanda
+ { 85, 66, 195, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2873, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Barthelemy
+ { 85, 66, 199, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2889, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Martin
+ { 85, 66, 200, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2901, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 24, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Pierre and Miquelon
+ { 85, 66, 206, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2925, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Senegal
+ { 85, 66, 208, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 203, 2318, 4, 20, 2565, 2157, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 21, 5, 7, 8, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Seychelles
+ { 85, 66, 226, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 19, 20, 0, 49, 350, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 0, 2339, 4, 20, 2932, 2947, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 17, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 0, 12, 5, 7, 15, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Switzerland
+ { 85, 66, 227, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 219, 2351, 4, 20, 2565, 2953, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // French/Latin/Syria
+ { 85, 66, 233, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2508, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Togo
+ { 85, 66, 238, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 221, 2365, 4, 20, 2565, 2958, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Tunisia
+ { 85, 66, 252, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 207, 2379, 4, 20, 2565, 2422, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Vanuatu
+ { 85, 66, 256, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2965, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 16, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Wallis and Futuna
+ { 86, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 14, 15, 893, 78, 10, 0, 6791, 6791, 6840, 6840, 6778, 6778, 5, 128, 0, 5, 22, 22, 405, 15, 0, 2981, 2987, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Friulian/Latin/Italy
+ { 87, 66, 206, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 2999, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Senegal
+ { 87, 1, 37, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3017, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 25, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Burkina Faso
+ { 87, 1, 40, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 229, 2463, 15, 0, 3007, 3042, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 8, 44, 5, 0, 10, 16, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Cameroon
+ { 87, 1, 89, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 185, 2507, 15, 0, 3007, 3058, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 29, 5, 0, 10, 14, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Gambia
+ { 87, 1, 92, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 15, 2536, 15, 0, 3007, 3072, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 3, 23, 5, 0, 10, 8, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Ghana
+ { 87, 1, 101, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3080, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 23, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea-Bissau
+ { 87, 1, 102, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 215, 2559, 15, 0, 3007, 3080, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 25, 5, 0, 10, 8, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea
+ { 87, 1, 134, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 10, 2584, 15, 0, 3007, 3103, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 31, 5, 0, 10, 18, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Liberia
+ { 87, 1, 149, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 217, 2615, 15, 0, 3007, 3121, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 37, 5, 0, 10, 16, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Mauritania
+ { 87, 1, 169, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 124, 2652, 15, 0, 3007, 3137, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 33, 5, 0, 10, 18, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Nigeria
+ { 87, 1, 170, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3155, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Niger
+ { 87, 1, 206, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3167, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 16, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Senegal
+ { 87, 1, 209, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 18, 2685, 15, 0, 3007, 3183, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 33, 5, 0, 10, 14, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Sierra Leone
+ { 87, 66, 37, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3197, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 14, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Burkina Faso
+ { 87, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 11, 2718, 4, 0, 2993, 3211, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 4, 18, 5, 0, 6, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Cameroon
+ { 87, 66, 89, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 185, 2736, 4, 0, 2993, 3219, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 13, 5, 0, 6, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Gambia
+ { 87, 66, 92, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 15, 0, 4, 0, 2993, 3225, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 3, 0, 5, 0, 6, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Ghana
+ { 87, 66, 101, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3230, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea-Bissau
+ { 87, 66, 102, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 215, 0, 4, 0, 2993, 3230, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 0, 5, 0, 6, 4, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea
+ { 87, 66, 134, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 10, 2749, 4, 0, 2993, 3242, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Liberia
+ { 87, 66, 149, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 217, 2765, 4, 0, 2993, 3251, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 15, 5, 0, 6, 8, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Mauritania
+ { 87, 66, 169, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 124, 2780, 4, 0, 2993, 3259, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Nigeria
+ { 87, 66, 170, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Niger
+ { 87, 66, 209, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 18, 2796, 4, 0, 2993, 3274, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 18, 5, 0, 6, 11, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Sierra Leone
+ { 88, 66, 246, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 937, 186, 10, 0, 7157, 7157, 7225, 7225, 7252, 7252, 3, 135, 421, 5, 22, 94, 2814, 2, 9, 3285, 3293, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 10, 13, 5, 68, 68, 27, 27, 13, 13, 1, 1, 6, 17, 23, 1, 15, 4, 6, 8, 22, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Gaelic/Latin/United Kingdom
+ { 89, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 7265, 7265, 7297, 7297, 7323, 7323, 0, 0, 0, 5, 22, 15, 50, 2, 9, 3315, 1718, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 32, 32, 26, 26, 13, 13, 2, 2, 4, 17, 23, 3, 10, 4, 6, 2, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ga/Latin/Ghana
+ { 90, 66, 220, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 78, 10, 0, 7336, 7336, 7384, 7384, 1185, 7418, 168, 168, 0, 5, 22, 22, 405, 4, 0, 3317, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 48, 48, 34, 34, 13, 20, 4, 4, 5, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Galician/Latin/Spain
+ { 91, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 7438, 7438, 7503, 7503, 7530, 7530, 0, 0, 0, 5, 22, 147, 2829, 0, 0, 3323, 3330, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Ganda/Latin/Uganda
+ { 92, 33, 77, 0, 0, 0, 0, 6, 0, 74, 2, 3, 4, 5, 10, 14, 15, 16, 17, 985, 78, 61, 76, 7543, 7543, 7543, 7543, 7571, 7571, 0, 0, 0, 5, 22, 0, 105, 15, 0, 3337, 143, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 15, 7, 28, 28, 28, 28, 13, 13, 2, 2, 4, 17, 23, 0, 9, 5, 0, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Geez/Ethiopic/Ethiopia
+ { 92, 33, 74, 0, 0, 0, 0, 6, 0, 74, 2, 3, 4, 5, 10, 14, 15, 16, 17, 985, 78, 61, 76, 7543, 7543, 7543, 7543, 7571, 7571, 0, 0, 0, 5, 22, 6, 0, 15, 0, 3337, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 15, 7, 28, 28, 28, 28, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 4, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Geez/Ethiopic/Eritrea
+ { 93, 35, 90, 0, 0, 455, 455, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 11, 12, 1008, 49, 10, 0, 7584, 7584, 7645, 7645, 7672, 7672, 0, 0, 427, 432, 22, 0, 2848, 4, 0, 3341, 3348, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 13, 5, 61, 61, 27, 27, 13, 13, 2, 2, 5, 29, 23, 1, 12, 5, 0, 7, 10, {71,69,76}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Georgian/Georgian/Georgia
+ { 94, 66, 91, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3365, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Germany
+ { 94, 66, 16, 0, 0, 463, 463, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 15, 0, 3376, 3376, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 24, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Austria
+ { 94, 66, 23, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3400, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Belgium
+ { 94, 66, 117, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3407, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Italy
+ { 94, 66, 136, 0, 0, 463, 463, 6, 0, 17, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 0, 2860, 15, 0, 3358, 3414, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 0, 17, 5, 0, 7, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Liechtenstein
+ { 94, 66, 138, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3427, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Luxembourg
+ { 94, 66, 226, 0, 0, 463, 463, 6, 0, 17, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 0, 2860, 15, 65, 3436, 3436, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 0, 17, 5, 5, 21, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Switzerland
+ { 96, 39, 94, 0, 0, 472, 472, 6, 1, 0, 2, 3, 4, 5, 6, 11, 12, 14, 15, 113, 129, 23, 38, 7791, 7791, 7845, 7845, 7872, 7872, 231, 244, 0, 5, 22, 22, 2877, 4, 0, 3457, 3465, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Greece
+ { 96, 39, 63, 0, 0, 472, 472, 6, 1, 0, 2, 3, 4, 5, 6, 11, 12, 14, 15, 113, 129, 23, 38, 7791, 7791, 7845, 7845, 7872, 7872, 231, 244, 0, 5, 22, 22, 2877, 4, 0, 3457, 3471, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Cyprus
+ { 97, 66, 183, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 7885, 7885, 7885, 7885, 83, 83, 0, 0, 0, 5, 22, 237, 0, 15, 0, 3477, 3484, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 53, 53, 53, 53, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 8, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Guarani/Latin/Paraguay
+ { 98, 40, 110, 0, 0, 481, 481, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 367, 383, 7938, 7938, 7990, 7990, 8021, 8021, 0, 0, 466, 5, 22, 120, 2881, 2, 9, 3492, 3499, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 13, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Gujarati/Gujarati/India
+ { 99, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 8039, 8039, 8100, 8100, 8127, 8127, 235, 248, 0, 5, 22, 176, 991, 2, 9, 3503, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 6, 3, 4, 17, 23, 3, 17, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Gusii/Latin/Kenya
+ { 101, 66, 169, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 10, 0, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 124, 2894, 15, 0, 3511, 3259, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 1, 15, 5, 0, 5, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Nigeria
+ { 101, 4, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 8231, 8231, 8287, 8287, 83, 83, 0, 0, 0, 5, 22, 124, 2909, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 30, 30, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 0, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Arabic/Nigeria
+ { 101, 4, 222, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 8231, 8231, 8287, 8287, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 30, 30, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Hausa/Arabic/Sudan
+ { 101, 66, 92, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 23, 38, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 15, 2915, 15, 0, 3511, 3225, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 3, 13, 5, 0, 5, 4, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Ghana
+ { 101, 66, 170, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 10, 0, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 127, 2928, 15, 0, 3511, 3516, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 5, 29, 5, 0, 5, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Niger
+ { 102, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 8317, 8317, 8373, 8373, 83, 83, 0, 0, 0, 5, 22, 10, 0, 2, 9, 3521, 3535, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 14, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Hawaiian/Latin/United States
+ { 103, 47, 116, 0, 0, 507, 507, 6, 0, 1, 2, 3, 35, 37, 10, 15, 15, 17, 17, 1027, 885, 11, 1, 8393, 8393, 8457, 8457, 8502, 8502, 247, 256, 558, 5, 22, 48, 2957, 70, 77, 3554, 3559, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 8, 12, 4, 64, 64, 45, 45, 20, 20, 6, 5, 4, 17, 23, 1, 7, 7, 9, 5, 5, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Hebrew/Hebrew/Israel
+ { 105, 29, 110, 0, 0, 513, 522, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76, 8522, 8522, 8574, 8574, 8605, 8605, 82, 203, 562, 5, 22, 120, 2964, 2, 0, 3564, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Devanagari/India
+ { 105, 66, 110, 0, 0, 530, 540, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 186, 23, 38, 8623, 8623, 8689, 8689, 8727, 8727, 0, 0, 0, 5, 22, 120, 1381, 2, 0, 3570, 1478, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 66, 66, 38, 38, 21, 21, 2, 2, 5, 17, 23, 1, 12, 4, 0, 13, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Latin/India
+ { 107, 66, 108, 0, 0, 549, 549, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 12, 11, 1045, 1064, 11, 1, 8748, 8748, 8799, 8799, 8817, 8817, 253, 261, 566, 5, 22, 238, 2976, 4, 0, 3583, 3589, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 12, 4, 51, 51, 18, 18, 16, 16, 3, 3, 4, 17, 23, 2, 13, 5, 0, 6, 12, {72,85,70}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Hungarian/Latin/Hungary
+ { 108, 66, 109, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 885, 10, 0, 8833, 8833, 8913, 8913, 8947, 8947, 256, 264, 570, 5, 22, 160, 2989, 4, 0, 3601, 3609, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 80, 80, 34, 34, 13, 13, 4, 4, 4, 17, 23, 3, 13, 5, 0, 8, 6, {73,83,75}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Icelandic/Latin/Iceland
+ { 109, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 3615, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 3, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ido/Latin/world
+ { 110, 66, 169, 0, 0, 557, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 10, 0, 8960, 8960, 9013, 9013, 83, 83, 260, 268, 0, 5, 22, 124, 3002, 2, 9, 3618, 3622, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 53, 53, 28, 28, 13, 13, 7, 7, 4, 17, 23, 1, 5, 4, 6, 4, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Igbo/Latin/Nigeria
+ { 111, 66, 83, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1077, 885, 213, 213, 9041, 9110, 9182, 9182, 83, 9209, 267, 275, 0, 5, 22, 22, 405, 4, 0, 3630, 3641, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 4, 69, 72, 27, 27, 13, 13, 3, 3, 4, 17, 23, 1, 4, 5, 0, 11, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Inari Sami/Latin/Finland
+ { 112, 66, 111, 0, 0, 574, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 212, 212, 9222, 9222, 9264, 9264, 9291, 9291, 0, 0, 0, 5, 22, 186, 3007, 2, 0, 1776, 1776, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 42, 42, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 16, 4, 0, 9, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Indonesian/Latin/Indonesia
+ { 114, 66, 258, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 14, 15, 1095, 394, 10, 0, 9304, 9304, 9360, 9360, 9387, 9387, 0, 0, 0, 5, 22, 0, 0, 15, 58, 3646, 3657, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 7, 11, 5, {0,0,0}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Interlingua/Latin/world
+ { 115, 66, 75, 0, 0, 0, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 180, 10, 0, 9400, 9400, 9451, 9451, 9485, 9485, 270, 278, 574, 232, 249, 22, 405, 15, 86, 3662, 3673, 6, 6, 6, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 13, 5, 51, 51, 34, 34, 13, 13, 9, 8, 7, 17, 23, 1, 4, 5, 6, 11, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Interlingue/Latin/Estonia
+ { 116, 18, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 1121, 61, 76, 9498, 9498, 9498, 9498, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 3680, 3686, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 15, 7, 54, 54, 54, 54, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 6, 4, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Canadian Aboriginal/Canada
+ { 116, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Latin/Canada
+ { 118, 66, 114, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 9552, 9552, 9626, 9626, 9662, 9662, 279, 286, 581, 5, 22, 22, 83, 2, 9, 3690, 3697, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 4, 4, 6, 7, 4, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/Ireland
+ { 118, 66, 246, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 9552, 9552, 9626, 9626, 9662, 9662, 279, 286, 581, 5, 22, 94, 3023, 2, 9, 3690, 3701, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 14, 4, 6, 7, 19, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/United Kingdom
+ { 119, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Italy
+ { 119, 66, 203, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3734, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/San Marino
+ { 119, 66, 226, 0, 0, 414, 414, 6, 0, 17, 2, 3, 4, 5, 10, 11, 12, 19, 20, 0, 49, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 0, 3037, 15, 65, 3720, 3744, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 15, 5, 5, 8, 8, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Switzerland
+ { 119, 66, 253, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3752, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 18, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Vatican City
+ { 120, 53, 120, 183, 183, 183, 183, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 821, 391, 1, 9758, 9758, 9785, 9785, 9785, 9785, 283, 290, 587, 590, 22, 145, 3052, 2, 9, 3770, 3770, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 10, 13, 4, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 3, 4, 6, 3, 2, {74,80,89}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Japanese/Japanese/Japan
+ { 121, 66, 111, 0, 0, 593, 603, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 10, 0, 9798, 9798, 9838, 9838, 9866, 9866, 285, 292, 607, 5, 22, 186, 3007, 15, 0, 3773, 3777, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 40, 40, 28, 28, 13, 13, 4, 5, 4, 17, 23, 2, 16, 5, 0, 4, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Javanese/Latin/Indonesia
+ { 122, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 10, 0, 9879, 9879, 9922, 9922, 83, 83, 0, 0, 0, 5, 22, 124, 3055, 15, 0, 3786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 7, 5, 0, 4, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Jju/Latin/Nigeria
+ { 123, 66, 206, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0, 9949, 9949, 9998, 9998,10025,10025, 0, 0, 0, 5, 22, 127, 3062, 4, 0, 3790, 3795, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 16, 5, 0, 5, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Jola-Fonyi/Latin/Senegal
+ { 124, 66, 43, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1131, 186, 10, 0,10038,10038,10110,10110,10137,10137, 82, 203, 0, 5, 22, 243, 3078, 4, 20, 3802, 3814, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 13, 5, 72, 72, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 18, 5, 7, 12, 10, {67,86,69}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kabuverdianu/Latin/Cape Verde
+ { 125, 66, 4, 0, 0, 612, 620, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 23, 38,10150,10183,10233,10260,10289,10302, 289, 297, 611, 618, 22, 209, 3096, 0, 0, 3824, 3833, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 33, 50, 27, 29, 13, 13, 7, 9, 7, 21, 23, 2, 14, 4, 0, 9, 8, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Kabyle/Latin/Algeria
+ { 126, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 86, 1158, 10, 0,10315,10315,10315,10315,10368,10368, 0, 0, 0, 5, 22, 11, 3110, 15, 0, 3841, 3845, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 53, 53, 53, 53, 20, 20, 2, 2, 4, 17, 23, 4, 9, 5, 0, 4, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kako/Latin/Cameroon
+ { 127, 66, 95, 0, 0, 627, 627, 6, 1, 0, 2, 3, 48, 5, 63, 12, 11, 20, 19, 86, 103, 212, 212,10388,10388,10485,10485,10512,10512, 0, 0, 0, 5, 22, 160, 3119, 2, 92, 3852, 3863, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 97, 97, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 5, 11, 16, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Kalaallisut/Latin/Greenland
+ { 128, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,10525,10525,10577,10577,10604,10604, 296, 306, 0, 5, 22, 176, 3138, 2, 9, 3879, 3887, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 52, 52, 27, 27, 13, 13, 6, 10, 4, 17, 23, 3, 19, 4, 6, 8, 12, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kalenjin/Latin/Kenya
+ { 129, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,10617,10617,10690,10690,10717,10717, 302, 316, 0, 5, 22, 176, 3157, 2, 9, 3899, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 73, 73, 27, 27, 13, 13, 9, 7, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kamba/Latin/Kenya
+ { 130, 56, 110, 0, 0, 638, 650, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 129, 367, 383,10730,10730,10783,10783,10815,10815, 311, 323, 639, 647, 22, 120, 3173, 2, 9, 3906, 3911, 6, 6, 12, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 53, 53, 32, 32, 19, 19, 9, 7, 8, 35, 23, 1, 13, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kannada/Kannada/India
+ { 132, 4, 110, 661, 661, 667, 677, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 549, 567, 61, 76,10834,10834,10885,10885,10934,10934, 320, 330, 0, 5, 22, 120, 3186, 2, 0, 3915, 3920, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 15, 7, 51, 51, 49, 49, 13, 13, 6, 6, 4, 17, 23, 1, 16, 4, 0, 5, 9, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Arabic/India
+ { 132, 29, 110, 0, 0, 686, 695, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 127, 127,10947,10996,10947,11045,11092,11092, 326, 336, 0, 5, 22, 120, 3202, 15, 0, 3929, 3934, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 49, 49, 49, 47, 13, 13, 5, 5, 4, 17, 23, 1, 11, 5, 0, 5, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Devanagari/India
+ { 133, 27, 123, 0, 0, 0, 703, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1168, 49, 10, 0,11105,11105,11160,11160,11180,11180, 0, 0, 196, 682, 699, 244, 3213, 4, 0, 3944, 3954, 6, 6, 6, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 13, 5, 55, 55, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kazakh/Cyrillic/Kazakhstan
+ { 134, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 11, 0, 15, 0, 3963, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 0, 5, 0, 6, 0, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kenyang/Latin/Cameroon
+ { 135, 60, 39, 0, 0, 713, 722, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 61, 76,11193,11238,11284,11284,11323,11323, 0, 0, 722, 5, 22, 245, 3230, 0, 45, 3969, 3974, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 45, 46, 39, 39, 13, 13, 2, 2, 2, 17, 23, 1, 11, 4, 6, 5, 7, {75,72,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Khmer/Khmer/Cambodia
+ { 136, 66, 99, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 246, 0, 15, 0, 3981, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 0, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kiche/Latin/Guatemala
+ { 137, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,11336,11336,11398,11398,11425,11425, 331, 341, 0, 5, 22, 176, 3241, 2, 9, 3988, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 27, 27, 13, 13, 6, 8, 4, 17, 23, 3, 16, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kikuyu/Latin/Kenya
+ { 138, 66, 194, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 16, 17, 163, 103, 10, 0,11438,11438,11521,11521, 83, 83, 0, 0, 0, 5, 22, 198, 0, 15, 0, 3994, 4005, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 83, 83, 34, 34, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 11, 8, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kinyarwanda/Latin/Rwanda
+ { 141, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 61, 76,11555,11555,11555,11555,11605,11623, 337, 349, 724, 5, 22, 120, 2964, 2, 9, 4013, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 50, 50, 50, 50, 18, 19, 4, 4, 4, 17, 23, 1, 12, 4, 6, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Konkani/Devanagari/India
+ { 142, 63, 218, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 404, 127,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 247, 3257, 2, 9, 4019, 4022, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 16, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 6, 4, 6, 3, 4, {75,82,87}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Korean/Korean/South Korea
+ { 142, 63, 50, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 169, 0,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 248, 3263, 2, 9, 4019, 4026, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 13, 5, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 3, 6, 4, 6, 3, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Korean/Korean/China
+ { 142, 63, 174, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 404, 127,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 247, 3269, 2, 9, 4019, 4028, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 16, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 16, 4, 6, 3, 11, {75,80,87}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Korean/Korean/North Korea
+ { 144, 66, 145, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,11682,11682,11735,11735,11762,11762, 343, 355, 0, 5, 22, 127, 3285, 0, 0, 4039, 4054, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 53, 53, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 15, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyraboro Senni/Latin/Mali
+ { 145, 66, 145, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,11775,11775,11827,11827,11762,11762, 343, 355, 0, 5, 22, 127, 3285, 0, 0, 4059, 4054, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 52, 52, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 11, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyra Chiini/Latin/Mali
+ { 146, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 23, 38, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4070, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 0, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kpelle/Latin/Liberia
+ { 146, 66, 102, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 215, 0, 15, 0, 4070, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 6, 0, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kpelle/Latin/Guinea
+ { 148, 66, 239, 0, 0, 738, 738, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1217, 49, 10, 0,11854,11854,11896,11896,11923,11923, 349, 361, 0, 5, 22, 126, 3301, 4, 20, 4076, 4092, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 13, 5, 42, 42, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 12, 5, 7, 16, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kurdish/Latin/Turkey
+ { 149, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 11, 12, 113, 129, 10, 0,11936,11936,12024,12024,12053,12053, 351, 363, 0, 5, 22, 11, 3313, 4, 0, 4099, 4105, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 88, 88, 29, 29, 13, 13, 4, 4, 4, 17, 23, 4, 13, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kwasio/Latin/Cameroon
+ { 150, 27, 128, 0, 0, 745, 745, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1244, 129, 10, 0,12066,12066,12122,12122,12159,12159, 355, 367, 196, 731, 22, 251, 3326, 4, 0, 4112, 4120, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 13, 5, 56, 56, 37, 37, 13, 13, 5, 14, 4, 18, 23, 3, 15, 5, 0, 8, 10, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kyrgyz/Cyrillic/Kyrgyzstan
+ { 151, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38,12172,12172,12172,12172, 83,12258, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4130, 4142, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 86, 86, 86, 86, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 22, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Lakota/Latin/United States
+ { 152, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 0, 186, 10, 0,12271,12271,12333,12333,12368,12368, 360, 381, 0, 5, 22, 121, 3341, 15, 0, 4164, 4172, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 35, 35, 13, 13, 3, 3, 4, 17, 23, 3, 22, 5, 0, 8, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Langi/Latin/Tanzania
+ { 153, 65, 129, 0, 0, 0, 755, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1267, 129, 420, 1,12381,12381,12437,12437,12472,12472, 363, 384, 0, 5, 22, 254, 3363, 2, 65, 4181, 4181, 6, 6, 6, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 27, 4, 56, 56, 35, 35, 16, 16, 8, 8, 4, 17, 23, 1, 7, 4, 5, 3, 3, {76,65,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Lao/Lao/Laos
+ { 154, 66, 253, 0, 0, 406, 406, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1286, 1309, 10, 0,12488,12488,12572,12572, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 0, 4184, 4190, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 84, 84, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 6, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Latin/Latin/Vatican City
+ { 155, 66, 131, 0, 0, 267, 267, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1317, 49, 10, 0,12599,12670,12741,12791,12841,12841, 371, 392, 749, 5, 22, 22, 3370, 4, 0, 4206, 4214, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 8, 13, 5, 71, 71, 50, 50, 13, 13, 14, 11, 5, 17, 23, 1, 4, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Latvian/Latin/Latvia
+ { 158, 66, 57, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3374, 4, 0, 4221, 4228, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 30, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo - Kinshasa
+ { 158, 66, 7, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 255, 3390, 4, 0, 4221, 4258, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Angola
+ { 158, 66, 46, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3406, 4, 0, 4221, 4264, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 26, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Central African Republic
+ { 158, 66, 56, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3406, 4, 0, 4221, 4290, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo - Brazzaville
+ { 160, 66, 137, 0, 0, 773, 773, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 13, 14, 1343, 103, 10, 0,12993,12993,13081,13081,13101,13101, 393, 409, 754, 5, 22, 22, 3422, 4, 0, 4295, 4303, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 27, 10, 13, 5, 88, 88, 20, 20, 13, 13, 9, 6, 6, 17, 23, 1, 5, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lithuanian/Latin/Lithuania
+ { 161, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 4310, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lojban/Latin/world
+ { 162, 66, 91, 0, 0, 781, 781, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 180, 11, 1,13114,13114,13166,13166,13193,13193, 402, 415, 0, 5, 22, 22, 405, 4, 0, 4321, 4335, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 4, 52, 52, 27, 27, 13, 13, 9, 10, 4, 17, 23, 1, 4, 5, 0, 14, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lower Sorbian/Latin/Germany
+ { 163, 66, 91, 0, 0, 267, 267, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 1370, 50, 447, 469,13206,13206,13270,13270, 4510, 4510, 0, 0, 0, 5, 22, 22, 83, 4, 0, 4341, 4355, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 22, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Germany
+ { 163, 66, 165, 0, 0, 267, 267, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 1370, 50, 447, 469,13206,13206,13270,13270, 4510, 4510, 0, 0, 0, 5, 22, 22, 83, 4, 0, 4341, 4366, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 22, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Netherlands
+ { 164, 66, 57, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,13297,13297,13346,13346,13373,13373, 411, 425, 0, 5, 22, 11, 3427, 0, 0, 4378, 4386, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 49, 49, 27, 27, 13, 13, 5, 6, 4, 17, 23, 2, 17, 4, 0, 8, 16, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luba-Katanga/Latin/Congo - Kinshasa
+ { 165, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 4402, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 15, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Lule Sami/Latin/Sweden
+ { 165, 66, 175, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 4402, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 15, 0, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Lule Sami/Latin/Norway
+ { 166, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13386,13386,13454,13454,13481,13481, 416, 431, 0, 5, 22, 176, 3444, 0, 0, 4417, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 68, 68, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 16, 4, 0, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luo/Latin/Kenya
+ { 167, 66, 138, 0, 0, 788, 788, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0,13494,13494,13558,13585, 4510, 4510, 418, 433, 461, 5, 22, 22, 83, 4, 0, 4423, 4423, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 64, 64, 27, 34, 13, 13, 5, 8, 5, 17, 23, 1, 4, 5, 0, 14, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luxembourgish/Latin/Luxembourg
+ { 168, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 13, 14, 18, 16, 0, 186, 10, 0,13619,13619,13693,13693, 83, 83, 168, 168, 0, 5, 22, 176, 3460, 2, 97, 4437, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 74, 74, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luyia/Latin/Kenya
+ { 169, 27, 140, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 0, 180, 10, 0,13713,13713,13766,13766, 3069, 3069, 423, 441, 760, 5, 22, 257, 3476, 4, 0, 4444, 4454, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 53, 53, 34, 34, 13, 13, 7, 5, 5, 17, 23, 4, 16, 5, 0, 10, 18, {77,75,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Macedonian/Cyrillic/Macedonia
+ { 170, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 2, 0, 4472, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Machame/Latin/Tanzania
+ { 171, 29, 110, 0, 0, 513, 522, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,13888,13888, 8574, 8574, 8605, 8605, 88, 83, 0, 5, 22, 120, 2964, 15, 0, 4481, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 63, 63, 31, 31, 18, 18, 3, 4, 4, 17, 23, 1, 12, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Maithili/Devanagari/India
+ { 172, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13951,13951,14009,14009,14036,14036, 435, 455, 0, 5, 22, 261, 0, 15, 0, 4487, 4492, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 58, 58, 27, 27, 13, 13, 8, 10, 4, 17, 23, 3, 0, 5, 0, 5, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Makhuwa-Meetto/Latin/Mozambique
+ { 173, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,14049,14049,14181,14181,14208,14208, 443, 465, 0, 5, 22, 121, 3492, 2, 9, 4502, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5,132,132, 27, 27, 13, 13, 4, 5, 4, 17, 23, 3, 20, 4, 6, 10, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Makonde/Latin/Tanzania
+ { 174, 66, 141, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 103, 10, 0,14221,14221,14280,14280,14313,14313, 0, 0, 0, 5, 22, 188, 1515, 2, 0, 4512, 4520, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 59, 59, 33, 33, 13, 13, 2, 2, 4, 17, 23, 2, 6, 4, 0, 8, 12, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Malagasy/Latin/Madagascar
+ { 175, 74, 110, 0, 0, 798, 811, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1393, 129, 61, 76,14326,14402,14477,14477,14517,14538, 0, 0, 765, 771, 22, 120, 3512, 2, 9, 4532, 4538, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 76, 75, 40, 40, 21, 20, 2, 2, 6, 27, 23, 1, 11, 4, 6, 6, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Malayalam/Malayalam/India
+ { 176, 66, 143, 0, 0, 584, 584, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 79, 23, 38,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 192, 3523, 2, 9, 4544, 1875, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 15, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 6, 6, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Malaysia
+ { 176, 4, 35, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 15, 14, 17, 16, 91, 79, 61, 76,14640,14640,14640,14640, 83, 83, 0, 0, 0, 5, 22, 10, 3539, 2, 9, 4550, 4560, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 7, 15, 7, 34, 34, 34, 34, 13, 13, 2, 2, 4, 17, 23, 1, 10, 4, 6, 10, 5, {66,78,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Arabic/Brunei
+ { 176, 4, 143, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 196, 79, 61, 76,14640,14640,14640,14640, 83, 83, 0, 0, 0, 5, 22, 192, 3549, 2, 9, 4550, 4565, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 15, 7, 34, 34, 34, 34, 13, 13, 2, 2, 4, 17, 23, 2, 13, 4, 6, 10, 6, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Arabic/Malaysia
+ { 176, 66, 35, 0, 0, 584, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 91, 79, 23, 38,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 10, 3562, 2, 9, 4544, 4571, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 7, 15, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 12, 4, 6, 6, 6, {66,78,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Brunei
+ { 176, 66, 111, 0, 0, 584, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 212, 212,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 186, 3007, 2, 0, 4544, 1776, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 0, 6, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Indonesia
+ { 176, 66, 210, 0, 0, 584, 584, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 79, 23, 38,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 10, 3574, 2, 9, 4544, 4577, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 15, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 15, 4, 6, 6, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Singapore
+ { 177, 66, 146, 0, 0, 823, 831, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1411, 186, 10, 0,14674,14674,14736,14736,14763,14783, 0, 0, 0, 5, 22, 22, 3589, 2, 0, 4586, 1891, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 62, 62, 27, 27, 20, 19, 2, 2, 4, 17, 23, 1, 4, 4, 0, 5, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Maltese/Latin/Malta
+ { 179, 9, 110, 0, 0, 838, 838, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 1434, 129, 61, 76,14802,14802,14802,14802,14860,14885, 449, 473, 0, 5, 22, 120, 3593, 15, 0, 4591, 4599, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 58, 58, 58, 58, 25, 29, 4, 5, 4, 17, 23, 1, 14, 5, 0, 8, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Bangla/India
+ { 179, 78, 110, 0, 0, 0, 0, 6, 0, 1, 2, 75, 4, 5, 10, 14, 15, 16, 17, 265, 283, 479, 494, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 120, 0, 15, 0, 4607, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 8, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Meitei Mayek/India
+ { 180, 66, 115, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 86, 78, 10, 0,14914,14914,14970,14970, 83, 83, 168, 168, 0, 5, 22, 94, 0, 2, 0, 4614, 4619, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 56, 56, 29, 29, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 5, 12, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Manx/Latin/Isle of Man
+ { 181, 66, 167, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 23, 38,14999,14999,15046,15046,15073,15073, 0, 0, 0, 5, 22, 10, 3607, 15, 0, 4631, 4636, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 47, 47, 27, 27, 15, 15, 2, 2, 4, 17, 23, 1, 15, 5, 0, 5, 8, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Maori/Latin/New Zealand
+ { 182, 66, 49, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4644, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 10, 0, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mapuche/Latin/Chile
+ { 183, 29, 110, 0, 0, 849, 849, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76,15088,15088,15140,15140, 8605, 8605, 0, 0, 562, 5, 22, 120, 2964, 2, 9, 4654, 664, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Marathi/Devanagari/India
+ { 185, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,15171,15171,13861,13861,14208,14208, 453, 478, 0, 5, 22, 176, 3622, 2, 9, 1275, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 18, 4, 6, 3, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Masai/Latin/Kenya
+ { 185, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,15171,15171,13861,13861,14208,14208, 453, 478, 0, 5, 22, 121, 3640, 2, 9, 1275, 4659, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 3, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Masai/Latin/Tanzania
+ { 186, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 798, 802, 22, 0, 3661, 15, 0, 4667, 4674, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 39, 23, 0, 10, 5, 0, 7, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Mazanderani/Arabic/Iran
+ { 188, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,15228,15228,15278,15278,15305,15305, 462, 484, 0, 5, 22, 176, 991, 2, 9, 4679, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 50, 50, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Meru/Latin/Kenya
+ { 189, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 103, 10, 0,15318,15318,15318,15318,15366,15366, 0, 0, 0, 5, 22, 11, 3671, 15, 0, 4685, 4690, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 48, 48, 48, 48, 20, 20, 2, 2, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Meta/Latin/Cameroon
+ { 190, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 23, 38, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 4697, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 11, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Mohawk/Latin/Canada
+ { 191, 27, 156, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1452, 596, 98, 0,15386,15428,15470,15470,15470,15470, 464, 486, 196, 841, 22, 264, 3676, 15, 0, 4708, 4714, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 35, 10, 15, 5, 42, 42, 20, 20, 20, 20, 4, 4, 4, 17, 23, 1, 13, 5, 0, 6, 6, {77,78,84}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Mongolian/Cyrillic/Mongolia
+ { 191, 83, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 248, 3689, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 0, 0, 0, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Mongolian/Mongolian/China
+ { 191, 83, 156, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1487, 596, 98, 0,15490,15490,15532,15555,15578,15578, 468, 490, 0, 5, 22, 264, 3693, 2, 0, 4720, 4720, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 10, 15, 5, 42, 42, 23, 23, 23, 22, 4, 5, 4, 17, 23, 1, 8, 4, 0, 6, 6, {77,78,84}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Mongolian/Mongolian/Mongolia
+ { 192, 66, 150, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,15601,15601,15648,15648,15674,15674, 0, 0, 0, 5, 22, 196, 3701, 15, 0, 4726, 4740, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 47, 47, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 14, 5, 0, 14, 5, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Morisyen/Latin/Mauritius
+ { 193, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0,15687,15687,15760,15760,15787,15787, 472, 495, 0, 5, 22, 11, 3715, 2, 9, 4745, 4751, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 73, 73, 27, 27, 13, 13, 5, 5, 4, 17, 23, 4, 10, 4, 6, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mundang/Latin/Cameroon
+ { 194, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38,15800,15800,15800,15800, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4758, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,106,106,106,106, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Muscogee/Latin/United States
+ { 195, 66, 162, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,15906,15906,15997,15997,16019,16019, 477, 500, 0, 5, 22, 10, 3725, 2, 0, 4765, 4778, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 91, 91, 22, 22, 13, 13, 7, 5, 4, 17, 23, 1, 15, 4, 0, 13, 8, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nama/Latin/Namibia
+ { 197, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 179, 0, 15, 0, 4786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 11, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Navajo/Latin/United States
+ { 199, 29, 164, 858, 0, 863, 863, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 344, 10, 0,16032,16032,16085,16085,16117,16117, 484, 505, 562, 858, 22, 265, 3740, 15, 0, 4797, 4797, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 4, 14, 5, 0, 6, 5, {78,80,82}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Nepali/Devanagari/Nepal
+ { 199, 29, 110, 858, 0, 863, 863, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 344, 61, 76,16032,16032,16085,16085,16117,16117, 484, 505, 562, 858, 22, 120, 3754, 15, 0, 4797, 664, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 1, 14, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Nepali/Devanagari/India
+ { 201, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1523, 78, 10, 0,16134,16134,16134,16134, 83, 83, 493, 512, 0, 5, 22, 11, 3768, 15, 0, 4803, 4819, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 8, 13, 5,110,110,110,110, 13, 13, 9, 8, 4, 17, 23, 4, 9, 5, 0, 16, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngiemboon/Latin/Cameroon
+ { 202, 66, 40, 870, 870, 881, 897, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 137, 103, 10, 0,16244,16244,16244,16244,16303,16303, 502, 520, 0, 5, 22, 11, 3777, 15, 0, 4826, 4831, 11, 11, 16, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 59, 59, 59, 59, 24, 24, 8, 13, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngomba/Latin/Cameroon
+ { 203, 66, 169, 0, 0, 906, 915, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,16327,16327,16378,16378, 83, 83, 510, 533, 877, 5, 22, 124, 3782, 2, 0, 4838, 4852, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 51, 51, 32, 32, 13, 13, 9, 8, 8, 17, 23, 1, 14, 4, 0, 14, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nigerian Pidgin/Latin/Nigeria
+ { 204, 90, 102, 0, 0, 0, 0, 6, 0, 76, 2, 77, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,16410,16410,16470,16502,16536,16536, 519, 541, 0, 5, 22, 269, 3796, 15, 0, 4860, 4863, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 60, 32, 34, 13, 13, 1, 1, 4, 17, 23, 1, 22, 5, 0, 3, 6, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Nko/Nko/Guinea
+ { 205, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 4869, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Northern Luri/Arabic/Iran
+ { 205, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 61, 76, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 43, 0, 15, 0, 4869, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 5, 0, 11, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Northern Luri/Arabic/Iraq
+ { 206, 66, 175, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 163, 103, 10, 0,16549,16549,16623,16623,16655,16655, 520, 542, 0, 5, 22, 160, 3818, 4, 0, 4880, 4895, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Norway
+ { 206, 66, 83, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 113, 49, 10, 0,16668,16668,16737,16737,16757,16757, 531, 185, 0, 5, 22, 22, 405, 4, 0, 4880, 4900, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 69, 69, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Finland
+ { 206, 66, 225, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 163, 103, 10, 0,16549,16549,16623,16623,16655,16655, 520, 542, 0, 5, 22, 160, 3832, 4, 0, 4880, 4906, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Sweden
+ { 207, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,16770,16770,16833,16833,16859,16859, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 4928, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 16, 12, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Northern Sotho/Latin/South Africa
+ { 208, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,16872,16872,16921,16921,16948,16948, 0, 0, 0, 5, 22, 179, 3846, 2, 9, 4940, 2434, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 10, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // North Ndebele/Latin/Zimbabwe
+ { 209, 66, 175, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 10, 0, 4788, 4788,16961,16961, 4874, 4874, 168, 168, 0, 5, 22, 160, 3863, 15, 58, 4950, 4962, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Norway
+ { 209, 66, 224, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 10, 0, 4788, 4788,16961,16961, 4874, 4874, 168, 168, 0, 5, 22, 160, 3863, 15, 58, 4950, 4967, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 21, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Svalbard and Jan Mayen
+ { 210, 66, 175, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 502, 0,16995,16995,17045,17072, 4874, 4874, 533, 555, 0, 5, 22, 160, 3863, 4, 0, 4988, 5001, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 19, 5, 50, 50, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 0, 13, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Nynorsk/Latin/Norway
+ { 211, 66, 219, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 187, 521, 38,17099,17099,17177,17177,17214,17214, 537, 559, 0, 5, 22, 94, 0, 2, 9, 5006, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 15, 7, 78, 78, 37, 37, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 9, 0, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nuer/Latin/South Sudan
+ { 212, 66, 142, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 23, 38,17227,17227,17293,17293, 83, 83, 0, 0, 0, 5, 22, 0, 1521, 15, 0, 5015, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 66, 66, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 15, 5, 0, 6, 0, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nyanja/Latin/Malawi
+ { 213, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 4053, 4053, 4126, 4126, 4153, 4153, 0, 0, 0, 5, 22, 147, 805, 2, 0, 5021, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 10, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Nyankole/Latin/Uganda
+ { 214, 66, 84, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 1555, 79, 10, 536,17320,17320,17320,17320,17376,17376, 0, 0, 376, 232, 249, 22, 405, 0, 45, 5031, 807, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 7, 13, 6, 56, 56, 56, 56, 20, 20, 2, 2, 6, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Occitan/Latin/France
+ { 214, 66, 220, 0, 0, 414, 414, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 79, 99, 1,17396,17396,17453,17453,17480,17480, 0, 0, 376, 232, 249, 22, 405, 0, 0, 5031, 5038, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 14, 4, 57, 57, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 4, 4, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Occitan/Latin/Spain
+ { 215, 91, 110, 0, 0, 923, 931, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76,17493,17493,17546,17546,17578,17578, 0, 0, 885, 5, 22, 120, 3876, 2, 9, 5045, 5050, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 53, 53, 32, 32, 17, 17, 2, 2, 5, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Odia/Odia/India
+ { 220, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,17595,17595,17649,17649, 83, 83, 539, 561, 0, 5, 22, 1, 3888, 2, 0, 5054, 5060, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 17, 4, 0, 6, 10, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Ethiopia
+ { 220, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 0,17595,17595,17649,17649,17676,17676, 539, 561, 0, 5, 22, 176, 0, 2, 0, 5054, 5070, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 6, 8, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Kenya
+ { 221, 101, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76,17689,17689,17689,17689, 83,17869, 0, 0, 0, 5, 22, 10, 0, 15, 0, 5078, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,180,180,180,180, 13, 20, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Osage/Osage/United States
+ { 222, 27, 90, 0, 0, 938, 938, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1576, 49, 10, 0,17889,17949,18009,18036,18063,18063, 541, 563, 0, 5, 22, 0, 3905, 15, 0, 5090, 5094, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 11, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Georgia
+ { 222, 27, 193, 0, 0, 938, 938, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1576, 49, 10, 0,17889,17949,18009,18036,18063,18063, 541, 563, 0, 5, 22, 133, 3908, 15, 0, 5090, 5105, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Russia
+ { 226, 66, 62, 0, 0, 143, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 10, 0,18076,18076,18076,18076,18138,18138, 0, 0, 0, 5, 22, 0, 3911, 15, 0, 5111, 5121, 6, 6, 7, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 62, 62, 20, 20, 2, 2, 4, 17, 23, 0, 6, 5, 0, 10, 6, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Papiamento/Latin/Curacao
+ { 226, 66, 13, 0, 0, 143, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 10, 0,18076,18076,18076,18076,18138,18138, 0, 0, 0, 5, 22, 0, 3917, 15, 0, 5111, 1227, 6, 6, 7, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 62, 62, 20, 20, 2, 2, 4, 17, 23, 0, 15, 5, 0, 10, 5, {65,87,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Papiamento/Latin/Aruba
+ { 227, 4, 1, 661, 661, 947, 956, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1599, 505, 99, 1,18158,18158,18158,18158, 83, 83, 556, 578, 890, 5, 22, 270, 3932, 2, 9, 5127, 5131, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 14, 4, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 1, 6, 4, 6, 4, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Pashto/Arabic/Afghanistan
+ { 227, 4, 178, 661, 661, 947, 956, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1599, 505, 61, 76,18158,18158,18158,18158, 83, 83, 556, 578, 890, 5, 22, 196, 3938, 2, 9, 5127, 5140, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 15, 7, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 2, 15, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Pashto/Arabic/Pakistan
+ { 228, 4, 112, 964, 964, 971, 979, 67, 21, 22, 23, 40, 82, 37, 44, 11, 12, 19, 20, 113, 505, 99, 1,18196,18196,18196,18196,18244,18244, 560, 582, 798, 5, 22, 271, 3953, 103, 109, 5147, 4674, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 14, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 4, 10, 6, 8, 5, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Persian/Arabic/Iran
+ { 228, 4, 1, 964, 964, 971, 979, 67, 21, 22, 23, 40, 82, 37, 44, 11, 12, 19, 20, 113, 505, 99, 1,18196,18196,18196,18196,18244,18244, 560, 582, 798, 5, 22, 270, 3963, 15, 109, 5152, 5131, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 14, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 1, 16, 5, 8, 3, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Persian/Arabic/Afghanistan
+ { 230, 66, 187, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 50, 10, 0,18257,18257,18315,18315,18348,18361, 0, 0, 311, 5, 22, 275, 3979, 4, 20, 5155, 5161, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 9, 13, 5, 58, 58, 33, 33, 13, 13, 2, 2, 5, 17, 23, 2, 12, 5, 7, 6, 6, {80,76,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Polish/Latin/Poland
+ { 231, 66, 32, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 186, 10, 0,18374,18374,18452,18452,18486,18486, 0, 0, 0, 5, 22, 9, 3991, 15, 0, 5167, 5176, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 13, 5, 78, 78, 34, 34, 13, 13, 2, 2, 5, 17, 23, 2, 15, 5, 0, 9, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Brazil
+ { 231, 66, 7, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 255, 4006, 4, 20, 5167, 5182, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 15, 5, 7, 9, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Angola
+ { 231, 66, 43, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 243, 4021, 4, 20, 5167, 5188, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 20, 5, 7, 9, 10, {67,86,69}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Cape Verde
+ { 231, 66, 73, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 11, 4041, 4, 20, 5167, 5198, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 17, 5, 7, 9, 16, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Equatorial Guinea
+ { 231, 66, 101, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 127, 4058, 4, 20, 5167, 5214, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 5, 18, 5, 7, 9, 12, {88,79,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Guinea-Bissau
+ { 231, 66, 138, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 22, 405, 4, 20, 5167, 5226, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 9, 10, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Luxembourg
+ { 231, 66, 139, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 23, 38,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 151, 4076, 4, 20, 5167, 5236, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 15, 5, 7, 9, 19, {77,79,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Macao
+ { 231, 66, 160, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 261, 4091, 4, 20, 5167, 5255, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 19, 5, 7, 9, 10, {77,90,78}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Mozambique
+ { 231, 66, 188, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 22, 405, 4, 20, 5265, 5282, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 17, 8, {69,85,82}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Portugal
+ { 231, 66, 204, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 277, 4110, 4, 20, 5167, 5290, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 28, 5, 7, 9, 19, {83,84,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Sao Tome and Principe
+ { 231, 66, 226, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 0, 4138, 4, 20, 5167, 5309, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 0, 12, 5, 7, 9, 5, {67,72,70}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Switzerland
+ { 231, 66, 232, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 179, 4150, 4, 20, 5167, 5314, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 24, 5, 7, 9, 11, {85,83,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Timor-Leste
+ { 232, 66, 187, 0, 0, 986, 986, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 13, 14, 1619, 49, 10, 0,18547,18547,18615,18615,18642,18642, 577, 598, 0, 5, 22, 275, 0, 4, 0, 5325, 5334, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 68, 68, 27, 27, 13, 13, 10, 14, 4, 17, 23, 2, 0, 5, 0, 9, 4, {80,76,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Prussian/Latin/Poland
+ { 233, 41, 110, 0, 0, 994, 994, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,18655,18655,18711,18711,18746,18746, 587, 612, 895, 5, 22, 120, 4174, 15, 0, 5338, 5344, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 35, 35, 22, 22, 6, 6, 4, 17, 23, 1, 11, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Punjabi/Gurmukhi/India
+ { 233, 4, 178, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 786, 186, 61, 76,18768,18768,18768,18768, 83, 83, 0, 0, 0, 5, 22, 78, 4185, 15, 0, 5348, 5140, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 10, 15, 7, 36, 36, 36, 36, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Punjabi/Arabic/Pakistan
+ { 234, 66, 184, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 23, 38,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 279, 4191, 15, 0, 5354, 5362, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 11, 5, 0, 8, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Quechua/Latin/Peru
+ { 234, 66, 28, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 23, 38,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 281, 4202, 15, 0, 5354, 5366, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 9, 5, 0, 8, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Bolivia
+ { 234, 66, 70, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 23, 38,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 10, 4211, 15, 0, 5354, 5373, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 15, 5, 0, 8, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Ecuador
+ { 235, 66, 192, 0, 0, 1003, 1003, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 49, 10, 0,18896,18896,18943,18943, 6778, 6778, 168, 168, 899, 5, 22, 283, 4226, 4, 20, 5380, 5386, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 47, 47, 33, 33, 13, 13, 4, 4, 4, 17, 23, 3, 12, 5, 7, 6, 7, {82,79,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Romania
+ { 235, 66, 154, 0, 0, 1003, 1003, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 49, 10, 0,18896,18896,18976,18976,19003,19003, 168, 168, 899, 5, 22, 18, 4238, 4, 20, 5380, 5393, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 47, 47, 27, 27, 15, 15, 4, 4, 4, 17, 23, 1, 15, 5, 7, 6, 17, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Moldova
+ { 236, 66, 226, 0, 0, 414, 414, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 1646, 394, 10, 0,19018,19018,19073,19073,19095,19095, 0, 0, 0, 5, 22, 0, 4253, 4, 0, 5410, 5419, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 55, 55, 22, 22, 13, 13, 2, 2, 5, 17, 23, 0, 13, 5, 0, 9, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Romansh/Latin/Switzerland
+ { 237, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,19108,19108,19172,19172,14208,14208, 593, 618, 0, 5, 22, 121, 4266, 2, 0, 5425, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 64, 64, 28, 28, 13, 13, 8, 7, 4, 17, 23, 3, 18, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rombo/Latin/Tanzania
+ { 238, 66, 38, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 15, 15, 17, 17, 113, 129, 10, 0,19200,19200,19288,19288, 83, 83, 601, 625, 0, 5, 22, 182, 4284, 0, 0, 5434, 5442, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 88, 88, 33, 33, 13, 13, 5, 5, 4, 17, 23, 3, 20, 4, 0, 8, 8, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Rundi/Latin/Burundi
+ { 239, 27, 193, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 133, 4304, 4, 0, 5450, 5457, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 16, 5, 0, 7, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Russia
+ { 239, 27, 22, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 1, 4320, 4, 0, 5450, 618, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {66,89,78}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Belarus
+ { 239, 27, 123, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 244, 4337, 4, 0, 5450, 5463, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 15, 5, 0, 7, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kazakhstan
+ { 239, 27, 128, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 251, 4352, 4, 0, 5450, 5472, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 3, 14, 5, 0, 7, 8, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kyrgyzstan
+ { 239, 27, 154, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 18, 4366, 4, 0, 5450, 5480, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 14, 5, 0, 7, 7, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Moldova
+ { 239, 27, 244, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 286, 4380, 4, 0, 5450, 5487, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 7, 7, {85,65,72}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Russian/Cyrillic/Ukraine
+ { 240, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 0, 0, 5494, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rwa/Latin/Tanzania
+ { 241, 66, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38,19415,19415,19470,19470,19497,19497, 0, 0, 0, 5, 22, 6, 0, 2, 0, 5500, 34, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 55, 55, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 4, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Saho/Latin/Eritrea
+ { 242, 27, 193, 0, 0, 1011, 1011, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1669, 344, 10, 0,19510,19510,19580,19580,19600,19600, 606, 630, 903, 908, 22, 133, 4397, 4, 0, 5504, 5513, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 6, 13, 5, 70, 70, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 20, 5, 0, 9, 9, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sakha/Cyrillic/Russia
+ { 243, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,19613,19613,19717,19717,19744,19744, 608, 632, 0, 5, 22, 176, 4417, 2, 9, 5522, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5,104,104, 27, 27, 13, 13, 7, 5, 4, 17, 23, 3, 18, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Samburu/Latin/Kenya
+ { 245, 66, 46, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0,19757,19757,19822,19822,19849,19849, 615, 637, 0, 5, 22, 11, 4435, 2, 65, 5530, 5535, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 18, 4, 5, 5, 22, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Sango/Latin/Central African Republic
+ { 246, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,19862,19862,19921,19921,19948,19948, 617, 639, 0, 5, 22, 121, 4453, 0, 0, 5557, 5566, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 27, 27, 13, 13, 9, 9, 4, 17, 23, 3, 18, 4, 0, 9, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Sangu/Latin/Tanzania
+ { 247, 29, 110, 0, 0, 1022, 1032, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,19961,19961, 8574, 8574, 8605, 8605, 484, 505, 0, 5, 22, 120, 4471, 15, 0, 5575, 5587, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 66, 66, 31, 31, 18, 18, 9, 7, 4, 17, 23, 1, 15, 5, 0, 12, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Sanskrit/Devanagari/India
+ { 248, 93, 110, 0, 0, 0, 0, 6, 0, 1, 2, 84, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,20027,20027,20068,20068,20093,20093, 626, 648, 0, 5, 22, 120, 4486, 15, 0, 5592, 5599, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 41, 41, 25, 25, 13, 13, 5, 5, 4, 17, 23, 1, 16, 5, 0, 7, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Ol Chiki/India
+ { 248, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 120, 0, 15, 0, 5605, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 8, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Devanagari/India
+ { 249, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1699, 186, 10, 0,20106,20106,20160,20160,20187,20187, 0, 0, 0, 5, 22, 22, 4502, 4, 0, 5613, 813, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 10, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sardinian/Latin/Italy
+ { 251, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 0,20200,20200,20254,20254,20281,20281, 0, 0, 0, 5, 22, 261, 4506, 0, 0, 5618, 5255, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 21, 4, 0, 4, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sena/Latin/Mozambique
+ { 252, 27, 207, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20294,20294,20345,20345, 2891, 2891, 0, 0, 925, 5, 22, 0, 4527, 4, 20, 5622, 5628, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 0, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Serbia
+ { 252, 27, 29, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0, 2809, 2809, 2864, 2864, 2891, 2891, 104, 653, 925, 5, 22, 137, 4539, 4, 20, 5622, 713, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 55, 55, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Bosnia and Herzegovina
+ { 252, 27, 126, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20294,20294,20345,20345, 2891, 2891, 0, 0, 925, 5, 22, 22, 4579, 4, 20, 5622, 5634, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Kosovo
+ { 252, 27, 157, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20372,20372,20345,20345, 2891, 2891, 104, 653, 925, 5, 22, 22, 4579, 4, 20, 5622, 5640, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 54, 54, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Montenegro
+ { 252, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0, 2699, 2699, 2756, 2756, 2783, 2783, 631, 661, 218, 5, 22, 135, 597, 4, 20, 5649, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 57, 57, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Bosnia and Herzegovina
+ { 252, 66, 126, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20426,20426,20479,20479, 2783, 2783, 0, 0, 218, 5, 22, 22, 4583, 4, 20, 5649, 5655, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Kosovo
+ { 252, 66, 157, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20506,20506,20479,20479, 2783, 2783, 631, 661, 218, 5, 22, 22, 4583, 4, 20, 5649, 5661, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 56, 56, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Montenegro
+ { 252, 66, 207, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20426,20426,20479,20479, 2783, 2783, 0, 0, 218, 5, 22, 0, 4587, 4, 20, 5649, 5670, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 0, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Serbia
+ { 253, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,20562,20562,20624,20624,20651,20651, 642, 669, 0, 5, 22, 121, 4599, 0, 0, 5676, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 27, 27, 13, 13, 5, 8, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Shambala/Latin/Tanzania
+ { 254, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 163, 103, 10, 0,20664,20664,20718,20718,20745,20745, 0, 0, 0, 5, 22, 179, 4619, 2, 9, 5685, 2434, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 15, 4, 6, 8, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Shona/Latin/Zimbabwe
+ { 255, 141, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,20758,20758,20785,20785,20805,20805, 647, 677, 0, 5, 22, 150, 0, 15, 0, 5693, 5696, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 3, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sichuan Yi/Yi/China
+ { 256, 66, 117, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,20818,20818,20818,20818, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 5698, 3728, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 62, 62, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 9, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sicilian/Latin/Italy
+ { 257, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38,20880,20880,20930,20930,20957,20957, 0, 0, 0, 5, 22, 1, 0, 2, 0, 5707, 5718, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 50, 50, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 4, 0, 11, 11, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sidamo/Latin/Ethiopia
+ { 258, 66, 187, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 12, 11, 0, 49, 10, 0,20970,20970,21030,21030,13193,13193, 649, 679, 311, 5, 22, 275, 0, 15, 0, 5729, 5161, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 60, 27, 27, 13, 13, 11, 11, 5, 17, 23, 2, 0, 5, 0, 7, 6, {80,76,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Silesian/Latin/Poland
+ { 259, 4, 178, 0, 0, 1041, 1049, 67, 21, 22, 23, 25, 26, 28, 59, 14, 15, 16, 17, 549, 103, 61, 76,21057,21057,21057,21057,21091,21091, 660, 690, 932, 938, 22, 196, 4634, 4, 0, 5736, 5740, 6, 6, 8, 7, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 18, 10, 15, 7, 34, 34, 34, 34, 30, 30, 11, 11, 6, 25, 23, 2, 12, 5, 0, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sindhi/Arabic/Pakistan
+ { 259, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76,21121,21148,21189,21211,21239,21239, 671, 701, 0, 5, 22, 120, 4646, 15, 0, 5747, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 27, 41, 22, 28, 20, 20, 8, 6, 4, 17, 23, 1, 17, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Sindhi/Devanagari/India
+ { 260, 119, 221, 0, 0, 1056, 1065, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 212, 212,21259,21259,21320,21320,21358,21358, 679, 707, 963, 968, 22, 287, 4663, 2, 9, 5753, 5758, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 38, 38, 18, 18, 5, 4, 5, 42, 23, 3, 17, 4, 6, 5, 11, {76,75,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sinhala/Sinhala/Sri Lanka
+ { 261, 66, 83, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 5769, 5779, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 10, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Skolt Sami/Latin/Finland
+ { 262, 66, 212, 0, 0, 781, 282, 6, 1, 9, 2, 3, 4, 5, 6, 13, 14, 18, 16, 698, 423, 11, 1,21376,21376,21427,21427,21447,21447, 0, 0, 311, 5, 22, 22, 405, 4, 20, 5791, 5801, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 4, 51, 51, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovak/Latin/Slovakia
+ { 263, 66, 213, 0, 0, 1073, 1073, 6, 1, 0, 2, 3, 48, 5, 6, 13, 14, 18, 16, 404, 423, 10, 0,21460,21460,21511,21511,21545,21545, 172, 711, 50, 5, 22, 22, 4680, 4, 20, 5810, 5821, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 51, 51, 34, 34, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 11, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovenian/Latin/Slovenia
+ { 264, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,21558,21558,21622,21622,21656,21656, 684, 715, 0, 5, 22, 147, 2829, 4, 0, 5830, 3330, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 64, 64, 34, 34, 13, 13, 6, 6, 4, 17, 23, 3, 19, 5, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Soga/Latin/Uganda
+ { 265, 66, 215, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 93, 4684, 2, 9, 5837, 5845, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 1, 20, 4, 6, 8, 10, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Somali/Latin/Somalia
+ { 265, 66, 67, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 3, 4704, 2, 9, 5837, 5855, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 13, 4, 6, 8, 7, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Somali/Latin/Djibouti
+ { 265, 66, 77, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 1, 4717, 2, 9, 5837, 5862, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 2, 15, 4, 6, 8, 8, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Ethiopia
+ { 265, 66, 124, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 0,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 176, 4732, 2, 9, 5837, 1307, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 15, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Kenya
+ { 266, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 25, 26, 28, 59, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 5870, 0, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Southern Kurdish/Arabic/Iran
+ { 266, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 25, 26, 28, 59, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 5870, 0, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Southern Kurdish/Arabic/Iraq
+ { 267, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 5881, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 19, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Southern Sami/Latin/Sweden
+ { 267, 66, 175, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 5881, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 19, 0, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Southern Sami/Latin/Norway
+ { 268, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,21760,21760,21820,21820, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 60, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Southern Sotho/Latin/South Africa
+ { 268, 66, 133, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 23, 38,21760,21760,21820,21820, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 60, 60, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Southern Sotho/Latin/Lesotho
+ { 269, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,21846,21846,21911,21911, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4940, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 65, 65, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 10, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // South Ndebele/Latin/South Africa
+ { 270, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 17, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Spain
+ { 270, 66, 11, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4747, 15, 58, 5900, 5917, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 14, 5, 7, 7, 9, {65,82,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Argentina
+ { 270, 66, 24, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 0,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4761, 2, 0, 5900, 5926, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 13, 5, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 14, 4, 0, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Belize
+ { 270, 66, 28, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 281, 4775, 2, 0, 5900, 5366, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 9, 4, 0, 7, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Bolivia
+ { 270, 66, 32, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 0,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 9, 4784, 2, 0, 5900, 5176, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 13, 5, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 2, 14, 4, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Brazil
+ { 270, 66, 42, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 5932, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Canary Islands
+ { 270, 66, 47, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 5940, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 15, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Ceuta and Melilla
+ { 270, 66, 49, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 394, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4798, 2, 65, 5900, 5955, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 12, 4, 5, 7, 5, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Chile
+ { 270, 66, 54, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 23, 38,21937,21937,21989,21989, 9387,22016, 132, 128, 0, 5, 22, 10, 4810, 15, 0, 5900, 5960, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 15, 5, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Colombia
+ { 270, 66, 59, 0, 0, 68, 68, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 290, 4825, 2, 0, 5900, 5968, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 19, 4, 0, 7, 10, {67,82,67}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Costa Rica
+ { 270, 66, 61, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4844, 2, 0, 5900, 5978, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 11, 4, 0, 7, 4, {67,85,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Cuba
+ { 270, 66, 69, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 291, 4855, 2, 9, 5900, 5982, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 6, 7, 20, {68,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Dominican Republic
+ { 270, 66, 70, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 65, 5900, 5373, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 5, 7, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Ecuador
+ { 270, 66, 72, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 0, 5900, 6002, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/El Salvador
+ { 270, 66, 73, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 11, 4890, 2, 0, 5900, 6013, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 28, 4, 0, 7, 17, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Equatorial Guinea
+ { 270, 66, 99, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 246, 4918, 2, 0, 5900, 6030, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 7, 4, 0, 7, 9, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Guatemala
+ { 270, 66, 106, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1730, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 18, 4925, 2, 0, 5900, 6039, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 17, 4, 0, 7, 8, {72,78,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Honduras
+ { 270, 66, 130, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 0, 0, 2, 0, 6047, 6070, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 0, 0, 4, 0, 23, 13, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Latin America
+ { 270, 66, 152, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 78, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4942, 2, 0, 6083, 6100, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 13, 4, 0, 17, 6, {77,88,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Mexico
+ { 270, 66, 168, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 294, 4955, 2, 0, 5900, 6106, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 20, 4, 0, 7, 9, {78,73,79}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Nicaragua
+ { 270, 66, 181, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 1121, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 296, 4975, 2, 0, 5900, 6115, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 0, 7, 6, {80,65,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Panama
+ { 270, 66, 183, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 299, 4990, 15, 86, 5900, 6121, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 17, 5, 6, 7, 8, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Paraguay
+ { 270, 66, 184, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 279, 5007, 15, 0, 5900, 5362, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 11, 5, 0, 7, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Peru
+ { 270, 66, 185, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 146, 5018, 4, 0, 5900, 6129, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 0, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Spanish/Latin/Philippines
+ { 270, 66, 189, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 1121, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 0, 5900, 2080, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Puerto Rico
+ { 270, 66, 248, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4870, 2, 0, 5900, 6138, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 20, 4, 0, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/United States
+ { 270, 66, 250, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 5031, 15, 58, 5900, 6152, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 7, 7, 7, {85,89,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Uruguay
+ { 270, 66, 254, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 302, 5044, 2, 65, 5900, 6159, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 16, 4, 5, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Venezuela
+ { 271, 135, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 10, 0,22029,22029,22076,22076, 83, 83, 692, 723, 0, 5, 22, 0, 5060, 0, 0, 6168, 6176, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 8, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Standard Moroccan Tamazight/Tifinagh/Morocco
+ { 272, 66, 111, 0, 0, 1090, 1103, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 213, 213,22105,22105,22148,22148, 9291, 9291, 0, 0, 0, 5, 22, 186, 5074, 2, 0, 6182, 1776, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 4, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 15, 4, 0, 10, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sundanese/Latin/Indonesia
+ { 273, 66, 230, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 121, 3492, 15, 0, 6192, 2268, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 20, 5, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Tanzania
+ { 273, 66, 57, 0, 0, 566, 566, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 11, 5089, 15, 0, 6192, 6201, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 2, 16, 5, 0, 9, 32, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Congo - Kinshasa
+ { 273, 66, 124, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 176, 991, 15, 0, 6192, 1307, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 17, 5, 0, 9, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swahili/Latin/Kenya
+ { 273, 66, 243, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 147, 5105, 15, 0, 6192, 983, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 18, 5, 0, 9, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Swahili/Latin/Uganda
+ { 274, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,22175,22175,22242,22242, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6233, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 67, 67, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swati/Latin/South Africa
+ { 274, 66, 76, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 23, 38,22175,22175,22242,22242, 83, 83, 0, 0, 0, 5, 22, 155, 0, 2, 0, 6233, 6240, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 67, 67, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 8, {83,90,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swati/Latin/Eswatini
+ { 275, 66, 225, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 10, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 160, 5123, 4, 0, 6248, 6255, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 2, 12, 5, 0, 7, 7, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Sweden
+ { 275, 66, 2, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 10, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 22, 405, 4, 0, 6248, 6262, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Aland Islands
+ { 275, 66, 83, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 10, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 22, 405, 4, 0, 6248, 1698, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Finland
+ { 276, 66, 226, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 10, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 0, 5135, 4, 0, 6267, 6267, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 0, 16, 5, 0, 16, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Switzerland
+ { 276, 66, 84, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 10, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 22, 83, 4, 0, 6267, 6283, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 1, 4, 5, 0, 16, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/France
+ { 276, 66, 136, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 10, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 0, 5135, 4, 0, 6267, 6293, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 0, 16, 5, 0, 16, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Liechtenstein
+ { 277, 123, 113, 1124, 1124, 1124, 1124, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 1757, 395, 61, 76,22434,22434,22486,22486,22515,22515, 712, 744, 1084, 5, 22, 0, 0, 15, 0, 6306, 6312, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 15, 7, 52, 52, 29, 29, 13, 13, 4, 4, 4, 17, 23, 0, 0, 5, 0, 6, 4, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Syriac/Syriac/Iraq
+ { 277, 123, 227, 1124, 1124, 1124, 1124, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 1757, 395, 61, 76,22434,22434,22486,22486,22515,22515, 712, 744, 1084, 5, 22, 99, 0, 15, 0, 6306, 6316, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 15, 7, 52, 52, 29, 29, 13, 13, 4, 4, 4, 17, 23, 5, 0, 5, 0, 6, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Syriac/Syriac/Syria
+ { 278, 135, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 10, 0,22528,22528,22076,22076, 83, 83, 692, 723, 0, 5, 22, 0, 5060, 0, 0, 6321, 6176, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 46, 46, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Tifinagh/Morocco
+ { 278, 66, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 10, 0,22574,22574,22621,22621, 83, 83, 716, 748, 0, 5, 22, 0, 5151, 0, 0, 6328, 6338, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 10, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Latin/Morocco
+ { 280, 127, 255, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 306, 0, 15, 0, 6344, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 4, 0, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tai Dam/Tai Viet/Vietnam
+ { 281, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,22650,22650,22754,22754,22781,22781, 722, 756, 0, 5, 22, 176, 991, 2, 9, 6348, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5,104,104, 27, 27, 13, 13, 10, 10, 4, 17, 23, 3, 17, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Taita/Latin/Kenya
+ { 282, 27, 229, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 12, 11, 16, 17, 786, 78, 10, 0,22794,22794,22848,22848,22875,22875, 0, 0, 0, 5, 22, 307, 5165, 4, 0, 6355, 6361, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 6, 5, 0, 6, 10, {84,74,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tajik/Cyrillic/Tajikistan
+ { 283, 129, 110, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 127, 127,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 120, 5171, 2, 9, 6371, 6376, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 1, 13, 4, 6, 5, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Tamil/Tamil/India
+ { 283, 129, 143, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 127, 127,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 192, 5184, 2, 9, 6371, 6383, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 2, 17, 4, 6, 5, 7, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Malaysia
+ { 283, 129, 210, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 127, 127,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 10, 5201, 2, 9, 6371, 6390, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 1, 17, 4, 6, 5, 11, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Singapore
+ { 283, 129, 221, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 10, 0,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 311, 5218, 2, 9, 6371, 6401, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 3, 13, 4, 6, 5, 6, {76,75,82}, 2, 1, 1, 6, 7, 1, 2, 3 }, // Tamil/Tamil/Sri Lanka
+ { 284, 66, 228, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 103, 23, 38,22993,22993,23164,23164,23191,23191, 0, 0, 0, 5, 22, 314, 5231, 15, 0, 6407, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 15, 7,171,171, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 11, 5, 0, 12, 0, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Taroko/Latin/Taiwan
+ { 285, 66, 170, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,11682,11682,11735,11735,11762,11762, 732, 774, 0, 5, 22, 127, 3285, 0, 0, 6419, 6432, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 53, 53, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 13, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tasawaq/Latin/Niger
+ { 286, 27, 193, 0, 0, 1143, 1143, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1775, 49, 11, 1,23204,23204,23259,23259,23294,23294, 0, 0, 0, 5, 22, 133, 5242, 4, 0, 6437, 5457, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 12, 4, 55, 55, 35, 35, 13, 13, 2, 2, 4, 17, 23, 1, 11, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tatar/Cyrillic/Russia
+ { 287, 131, 110, 0, 0, 1152, 1152, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1798, 394, 61, 76,23307,23307,23366,23366,23397,23397, 0, 0, 1095, 1102, 22, 120, 5253, 2, 9, 6442, 6448, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 59, 59, 31, 31, 17, 17, 2, 2, 7, 29, 23, 1, 14, 4, 6, 6, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Telugu/Telugu/India
+ { 288, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,23414,23414,23482,23482,23509,23509, 740, 784, 0, 5, 22, 147, 5267, 2, 9, 6456, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Teso/Latin/Uganda
+ { 288, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,23414,23414,23482,23482,23509,23509, 740, 784, 0, 5, 22, 176, 5288, 2, 9, 6456, 6462, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 20, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Teso/Latin/Kenya
+ { 289, 133, 231, 24, 24, 1163, 1171, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1816, 129, 542, 0,23522,23522,23589,23589,23611,23611, 749, 790, 1131, 5, 22, 317, 5308, 2, 9, 6467, 6467, 5, 5, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 6, 31, 5, 67, 67, 22, 22, 15, 15, 10, 10, 4, 17, 23, 1, 3, 4, 6, 3, 3, {84,72,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Thai/Thai/Thailand
+ { 290, 134, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1835, 103, 10, 0,23626,23626,23704,23704,23754,23754, 759, 800, 0, 5, 22, 150, 5311, 15, 0, 6470, 6478, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 6, 5, 0, 8, 6, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tibetan/Tibetan/China
+ { 290, 134, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1835, 103, 61, 76,23626,23626,23704,23704,23754,23754, 759, 800, 0, 5, 22, 120, 5317, 15, 0, 6470, 6484, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 15, 7, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 12, 5, 0, 8, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Tibetan/Tibetan/India
+ { 291, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1858, 78, 61, 76,23780,23780,23820,23820,23846,23846, 0, 0, 0, 5, 22, 6, 0, 2, 0, 6491, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 8, 15, 7, 40, 40, 26, 26, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 3, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigre/Ethiopic/Eritrea
+ { 292, 33, 77, 38, 38, 1178, 1178, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1879, 78, 61, 76,23859,23859,23887,23887,23907,23907, 766, 808, 0, 5, 22, 1, 112, 2, 0, 6494, 143, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 2, 2, 4, 0, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Ethiopia
+ { 292, 33, 74, 38, 38, 1178, 1178, 6, 0, 1, 2, 3, 4, 5, 10, 16, 17, 14, 15, 1879, 78, 61, 76,23859,23859,23887,23887,23907,23907, 766, 808, 0, 5, 22, 6, 5329, 2, 0, 6494, 671, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 3, 4, 0, 4, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Eritrea
+ { 294, 66, 182, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 787, 78, 573, 589,23920,23920,23964,23964, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 6498, 6507, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 16, 8, 44, 44, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 9, 13, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tok Pisin/Latin/Papua New Guinea
+ { 295, 66, 235, 1185, 1185, 1185, 1185, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 23, 38,23991,23991,24050,24050,24078,24078, 770, 812, 1135, 1140, 1199, 205, 5332, 15, 0, 6520, 2283, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 59, 59, 28, 28, 13, 13, 10, 6, 5, 59, 65, 2, 17, 5, 0, 13, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tongan/Latin/Tonga
+ { 296, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,24091,24091,24162,24162, 83, 83, 0, 0, 0, 5, 22, 9, 0, 15, 0, 6533, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 71, 71, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 8, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tsonga/Latin/South Africa
+ { 297, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,24188,24188,24251,24251, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6541, 6549, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 31, 31, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 8, 13, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tswana/Latin/South Africa
+ { 297, 66, 30, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,24188,24188,24251,24251, 83, 83, 0, 0, 0, 5, 22, 153, 0, 2, 0, 6541, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 31, 31, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 8, 0, {66,87,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tswana/Latin/Botswana
+ { 298, 66, 239, 0, 0, 1193, 1193, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1896, 50, 10, 0,24282,24282,24335,24335,24362,24362, 780, 818, 185, 5, 22, 126, 5349, 2, 9, 6562, 6568, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 13, 5, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 11, 4, 6, 6, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Turkey
+ { 298, 66, 63, 0, 0, 1193, 1193, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1896, 50, 23, 38,24282,24282,24335,24335,24362,24362, 780, 818, 185, 5, 22, 22, 83, 2, 9, 6562, 6575, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 15, 7, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 4, 6, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Cyprus
+ { 299, 66, 240, 0, 0, 1201, 1201, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 14, 15, 1896, 49, 10, 0,24375,24428,24481,24508,24535,24535, 782, 820, 1264, 5, 22, 0, 5360, 4, 0, 6581, 6593, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 53, 53, 27, 27, 13, 13, 13, 14, 4, 17, 23, 0, 14, 5, 0, 12, 12, {84,77,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkmen/Latin/Turkmenistan
+ { 301, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 10, 0,24548,24548,24589,24589, 83, 83, 0, 0, 0, 5, 22, 124, 5374, 15, 0, 6605, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 41, 41, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tyap/Latin/Nigeria
+ { 303, 27, 244, 0, 0, 117, 117, 6, 1, 9, 2, 3, 4, 5, 85, 11, 12, 13, 14, 1912, 49, 10, 0,24616,24671, 3049, 3049, 4289, 4289, 795, 834, 1268, 841, 22, 286, 5378, 4, 0, 6610, 6620, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 13, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 10, 7, {85,65,72}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ukrainian/Cyrillic/Ukraine
+ { 304, 66, 91, 0, 0, 781, 781, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 180, 11, 597,24726,24726,24778,24778,24805,24805, 402, 836, 1273, 5, 22, 22, 405, 4, 0, 6627, 6642, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 12, 52, 52, 27, 27, 13, 13, 9, 9, 5, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Upper Sorbian/Latin/Germany
+ { 305, 4, 178, 661, 661, 1209, 1219, 6, 0, 1, 2, 3, 35, 37, 10, 15, 14, 17, 16, 1934, 129, 61, 76,24818,24818,24818,24818, 83, 83, 0, 0, 1278, 1282, 22, 196, 5395, 2, 9, 6648, 5140, 6, 6, 10, 9, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 6, 15, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 2, 14, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Urdu/Arabic/Pakistan
+ { 305, 4, 110, 661, 661, 1209, 1219, 6, 21, 22, 2, 40, 35, 41, 44, 15, 14, 17, 16, 1934, 129, 61, 76,24818,24818,24818,24818, 83, 83, 0, 0, 1278, 1282, 22, 120, 5409, 2, 9, 6648, 6652, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 15, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 1, 12, 4, 6, 4, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Urdu/Arabic/India
+ { 306, 4, 50, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 12, 11, 20, 19, 1952, 103, 10, 0,24853,24853,24907,24907,24927,24927, 797, 845, 0, 5, 22, 145, 5421, 2, 9, 6657, 6665, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 54, 54, 20, 20, 13, 13, 12, 12, 4, 17, 23, 1, 11, 4, 6, 8, 5, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Uyghur/Arabic/China
+ { 307, 66, 251, 0, 0, 1228, 1228, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 17, 16, 1969, 78, 99, 0,24940,24940,25000,25000,25031,25031, 360, 857, 185, 5, 22, 318, 5432, 2, 9, 6670, 6676, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 14, 5, 60, 60, 31, 31, 13, 13, 2, 2, 4, 17, 23, 4, 17, 4, 6, 6, 11, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Latin/Uzbekistan
+ { 307, 4, 1, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1987, 505, 99, 1,18196,18196,25044,25044, 83, 83, 0, 0, 0, 5, 22, 270, 3963, 4, 0, 6687, 5131, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 33, 8, 14, 4, 48, 48, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Uzbek/Arabic/Afghanistan
+ { 307, 27, 251, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1008, 78, 98, 0,25064,25064,25116,25116,25143,25143, 809, 859, 0, 5, 22, 322, 5449, 4, 0, 6693, 6700, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 14, 5, 0, 7, 10, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Cyrillic/Uzbekistan
+ { 308, 139, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 61, 76,25156,25156,25156,25156, 83, 83, 0, 0, 0, 5, 22, 10, 5463, 2, 9, 6710, 6712, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 29, 29, 29, 29, 13, 13, 2, 2, 4, 17, 23, 1, 8, 4, 6, 2, 4, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Vai/Liberia
+ { 308, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,25185,25185,25185,25185, 83, 83, 0, 0, 0, 5, 22, 10, 5471, 2, 9, 6716, 6719, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 47, 47, 47, 47, 13, 13, 2, 2, 4, 17, 23, 1, 13, 4, 6, 3, 8, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Latin/Liberia
+ { 309, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,25232,25232,25301,25301, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6727, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 69, 69, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 9, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Venda/Latin/South Africa
+ { 310, 66, 255, 0, 0, 1236, 1236, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 10, 0,25327,25327,25381,25381,25413,25413, 811, 861, 0, 5, 22, 306, 5484, 4, 0, 6736, 6746, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 54, 54, 32, 32, 20, 20, 2, 2, 4, 17, 23, 1, 13, 5, 0, 10, 8, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Vietnamese/Latin/Vietnam
+ { 311, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2020, 103, 10, 0,25433,25433,25475,25495,25522,25522, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6754, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 42, 42, 20, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 7, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Volapuk/Latin/world
+ { 312, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 2, 0, 6761, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 8, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Vunjo/Latin/Tanzania
+ { 313, 66, 23, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 6769, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Walloon/Latin/Belgium
+ { 314, 66, 226, 0, 0, 463, 463, 6, 1, 17, 2, 3, 4, 5, 10, 11, 12, 19, 20, 404, 103, 10, 0,25535,25535,25587,25587,25614,25614, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6774, 6780, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Walser/Latin/Switzerland
+ { 315, 66, 15, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 241, 0, 15, 0, 6786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 8, 0, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Warlpiri/Latin/Australia
+ { 316, 66, 246, 0, 0, 1244, 1255, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 78, 10, 0,25627,25627,25703,25731,25760,25760, 813, 863, 1302, 5, 22, 94, 5497, 2, 9, 6794, 6801, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 76, 76, 28, 29, 14, 14, 2, 2, 7, 17, 23, 1, 12, 4, 6, 7, 16, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Welsh/Latin/United Kingdom
+ { 317, 4, 178, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 196, 5509, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 13, 5, 0, 14, 0, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Western Balochi/Arabic/Pakistan
+ { 317, 4, 1, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 270, 5522, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 14, 0, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Western Balochi/Arabic/Afghanistan
+ { 317, 4, 112, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 271, 5539, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 11, 5, 0, 14, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Western Balochi/Arabic/Iran
+ { 317, 4, 176, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6817, 6831, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 14, 5, {79,77,82}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Western Balochi/Arabic/Oman
+ { 317, 4, 245, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6817, 6836, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 14, 19, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // Western Balochi/Arabic/United Arab Emirates
+ { 318, 66, 165, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 394, 10, 0,25774,25774,25827,25827, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 58, 6855, 6860, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 53, 53, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 7, 5, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Western Frisian/Latin/Netherlands
+ { 319, 33, 77, 0, 0, 0, 0, 6, 0, 17, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2043, 78, 61, 76,25847,25847,25847,25847,25873,25873, 0, 0, 0, 5, 22, 1, 105, 2, 0, 6868, 143, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 15, 7, 26, 26, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 9, 4, 0, 5, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Wolaytta/Ethiopic/Ethiopia
+ { 320, 66, 206, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2065, 394, 10, 0,25886,25886,25935,25935,25935,25935, 732, 865, 0, 5, 22, 127, 5550, 15, 0, 6873, 2999, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 49, 49, 27, 27, 27, 27, 3, 3, 4, 17, 23, 5, 29, 5, 0, 5, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Wolof/Latin/Senegal
+ { 321, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 0,25962,25962,26022,26049,26078,26098, 0, 0, 0, 5, 22, 9, 5579, 2, 0, 6878, 6886, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 60, 60, 27, 29, 20, 21, 2, 2, 4, 17, 23, 1, 25, 4, 0, 8, 15, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Xhosa/Latin/South Africa
+ { 322, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 129, 10, 0,26119,26119,26189,26189,26209,26209, 815, 868, 0, 5, 22, 11, 0, 4, 20, 6901, 6907, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 70, 70, 20, 20, 13, 13, 8, 8, 4, 17, 23, 4, 0, 5, 7, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yangben/Latin/Cameroon
+ { 323, 47, 244, 0, 0, 1265, 1265, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 2082, 78, 10, 0,26222,26222,26222,26222, 83, 83, 823, 876, 0, 5, 22, 286, 0, 15, 0, 6914, 6920, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 13, 5, 53, 53, 53, 53, 13, 13, 11, 10, 4, 17, 23, 1, 0, 5, 0, 6, 9, {85,65,72}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yiddish/Hebrew/Ukraine
+ { 324, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2101, 129, 10, 1,26275,26318,26386,26386,26418,26418, 834, 886, 1309, 1320, 22, 124, 5604, 2, 9, 6929, 6939, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 1, 14, 4, 6, 10, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Nigeria
+ { 324, 66, 25, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2101, 129, 10, 1,26431,26474,26542,26542,26574,26574, 839, 891, 1357, 1320, 22, 127, 5618, 2, 9, 6929, 6947, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 5, 26, 4, 6, 10, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Benin
+ { 325, 66, 170, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,26587,26587,11735,11735,26639,26639, 732, 774, 0, 5, 22, 127, 3285, 0, 0, 6953, 6432, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 52, 52, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 10, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Zarma/Latin/Niger
+ { 326, 66, 50, 0, 0, 1274, 1274, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,26652,26652,26652,26652, 83, 83, 844, 896, 0, 5, 22, 150, 5644, 15, 0, 6963, 6972, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 89, 89, 89, 89, 13, 13, 7, 12, 4, 17, 23, 1, 10, 5, 0, 9, 8, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Zhuang/Latin/China
+ { 327, 66, 216, 0, 0, 1285, 1294, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 0,26741,26741,26814,26814,26841,26841, 0, 0, 0, 5, 22, 9, 5654, 2, 9, 6980, 6987, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 73, 73, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 17, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Zulu/Latin/South Africa
+ { 328, 66, 32, 0, 0, 1302, 1302, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2117, 186, 10, 0,26854,26854,26940,26940,26974,26974, 0, 0, 1368, 5, 22, 9, 5674, 15, 0, 7004, 7011, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 86, 86, 34, 34, 20, 20, 2, 2, 7, 17, 23, 2, 12, 5, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kaingang/Latin/Brazil
+ { 329, 66, 32, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,26994,26994,27058,27058,27085,27085, 0, 0, 1375, 5, 22, 9, 5686, 15, 0, 7017, 7025, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 64, 64, 27, 27, 13, 13, 2, 2, 8, 17, 23, 2, 15, 5, 0, 8, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Brazil
+ { 329, 66, 54, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,26994,26994,27058,27058,27085,27085, 132, 128, 1375, 5, 22, 10, 5701, 15, 0, 7031, 7038, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 1, 17, 5, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Colombia
+ { 329, 66, 254, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,26994,26994,27058,27058,27085,27085, 132, 128, 1375, 5, 22, 302, 5718, 15, 0, 7031, 7046, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 4, 22, 5, 0, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Venezuela
+ { 330, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76,27098,27098,27098,27098, 83, 83, 851, 83, 0, 5, 22, 120, 0, 15, 0, 7055, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 54, 54, 54, 54, 13, 13, 4, 4, 4, 17, 23, 1, 0, 5, 0, 8, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Haryanvi/Devanagari/India
+ { 331, 66, 91, 0, 0, 915, 915, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 404, 78, 10, 0,27152,27152,27208,27208, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 0, 7063, 7073, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Frisian/Latin/Germany
+ { 332, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76, 8522, 8522, 8522, 8522, 83, 83, 855, 908, 0, 5, 22, 120, 0, 15, 0, 7082, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 52, 52, 52, 52, 13, 13, 5, 4, 4, 17, 23, 1, 0, 5, 0, 9, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Rajasthani/Devanagari/India
+ { 333, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 7091, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Moksha/Cyrillic/Russia
+ { 334, 66, 258, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,27235,27235,27235,27235, 83, 83, 860, 912, 0, 5, 22, 0, 0, 2, 0, 7103, 7112, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 90, 90, 90, 90, 13, 13, 12, 12, 4, 17, 23, 0, 0, 4, 0, 9, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 2, 2 }, // Toki Pona/Latin/world
+ { 335, 66, 214, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,27325,27325,27325,27325, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 7118, 7123, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 46, 46, 46, 46, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 13, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Pijin/Latin/Solomon Islands
+ { 336, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 124, 0, 15, 0, 7136, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Obolo/Latin/Nigeria
+ { 337, 4, 178, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 367, 383,27371,27371,27417,27417, 83, 83, 0, 0, 0, 5, 22, 196, 5395, 15, 0, 7141, 5140, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 46, 46, 24, 24, 13, 13, 2, 2, 4, 17, 23, 2, 13, 5, 0, 5, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Baluchi/Arabic/Pakistan
+ { 337, 66, 178, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 573, 589,27441,27441,27511,27511, 83, 83, 0, 0, 0, 5, 22, 196, 5740, 15, 0, 7146, 7153, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 70, 70, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 14, 5, 0, 7, 8, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Baluchi/Latin/Pakistan
+ { 338, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 2140, 78, 10, 0,27537,27537,27591,27591,27625,27625, 0, 0, 0, 5, 22, 22, 405, 4, 20, 7161, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 8, 13, 5, 54, 54, 34, 34, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ligurian/Latin/Italy
+ { 339, 142, 161, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 1, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 134, 0, 15, 0, 7167, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 4, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 18, 0, {77,77,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Rohingya/Hanifi/Myanmar
+ { 339, 142, 20, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 132, 0, 15, 0, 7167, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 18, 0, {66,68,84}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Rohingya/Hanifi/Bangladesh
+ { 340, 4, 178, 1321, 1321, 1326, 1335, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1934, 129, 61, 76,27638,27638,27638,27638,27695,27695, 0, 0, 1278, 1282, 22, 196, 5395, 15, 0, 7185, 5140, 5, 5, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 57, 57, 57, 57, 13, 13, 2, 2, 4, 20, 23, 2, 14, 5, 0, 7, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Torwali/Arabic/Pakistan
+ { 341, 66, 25, 0, 0, 566, 566, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 2161, 2178, 10, 0,27708,27708,27766,27766,27800,27800, 872, 924, 0, 5, 22, 127, 5754, 15, 86, 7192, 7203, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 58, 58, 34, 34, 20, 20, 13, 13, 4, 17, 23, 5, 33, 5, 6, 11, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Anii/Latin/Benin
+ { 342, 29, 110, 0, 0, 1343, 1353, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,27820,27820,27872,27872,27905,27905, 885, 937, 0, 5, 22, 120, 5787, 2, 0, 7208, 664, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 52, 52, 33, 33, 18, 18, 6, 11, 4, 17, 23, 1, 14, 4, 0, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Kangri/Devanagari/India
+ { 343, 66, 117, 0, 0, 414, 414, 6, 1, 68, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 78, 10, 0,27923,27923,27967,27967,27625,27625, 0, 0, 0, 5, 22, 155, 405, 117, 0, 7215, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 44, 44, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Venetian/Latin/Italy
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0,0,0}, 0, 0, 0, 0, 0, 0, 0, 0 } // trailing zeros
};
@@ -2388,49 +2388,57 @@ static constexpr char16_t date_format_data[] = {
};
static constexpr char16_t time_format_data[] = {
-0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x68, 0x3a,
-0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x20, 0x74, 0x68, 0x3a,
-0x6d, 0x6d, 0x202f, 0x41, 0x70, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73,
-0x202f, 0x41, 0x70, 0x2c, 0x20, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73,
-0x73, 0x20, 0x41, 0x70, 0x20, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41,
-0x70, 0x41, 0x70, 0x20, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20,
-0x74, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x28, 0x74,
-0x29, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x2c, 0x20, 0x74,
-0x41, 0x70, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74,
-0x41, 0x70, 0x20, 0x928, 0x93f, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x48, 0x3a,
-0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x27, 0x447, 0x27, 0x2e, 0x20, 0x74,
-0x74, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x41, 0x70,
-0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x5b, 0x74, 0x5d, 0x74,
-0x20, 0x41, 0x70, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x48, 0x48,
-0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20, 0x74, 0xf46, 0xf74, 0xf0b, 0xf5a,
-0xf7c, 0xf51, 0xf0b, 0x20, 0x68, 0x20, 0xf66, 0xf90, 0xf62, 0xf0b, 0xf58, 0xf0b,
-0x20, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20, 0x74, 0xf46,
-0xf74, 0xf0b, 0xf5a, 0xf7c, 0xf51, 0xf0b, 0x20, 0x68, 0x20, 0xf66, 0xf90, 0xf62,
-0xf0b, 0xf58, 0xf0b, 0x20, 0x6d, 0x6d, 0x20, 0x41, 0x70, 0x41, 0x70, 0x20,
-0x27, 0x67, 0x61, 0x27, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73,
-0x20, 0x74, 0x48, 0x20, 0x27, 0x68, 0x27, 0x20, 0x6d, 0x6d, 0x20, 0x27,
-0x6d, 0x69, 0x6e, 0x27, 0x20, 0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20,
-0x74, 0x48, 0x48, 0x20, 0x27, 0x68, 0x27, 0x20, 0x6d, 0x6d, 0x20, 0x27,
-0x6d, 0x69, 0x6e, 0x27, 0x20, 0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20,
-0x74, 0x48, 0x48, 0x2e, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x27, 0x68,
-0x27, 0x20, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20,
-0x41, 0x70, 0x20, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41, 0x70,
-0x48, 0x6642, 0x6d, 0x6d, 0x5206, 0x73, 0x73, 0x79d2, 0x20, 0x74, 0x41, 0x70,
-0x20, 0x68, 0xc2dc, 0x20, 0x6d, 0xbd84, 0x20, 0x73, 0xcd08, 0x20, 0x74, 0x48,
-0x20, 0xec2, 0xea1, 0xe87, 0x20, 0x6d, 0x20, 0xe99, 0xeb2, 0xe97, 0xeb5, 0x20,
-0x73, 0x73, 0x20, 0xea7, 0xeb4, 0xe99, 0xeb2, 0xe97, 0xeb5, 0x20, 0x74, 0x27,
-0x4b, 0x6c, 0x6f, 0x63, 0x6b, 0x27, 0x20, 0x48, 0x2e, 0x6d, 0x6d, 0x3a,
-0x73, 0x73, 0x20, 0x28, 0x74, 0x29, 0x27, 0x4b, 0x6c, 0x27, 0x2e, 0x20,
-0x48, 0x2e, 0x6d, 0x6d, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20,
-0x41, 0x70, 0x20, 0x74, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x20, 0x41, 0x70,
-0x27, 0x6b, 0x6c, 0x27, 0x2e, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a,
-0x73, 0x73, 0x20, 0x74, 0x74, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73,
-0x73, 0x202f, 0x41, 0x70, 0x48, 0x27, 0x68, 0x27, 0x6d, 0x6d, 0x48, 0x20,
-0xe19, 0xe32, 0xe2c, 0xe34, 0xe01, 0xe32, 0x20, 0x6d, 0x6d, 0x20, 0xe19, 0xe32,
-0xe17, 0xe35, 0x20, 0x73, 0x73, 0x20, 0xe27, 0xe34, 0xe19, 0xe32, 0xe17, 0xe35,
-0x20, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41,
-0x70, 0x20, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x202f, 0x41, 0x70, 0x48,
-0x3a, 0x6d, 0x6d, 0x20, 0x27, 0x68, 0x6f, 0x64, 0x17a, 0x27, 0x2e
+0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x48, 0x48,
+0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68,
+0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x202f, 0x41, 0x70, 0x68, 0x3a, 0x6d,
+0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x2c, 0x20, 0x74, 0x74, 0x74,
+0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20,
+0x74, 0x74, 0x74, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41, 0x70, 0x41,
+0x70, 0x20, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x28,
+0x74, 0x74, 0x74, 0x74, 0x29, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73,
+0x73, 0x2c, 0x20, 0x74, 0x74, 0x74, 0x74, 0x41, 0x70, 0x20, 0x68, 0x3a,
+0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0x41, 0x70,
+0x20, 0x928, 0x93f, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x48, 0x3a, 0x6d, 0x6d,
+0x3a, 0x73, 0x73, 0x20, 0x27, 0x447, 0x27, 0x2e, 0x20, 0x74, 0x74, 0x74,
+0x74, 0x74, 0x74, 0x74, 0x74, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a,
+0x73, 0x73, 0x41, 0x70, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20,
+0x5b, 0x74, 0x74, 0x74, 0x74, 0x5d, 0x74, 0x74, 0x74, 0x74, 0x20, 0x41,
+0x70, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x48, 0x48, 0x2e, 0x6d,
+0x6d, 0x2e, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0xf46, 0xf74, 0xf0b,
+0xf5a, 0xf7c, 0xf51, 0xf0b, 0x20, 0x68, 0x20, 0xf66, 0xf90, 0xf62, 0xf0b, 0xf58,
+0xf0b, 0x20, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20, 0x74,
+0x74, 0x74, 0x74, 0xf46, 0xf74, 0xf0b, 0xf5a, 0xf7c, 0xf51, 0xf0b, 0x20, 0x68,
+0x20, 0xf66, 0xf90, 0xf62, 0xf0b, 0xf58, 0xf0b, 0x20, 0x6d, 0x6d, 0x20, 0x41,
+0x70, 0x41, 0x70, 0x20, 0x27, 0x67, 0x61, 0x27, 0x20, 0x68, 0x3a, 0x6d,
+0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0x48, 0x20, 0x27,
+0x68, 0x27, 0x20, 0x6d, 0x6d, 0x20, 0x27, 0x6d, 0x69, 0x6e, 0x27, 0x20,
+0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20, 0x74, 0x74, 0x74, 0x74, 0x48,
+0x48, 0x20, 0x27, 0x68, 0x27, 0x20, 0x6d, 0x6d, 0x20, 0x27, 0x6d, 0x69,
+0x6e, 0x27, 0x20, 0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x48, 0x48, 0x2e, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x27,
+0x68, 0x27, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d,
+0x3a, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68,
+0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41, 0x70, 0x48, 0x6642, 0x6d, 0x6d, 0x5206,
+0x73, 0x73, 0x79d2, 0x20, 0x74, 0x74, 0x74, 0x74, 0x41, 0x70, 0x20, 0x68,
+0xc2dc, 0x20, 0x6d, 0xbd84, 0x20, 0x73, 0xcd08, 0x20, 0x74, 0x74, 0x74, 0x74,
+0x48, 0x20, 0xec2, 0xea1, 0xe87, 0x20, 0x6d, 0x20, 0xe99, 0xeb2, 0xe97, 0xeb5,
+0x20, 0x73, 0x73, 0x20, 0xea7, 0xeb4, 0xe99, 0xeb2, 0xe97, 0xeb5, 0x20, 0x74,
+0x74, 0x74, 0x74, 0x27, 0x4b, 0x6c, 0x6f, 0x63, 0x6b, 0x27, 0x20, 0x48,
+0x2e, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x28, 0x74, 0x74, 0x74, 0x74,
+0x29, 0x27, 0x4b, 0x6c, 0x27, 0x2e, 0x20, 0x48, 0x2e, 0x6d, 0x6d, 0x68,
+0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x20, 0x41, 0x70, 0x27, 0x6b,
+0x6c, 0x27, 0x2e, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73,
+0x20, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x20, 0x68, 0x3a,
+0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x48, 0x27, 0x68, 0x27,
+0x6d, 0x6d, 0x48, 0x20, 0xe19, 0xe32, 0xe2c, 0xe34, 0xe01, 0xe32, 0x20, 0x6d,
+0x6d, 0x20, 0xe19, 0xe32, 0xe17, 0xe35, 0x20, 0x73, 0x73, 0x20, 0xe27, 0xe34,
+0xe19, 0xe32, 0xe17, 0xe35, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68, 0x68, 0x3a,
+0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x20, 0x74, 0x74, 0x74,
+0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x202f, 0x41, 0x70, 0x48, 0x3a, 0x6d,
+0x6d, 0x20, 0x27, 0x68, 0x6f, 0x64, 0x17a, 0x27, 0x2e
};
static constexpr char16_t days_data[] = {
diff --git a/src/corelib/text/qlocale_mac.mm b/src/corelib/text/qlocale_mac.mm
index e665b3a2f2..89339be2eb 100644
--- a/src/corelib/text/qlocale_mac.mm
+++ b/src/corelib/text/qlocale_mac.mm
@@ -403,13 +403,19 @@ static QVariant macToQtFormat(QStringView sys_fmt)
result += "zzz"_L1;
break;
case 'O': // Time Zone (1, 4)
+ result += u't';
+ break;
case 'v': // Time Zone (1, 4)
case 'V': // Time Zone (1..4)
+ result += "tttt"_L1;
+ break;
case 'x': // Time Zone (1..5)
case 'X': // Time Zone (1..5)
+ result += (repeat > 1 && (repeat & 1)) ? "ttt"_L1 : "tt"_L1;
+ break;
case 'z': // Time Zone (1..4)
case 'Z': // Time Zone (1..5)
- result += u't';
+ result += repeat < 4 ? "tt"_L1 : repeat > 4 ? "ttt"_L1 : "t"_L1;
break;
default:
// a..z and A..Z are reserved for format codes, so any occurrence of these not
diff --git a/src/corelib/text/qregularexpression.cpp b/src/corelib/text/qregularexpression.cpp
index 95fd0e3d9a..78261e14cb 100644
--- a/src/corelib/text/qregularexpression.cpp
+++ b/src/corelib/text/qregularexpression.cpp
@@ -42,6 +42,7 @@ using namespace Qt::StringLiterals;
\keyword regular expression
+ \compares equality
Regular expressions, or \e{regexps}, are a very powerful tool to handle
strings and texts. This is useful in many contexts, e.g.,
@@ -721,7 +722,7 @@ struct QRegularExpressionPrivate : QSharedData
CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
const QRegularExpressionMatchPrivate *previous = nullptr) const;
- int captureIndexForName(QStringView name) const;
+ int captureIndexForName(QAnyStringView name) const;
// sizeof(QSharedData) == 4, so start our members with an enum
QRegularExpression::PatternOptions patternOptions;
@@ -1013,7 +1014,7 @@ void QRegularExpressionPrivate::optimizePattern()
Returns the capturing group number for the given name. Duplicated names for
capturing groups are not supported.
*/
-int QRegularExpressionPrivate::captureIndexForName(QStringView name) const
+int QRegularExpressionPrivate::captureIndexForName(QAnyStringView name) const
{
Q_ASSERT(!name.isEmpty());
@@ -1734,18 +1735,20 @@ void QRegularExpression::optimize() const
}
/*!
- Returns \c true if the regular expression is equal to \a re, or false
+ \fn bool QRegularExpression::operator==(const QRegularExpression &lhs, const QRegularExpression &rhs) noexcept
+
+ Returns \c true if the \a lhs regular expression is equal to the \a rhs, or false
otherwise. Two QRegularExpression objects are equal if they have
the same pattern string and the same pattern options.
\sa operator!=()
*/
-bool QRegularExpression::operator==(const QRegularExpression &re) const
+bool comparesEqual(const QRegularExpression &lhs,
+ const QRegularExpression &rhs) noexcept
{
- return (d == re.d) ||
- (d->pattern == re.d->pattern && d->patternOptions == re.d->patternOptions);
+ return (lhs.d == rhs.d) ||
+ (lhs.d->pattern == rhs.d->pattern && lhs.d->patternOptions == rhs.d->patternOptions);
}
-
/*!
\fn QRegularExpression & QRegularExpression::operator=(QRegularExpression && re)
@@ -1758,9 +1761,9 @@ bool QRegularExpression::operator==(const QRegularExpression &re) const
*/
/*!
- \fn bool QRegularExpression::operator!=(const QRegularExpression &re) const
+ \fn bool QRegularExpression::operator!=(const QRegularExpression &lhs, const QRegularExpression &rhs) noexcept
- Returns \c true if the regular expression is different from \a re, or
+ Returns \c true if the \a lhs regular expression is different from the \a rhs, or
false otherwise.
\sa operator==()
@@ -2217,8 +2220,7 @@ int QRegularExpressionMatch::lastCapturedIndex() const
}
/*!
- \fn bool QRegularExpressionMatch::hasCaptured(const QString &name) const
- \fn bool QRegularExpressionMatch::hasCaptured(QStringView name) const
+ \fn bool QRegularExpressionMatch::hasCaptured(QAnyStringView name) const
\since 6.3
Returns true if the capturing group named \a name captured something
@@ -2235,9 +2237,12 @@ int QRegularExpressionMatch::lastCapturedIndex() const
Similarly, a capturing group may capture a substring of length 0;
this function will return \c{true} for such a capturing group.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa captured(), hasMatch()
*/
-bool QRegularExpressionMatch::hasCaptured(QStringView name) const
+bool QRegularExpressionMatch::hasCaptured(QAnyStringView name) const
{
const int nth = d->regularExpression.d->captureIndexForName(name);
return hasCaptured(nth);
@@ -2317,17 +2322,6 @@ QStringView QRegularExpressionMatch::capturedView(int nth) const
return d->subject.mid(start, capturedLength(nth));
}
-/*! \fn QString QRegularExpressionMatch::captured(const QString &name) const
-
- Returns the substring captured by the capturing group named \a name.
-
- If the named capturing group \a name did not capture a string, or if
- there is no capturing group named \a name, returns a null QString.
-
- \sa capturedView(), capturedStart(), capturedEnd(), capturedLength(),
- QString::isNull()
-*/
-
/*!
\since 5.10
@@ -2336,10 +2330,13 @@ QStringView QRegularExpressionMatch::capturedView(int nth) const
If the named capturing group \a name did not capture a string, or if
there is no capturing group named \a name, returns a null QString.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedView(), capturedStart(), capturedEnd(), capturedLength(),
QString::isNull()
*/
-QString QRegularExpressionMatch::captured(QStringView name) const
+QString QRegularExpressionMatch::captured(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::captured: empty capturing group name passed");
@@ -2358,10 +2355,13 @@ QString QRegularExpressionMatch::captured(QStringView name) const
If the named capturing group \a name did not capture a string, or if
there is no capturing group named \a name, returns a null QStringView.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa captured(), capturedStart(), capturedEnd(), capturedLength(),
QStringView::isNull()
*/
-QStringView QRegularExpressionMatch::capturedView(QStringView name) const
+QStringView QRegularExpressionMatch::capturedView(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedView: empty capturing group name passed");
@@ -2433,37 +2433,6 @@ qsizetype QRegularExpressionMatch::capturedEnd(int nth) const
return d->capturedOffsets.at(nth * 2 + 1);
}
-/*! \fn qsizetype QRegularExpressionMatch::capturedStart(const QString &name) const
-
- Returns the offset inside the subject string corresponding to the starting
- position of the substring captured by the capturing group named \a name.
- If the capturing group named \a name did not capture a string or doesn't
- exist, returns -1.
-
- \sa capturedEnd(), capturedLength(), captured()
-*/
-
-/*! \fn qsizetype QRegularExpressionMatch::capturedLength(const QString &name) const
-
- Returns the length of the substring captured by the capturing group named
- \a name.
-
- \note This function returns 0 if the capturing group named \a name did not
- capture a string or doesn't exist.
-
- \sa capturedStart(), capturedEnd(), captured()
-*/
-
-/*! \fn qsizetype QRegularExpressionMatch::capturedEnd(const QString &name) const
-
- Returns the offset inside the subject string immediately after the ending
- position of the substring captured by the capturing group named \a name. If
- the capturing group named \a name did not capture a string or doesn't
- exist, returns -1.
-
- \sa capturedStart(), capturedLength(), captured()
-*/
-
/*!
\since 5.10
@@ -2472,9 +2441,12 @@ qsizetype QRegularExpressionMatch::capturedEnd(int nth) const
If the capturing group named \a name did not capture a string or doesn't
exist, returns -1.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedEnd(), capturedLength(), captured()
*/
-qsizetype QRegularExpressionMatch::capturedStart(QStringView name) const
+qsizetype QRegularExpressionMatch::capturedStart(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedStart: empty capturing group name passed");
@@ -2495,9 +2467,12 @@ qsizetype QRegularExpressionMatch::capturedStart(QStringView name) const
\note This function returns 0 if the capturing group named \a name did not
capture a string or doesn't exist.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedStart(), capturedEnd(), captured()
*/
-qsizetype QRegularExpressionMatch::capturedLength(QStringView name) const
+qsizetype QRegularExpressionMatch::capturedLength(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedLength: empty capturing group name passed");
@@ -2517,9 +2492,12 @@ qsizetype QRegularExpressionMatch::capturedLength(QStringView name) const
the capturing group named \a name did not capture a string or doesn't
exist, returns -1.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedStart(), capturedLength(), captured()
*/
-qsizetype QRegularExpressionMatch::capturedEnd(QStringView name) const
+qsizetype QRegularExpressionMatch::capturedEnd(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
diff --git a/src/corelib/text/qregularexpression.h b/src/corelib/text/qregularexpression.h
index ed838327ef..ab147b87d4 100644
--- a/src/corelib/text/qregularexpression.h
+++ b/src/corelib/text/qregularexpression.h
@@ -157,11 +157,15 @@ public:
static QRegularExpression fromWildcard(QStringView pattern, Qt::CaseSensitivity cs = Qt::CaseInsensitive,
WildcardConversionOptions options = DefaultWildcardConversion);
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QRegularExpression &re) const;
inline bool operator!=(const QRegularExpression &re) const { return !operator==(re); }
-
+#endif
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QRegularExpression &lhs,
+ const QRegularExpression &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QRegularExpression)
+
friend struct QRegularExpressionPrivate;
friend class QRegularExpressionMatch;
friend struct QRegularExpressionMatchPrivate;
@@ -213,18 +217,26 @@ public:
int lastCapturedIndex() const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool hasCaptured(const QString &name) const
- { return hasCaptured(QStringView(name)); }
+ { return hasCaptured(qToAnyStringViewIgnoringNull(name)); }
bool hasCaptured(QStringView name) const;
+#endif
+ bool hasCaptured(QAnyStringView name) const;
bool hasCaptured(int nth) const;
QString captured(int nth = 0) const;
QStringView capturedView(int nth = 0) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
QString captured(const QString &name) const
- { return captured(QStringView(name)); }
+ { return captured(qToAnyStringViewIgnoringNull(name)); }
+
QString captured(QStringView name) const;
QStringView capturedView(QStringView name) const;
+#endif
+ QString captured(QAnyStringView name) const;
+ QStringView capturedView(QAnyStringView name) const;
QStringList capturedTexts() const;
@@ -232,16 +244,21 @@ public:
qsizetype capturedLength(int nth = 0) const;
qsizetype capturedEnd(int nth = 0) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
qsizetype capturedStart(const QString &name) const
- { return capturedStart(QStringView(name)); }
+ { return capturedStart(qToAnyStringViewIgnoringNull(name)); }
qsizetype capturedLength(const QString &name) const
- { return capturedLength(QStringView(name)); }
+ { return capturedLength(qToAnyStringViewIgnoringNull(name)); }
qsizetype capturedEnd(const QString &name) const
- { return capturedEnd(QStringView(name)); }
+ { return capturedEnd(qToAnyStringViewIgnoringNull(name)); }
qsizetype capturedStart(QStringView name) const;
qsizetype capturedLength(QStringView name) const;
qsizetype capturedEnd(QStringView name) const;
+#endif
+ qsizetype capturedStart(QAnyStringView name) const;
+ qsizetype capturedLength(QAnyStringView name) const;
+ qsizetype capturedEnd(QAnyStringView name) const;
private:
friend class QRegularExpression;
@@ -352,30 +369,24 @@ private:
// [input.iterators] imposes operator== on us. Unfortunately, it's not
// trivial to implement, so just do the bare minimum to satifisfy
// Cpp17EqualityComparable.
- friend bool operator==(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
- const QRegularExpressionMatchIteratorRangeBasedForIterator &rhs) noexcept
+ friend bool comparesEqual(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
+ const QRegularExpressionMatchIteratorRangeBasedForIterator &rhs)
+ noexcept
{
return (&lhs == &rhs);
}
-
- friend bool operator!=(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
- const QRegularExpressionMatchIteratorRangeBasedForIterator &rhs) noexcept
- {
- return !(lhs == rhs);
- }
+ Q_DECLARE_EQUALITY_COMPARABLE(QRegularExpressionMatchIteratorRangeBasedForIterator)
// This is what we really use in a range-based for.
- friend bool operator==(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
- QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel) noexcept
+ friend bool comparesEqual(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
+ const QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel &rhs)
+ noexcept
{
+ Q_UNUSED(rhs);
return lhs.m_atEnd;
}
-
- friend bool operator!=(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
- QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel) noexcept
- {
- return !lhs.m_atEnd;
- }
+ Q_DECLARE_EQUALITY_COMPARABLE(QRegularExpressionMatchIteratorRangeBasedForIterator,
+ QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel)
QRegularExpressionMatchIterator m_matchIterator;
QRegularExpressionMatch m_currentMatch;
diff --git a/src/corelib/text/qstaticlatin1stringmatcher.h b/src/corelib/text/qstaticlatin1stringmatcher.h
index d80ebd8547..bd6d9db08b 100644
--- a/src/corelib/text/qstaticlatin1stringmatcher.h
+++ b/src/corelib/text/qstaticlatin1stringmatcher.h
@@ -109,13 +109,30 @@ public:
}
constexpr qsizetype indexIn(QLatin1StringView haystack, qsizetype from = 0) const noexcept
+ { return indexIn_helper(haystack, from); }
+
+ constexpr qsizetype indexIn(QStringView haystack, qsizetype from = 0) const noexcept
+ { return indexIn_helper(haystack, from); }
+
+private:
+ template <typename String>
+ constexpr qsizetype indexIn_helper(String haystack, qsizetype from = 0) const noexcept
{
+ static_assert(QtPrivate::isLatin1OrUtf16View<String>);
+
if (from >= haystack.size())
return -1;
- const char *begin = haystack.begin() + from;
- const char *end = haystack.end();
+
+ const auto start = [haystack]() constexpr {
+ if constexpr (std::is_same_v<String, QStringView>)
+ return haystack.utf16();
+ else
+ return haystack.begin();
+ }();
+ const auto begin = start + from;
+ const auto end = start + haystack.size();
const auto r = m_searcher(begin, end, m_pattern.begin(), m_pattern.end());
- return r.begin == end ? -1 : std::distance(haystack.begin(), r.begin);
+ return r.begin == end ? -1 : std::distance(start, r.begin);
}
};
diff --git a/src/corelib/text/qstaticlatin1stringmatcher.qdoc b/src/corelib/text/qstaticlatin1stringmatcher.qdoc
index 6577f985b2..86edf69bc2 100644
--- a/src/corelib/text/qstaticlatin1stringmatcher.qdoc
+++ b/src/corelib/text/qstaticlatin1stringmatcher.qdoc
@@ -44,6 +44,7 @@
/*!
\fn template<Qt::CaseSensitivity CS, size_t N> constexpr qsizetype QStaticLatin1StringMatcher<CS, N>::indexIn(QLatin1StringView haystack, qsizetype from) const
+ \fn template<Qt::CaseSensitivity CS, size_t N> constexpr qsizetype QStaticLatin1StringMatcher<CS, N>::indexIn(QStringView haystack, qsizetype from) const
Searches the QLatin1StringView \a haystack, from byte position \a from
(default 0, i.e. from the first byte), for QLatin1StringView pattern()
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index fe9790403f..f0bf0c50a3 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -9077,7 +9077,7 @@ static inline char16_t to_unicode(const QChar c) { return c.unicode(); }
static inline char16_t to_unicode(const char c) { return QLatin1Char{c}.unicode(); }
template <typename Char>
-static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber = 999)
+static int getEscape(const Char *uc, qsizetype *pos, qsizetype len)
{
qsizetype i = *pos;
++i;
@@ -9088,17 +9088,16 @@ static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumbe
if (uint(escape) >= 10U)
return -1;
++i;
- while (i < len) {
+ if (i < len) {
+ // there's a second digit
int digit = to_unicode(uc[i]) - '0';
- if (uint(digit) >= 10U)
- break;
- escape = (escape * 10) + digit;
- ++i;
- }
- if (escape <= maxNumber) {
- *pos = i;
- return escape;
+ if (uint(digit) < 10U) {
+ escape = (escape * 10) + digit;
+ ++i;
+ }
}
+ *pos = i;
+ return escape;
}
return -1;
}
diff --git a/src/corelib/text/qstringalgorithms.h b/src/corelib/text/qstringalgorithms.h
index 538ae892b0..71a1dbd526 100644
--- a/src/corelib/text/qstringalgorithms.h
+++ b/src/corelib/text/qstringalgorithms.h
@@ -178,12 +178,21 @@ lengthHelperContainer(const Char (&str)[N])
return lengthHelperContainerLoop(str);
}
+inline qsizetype qstrnlen_helper(const char *str, size_t maxlen)
+{
+#if !defined(Q_COMPILER_SLOW_QSTRNLEN_COMPILATION)
+ return qstrnlen(str, maxlen);
+#else
+ return strnlen_s(str, maxlen);
+#endif
+}
+
template <typename Char, size_t N> [[nodiscard]] constexpr inline
std::enable_if_t<sizeof(Char) == 1, qsizetype> lengthHelperContainer(const Char (&str)[N])
{
#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
if (!q20::is_constant_evaluated())
- return qstrnlen(reinterpret_cast<const char *>(str), N);
+ return qstrnlen_helper(reinterpret_cast<const char *>(str), N);
#endif
return lengthHelperContainerLoop(str);
diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp
index 565e3e598b..67c75d708e 100644
--- a/src/corelib/text/qstringconverter.cpp
+++ b/src/corelib/text/qstringconverter.cpp
@@ -2510,6 +2510,16 @@ const char *QStringConverter::nameForEncoding(QStringConverter::Encoding e)
*/
/*!
+ \fn constexpr QStringEncoder::QStringEncoder(const QString &name, Flags flags = Flag::Default)
+ \since 6.8
+
+ Creates an encoder object using \a name and \a flags.
+ If \a name is not the name of a known encoding an invalid converter will get created.
+
+ \sa isValid()
+*/
+
+/*!
\fn QStringEncoder::DecodedData<const QString &> QStringEncoder::encode(const QString &in)
\fn QStringEncoder::DecodedData<QStringView> QStringEncoder::encode(QStringView in)
\fn QStringEncoder::DecodedData<const QString &> QStringEncoder::operator()(const QString &in)
@@ -2601,6 +2611,16 @@ const char *QStringConverter::nameForEncoding(QStringConverter::Encoding e)
*/
/*!
+ \fn constexpr QStringDecoder::QStringDecoder(const QString &name, Flags flags = Flag::Default)
+ \since 6.8
+
+ Creates an decoder object using \a name and \a flags.
+ If \a name is not the name of a known encoding an invalid converter will get created.
+
+ \sa isValid()
+*/
+
+/*!
\fn QStringDecoder::EncodedData<const QByteArray &> QStringDecoder::operator()(const QByteArray &ba)
\fn QStringDecoder::EncodedData<const QByteArray &> QStringDecoder::decode(const QByteArray &ba)
\fn QStringDecoder::EncodedData<QByteArrayView> QStringDecoder::operator()(QByteArrayView ba)
diff --git a/src/corelib/text/qstringconverter.h b/src/corelib/text/qstringconverter.h
index 055019836a..40791f8e26 100644
--- a/src/corelib/text/qstringconverter.h
+++ b/src/corelib/text/qstringconverter.h
@@ -33,6 +33,9 @@ public:
explicit QStringEncoder(const char *name, Flags flags = Flag::Default)
: QStringConverter(name, flags)
{}
+ Q_WEAK_OVERLOAD explicit QStringEncoder(const QString &name, Flags flags = Flag::Default)
+ : QStringEncoder(name.toLatin1().constData(), flags)
+ {}
template<typename T>
struct DecodedData
@@ -95,6 +98,9 @@ public:
explicit QStringDecoder(const char *name, Flags f = Flag::Default)
: QStringConverter(name, f)
{}
+ Q_WEAK_OVERLOAD explicit QStringDecoder(const QString &name, Flags f = Flag::Default)
+ : QStringDecoder(name.toLatin1().constData(), f)
+ {}
template<typename T>
struct EncodedData
diff --git a/src/corelib/text/qt_attribution.json b/src/corelib/text/qt_attribution.json
index 3ae1bd2925..6235ec5c16 100644
--- a/src/corelib/text/qt_attribution.json
+++ b/src/corelib/text/qt_attribution.json
@@ -13,11 +13,13 @@
"Comment": {
"Version": [ "Don't use the Unicode standard version;",
"UCD has its own 'Revision' numbers",
- "see the 'UAX #44, UCD' page (https://www.unicode.org/reports/tr44/)" ] },
+ "see the 'UAX #44, UCD' page (https://www.unicode.org/reports/tr44/)" ],
+ "License": [ "Will change to Unicode-3.0 on next update",
+ "util/unicode/main.cpp is updated to do that already",
+ "Please update the following and delete this note when that happens" ] },
"Version": "30",
"License": "Unicode License Agreement - Data Files and Software (2016)",
"LicenseId": "Unicode-DFS-2016",
- "LicenseFile": "UNICODE_LICENSE.txt",
"Copyright": "Copyright (C) 1991-2022 Unicode, Inc."
},
{
diff --git a/src/corelib/text/qunicodetables.cpp b/src/corelib/text/qunicodetables.cpp
index 5aeec609ef..dc93b99668 100644
--- a/src/corelib/text/qunicodetables.cpp
+++ b/src/corelib/text/qunicodetables.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2020 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
+// SPDX-License-Identifier: Unicode-DFS-2016
/* This file is autogenerated from the Unicode 15.1 database. Do not edit */
diff --git a/src/corelib/text/qunicodetables_p.h b/src/corelib/text/qunicodetables_p.h
index 25fff5cd1b..eabdc919cb 100644
--- a/src/corelib/text/qunicodetables_p.h
+++ b/src/corelib/text/qunicodetables_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2020 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
+// SPDX-License-Identifier: Unicode-DFS-2016
/* This file is autogenerated from the Unicode 15.1 database. Do not edit */
diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h
index 5939a93780..3945df066a 100644
--- a/src/corelib/thread/qfuture.h
+++ b/src/corelib/thread/qfuture.h
@@ -183,8 +183,6 @@ QT_WARNING_POP
{ future = o.future; index = o.index; return *this; }
inline const T &operator*() const { return future->d.resultReference(index); }
inline const T *operator->() const { return future->d.resultPointer(index); }
- inline bool operator!=(const const_iterator &other) const { return index != other.index; }
- inline bool operator==(const const_iterator &o) const { return !operator!=(o); }
inline const_iterator &operator++()
{ index = advanceIndex(index, 1); return *this; }
inline const_iterator &operator--()
@@ -213,6 +211,12 @@ QT_WARNING_POP
{ return const_iterator(k.future, k.advanceIndex(k.index, j)); }
private:
+ friend bool comparesEqual(const const_iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return lhs.index == rhs.index;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(const_iterator)
+
/*! \internal
Advances the iterator index \a idx \a n steps, waits for the
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index 9eda766968..b278d39882 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -613,17 +613,17 @@
Returns a pointer to the current result.
*/
-/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator!=(const const_iterator &other) const
+/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different result than this iterator;
+ Returns \c true if \a lhs points to a different result than \a rhs iterator;
otherwise returns \c false.
\sa operator==()
*/
-/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator==(const const_iterator &other) const
+/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same result as this iterator;
+ Returns \c true if \a lhs points to the same result as \a rhs iterator;
otherwise returns \c false.
\sa operator!=()
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 79fc6d9a01..351093adc7 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -287,6 +287,7 @@ using IsForwardIterable =
template<typename Function, typename ResultType, typename ParentResultType>
class Continuation
{
+ Q_DISABLE_COPY_MOVE(Continuation)
public:
template<typename F = Function>
Continuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p)
@@ -588,9 +589,6 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d);
}
-// defined in qfutureinterface.cpp:
-Q_CORE_EXPORT void watchContinuationImpl(const QObject *context, QSlotObjectBase *slotObj,
- QFutureInterfaceBase &fi);
template <typename Continuation>
void watchContinuation(const QObject *context, Continuation &&c, QFutureInterfaceBase &fi)
{
diff --git a/src/corelib/thread/qresultstore.cpp b/src/corelib/thread/qresultstore.cpp
index 14ed7c6b87..8b7601f5b0 100644
--- a/src/corelib/thread/qresultstore.cpp
+++ b/src/corelib/thread/qresultstore.cpp
@@ -88,16 +88,6 @@ void ResultIteratorBase::batchedAdvance()
m_vectorIndex = 0;
}
-bool ResultIteratorBase::operator==(const ResultIteratorBase &other) const
-{
- return (mapIterator == other.mapIterator && m_vectorIndex == other.m_vectorIndex);
-}
-
-bool ResultIteratorBase::operator!=(const ResultIteratorBase &other) const
-{
- return !operator==(other);
-}
-
bool ResultIteratorBase::isVector() const
{
return mapIterator.value().isVector();
diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h
index 30ce1fe904..f21068206f 100644
--- a/src/corelib/thread/qresultstore.h
+++ b/src/corelib/thread/qresultstore.h
@@ -46,12 +46,21 @@ public:
ResultIteratorBase operator++();
int batchSize() const;
void batchedAdvance();
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const ResultIteratorBase &other) const;
bool operator!=(const ResultIteratorBase &other) const;
+#endif
bool isVector() const;
bool canIncrementVectorIndex() const;
bool isValid() const;
+private:
+ friend bool comparesEqual(const ResultIteratorBase &lhs,
+ const ResultIteratorBase &rhs) noexcept
+ {
+ return (lhs.mapIterator == rhs.mapIterator && lhs.m_vectorIndex == rhs.m_vectorIndex);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(ResultIteratorBase)
protected:
QMap<int, ResultItem>::const_iterator mapIterator;
int m_vectorIndex;
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index a9115c5b39..ea76a2ccad 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -65,9 +65,10 @@ QThreadData::~QThreadData()
// crashing during QCoreApplicationData's global static cleanup we need to
// safeguard the main thread here.. This fix is a bit crude, but it solves
// the problem...
- if (this->thread.loadAcquire() == QCoreApplicationPrivate::theMainThread.loadAcquire()) {
- QCoreApplicationPrivate::theMainThread.storeRelease(nullptr);
- QThreadData::clearCurrentThreadData();
+ if (threadId.loadAcquire() == QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
+ QCoreApplicationPrivate::theMainThread.storeRelease(nullptr);
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(nullptr);
+ QThreadData::clearCurrentThreadData();
}
// ~QThread() sets thread to nullptr, so if it isn't null here, it's
@@ -426,6 +427,23 @@ QThread *QThread::currentThread()
}
/*!
+ \since 6.8
+
+ Returns whether the currently executing thread is the main thread.
+
+ The main thread is the thread in which QCoreApplication was created.
+ This is usually the thread that called the \c{main()} function, but not necessarily so.
+ It is the thread that is processing the GUI events and in which graphical objects
+ (QWindow, QWidget) can be created.
+
+ \sa currentThread(), QCoreApplication::instance()
+*/
+bool QThread::isMainThread()
+{
+ return currentThreadId() == QCoreApplicationPrivate::theMainThreadId.loadRelaxed();
+}
+
+/*!
Constructs a new QThread to manage a new thread. The \a parent
takes ownership of the QThread. The thread does not begin
executing until start() is called.
@@ -513,10 +531,18 @@ bool QThread::isRunning() const
}
/*!
- Sets the maximum stack size for the thread to \a stackSize. If \a
- stackSize is greater than zero, the maximum stack size is set to
- \a stackSize bytes, otherwise the maximum stack size is
- automatically determined by the operating system.
+ Sets the stack size for the thread to \a stackSize. If \a stackSize is
+ zero, the operating system or runtime will choose a default value.
+ Otherwise, the thread's stack size will be the value provided (which may be
+ rounded up or down).
+
+ On most operating systems, the amount of memory allocated to serve the
+ stack will initially be smaller than \a stackSize and will grow as the
+ thread uses the stack. This parameter sets the maximum size it will be
+ allowed to grow to (that is, it sets the size of the virtual memory space
+ the stack is allowed to occupy).
+
+ This function can only be called before the thread is started.
\warning Most operating systems place minimum and maximum limits
on thread stack sizes. The thread will fail to start if the stack
@@ -913,6 +939,36 @@ int QThread::loopLevel() const
return d->data->eventLoops.size();
}
+/*!
+ \internal
+ Returns the thread handle of this thread.
+ It can be compared with the return value of currentThreadId().
+
+ This is used to implement isCurrentThread, and might be useful
+ for debugging (e.g. by comparing the value in gdb with info threads).
+
+ \note Thread handles of destroyed threads might be reused by the
+ operating system. Storing the return value of this function can
+ therefore give surprising results if it outlives the QThread object
+ (threads claimed to be the same even if they aren't).
+*/
+Qt::HANDLE QThreadPrivate::threadId() const
+{
+ return data->threadId.loadRelaxed();
+}
+
+/*!
+ \since 6.8
+ Returns true if this thread is QThread::currentThread.
+
+ \sa currentThreadId()
+*/
+bool QThread::isCurrentThread() const
+{
+ Q_D(const QThread);
+ return QThread::currentThreadId() == d->threadId();
+}
+
#else // QT_CONFIG(thread)
QThread::QThread(QObject *parent)
@@ -985,6 +1041,11 @@ QThread *QThread::currentThread()
return QThreadData::current()->thread.loadAcquire();
}
+bool QThread::isCurrentThread() const
+{
+ return true;
+}
+
int QThread::idealThreadCount() noexcept
{
return 1;
@@ -1031,8 +1092,10 @@ QThreadData *QThreadData::current(bool createIfNecessary)
data->threadId.storeRelaxed(Qt::HANDLE(data->thread.loadAcquire()));
data->deref();
data->isAdopted = true;
- if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
+ if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
+ }
}
return data;
}
@@ -1152,11 +1215,11 @@ bool QThread::event(QEvent *event)
void QThread::requestInterruption()
{
- if (this == QCoreApplicationPrivate::theMainThread.loadAcquire()) {
+ Q_D(QThread);
+ if (d->threadId() == QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
qWarning("QThread::requestInterruption has no effect on the main thread");
return;
}
- Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (!d->running || d->finished || d->isInFinish)
return;
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h
index a4b7183b5a..641c8ef68a 100644
--- a/src/corelib/thread/qthread.h
+++ b/src/corelib/thread/qthread.h
@@ -30,6 +30,7 @@ class Q_CORE_EXPORT QThread : public QObject
public:
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION;
static QThread *currentThread();
+ static bool isMainThread();
static int idealThreadCount() noexcept;
static void yieldCurrentThread();
@@ -68,6 +69,8 @@ public:
bool event(QEvent *event) override;
int loopLevel() const;
+ bool isCurrentThread() const;
+
template <typename Function, typename... Args>
[[nodiscard]] static QThread *create(Function &&f, Args &&... args);
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index 2335ba398d..c39e21ec9a 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -179,6 +179,7 @@ public:
~QThreadPrivate();
void setPriority(QThread::Priority prio);
+ Qt::HANDLE threadId() const;
mutable QMutex mutex;
QAtomicInt quitLockRef;
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index 4b165eef9c..44487a2cc2 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -191,8 +191,10 @@ QThreadData *QThreadData::current(bool createIfNecessary)
data->deref();
data->isAdopted = true;
data->threadId.storeRelaxed(to_HANDLE(pthread_self()));
- if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
+ if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
+ }
}
return data;
}
@@ -280,8 +282,16 @@ void *QThreadPrivate::start(void *arg)
#ifdef PTHREAD_CANCEL_DISABLE
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
#endif
- pthread_cleanup_push(QThreadPrivate::finish, arg);
-
+#if !defined(Q_OS_QNX) && !defined(Q_OS_VXWORKS)
+ // On QNX, calling finish() from a thread_local destructor causes the C
+ // library to hang.
+ // On VxWorks, its pthread implementation fails on call to `pthead_setspecific` which is made
+ // by first QObject constructor during `finish()`. This causes call to QThread::current, since
+ // QObject doesn't have parent, and since the pthread is already removed, it tries to set
+ // QThreadData for current pthread key, which crashes.
+ static thread_local
+#endif
+ auto cleanup = qScopeGuard([=] { finish(arg); });
terminate_on_exception([&] {
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadData *data = QThreadData::get2(thr);
@@ -326,11 +336,7 @@ void *QThreadPrivate::start(void *arg)
thr->run();
});
- // This pop runs finish() below. It's outside the try/catch (and has its
- // own try/catch) to prevent finish() to be run in case an exception is
- // thrown.
- pthread_cleanup_pop(1);
-
+ // The qScopeGuard above call runs finish() below.
return nullptr;
}
@@ -363,7 +369,7 @@ void QThreadPrivate::finish(void *arg)
d->running = false;
d->finished = true;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
d->isInFinish = false;
d->data->threadId.storeRelaxed(nullptr);
@@ -640,7 +646,7 @@ void QThread::start(Priority priority)
d->finished = false;
d->returnCode = 0;
d->exited = false;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
pthread_attr_t attr;
pthread_attr_init(&attr);
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
index ee3b94dc3b..74bc1d2650 100644
--- a/src/corelib/thread/qthread_win.cpp
+++ b/src/corelib/thread/qthread_win.cpp
@@ -87,8 +87,9 @@ QThreadData *QThreadData::current(bool createIfNecessary)
threadData->isAdopted = true;
threadData->threadId.storeRelaxed(reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId())));
- if (!QCoreApplicationPrivate::theMainThread) {
- QCoreApplicationPrivate::theMainThread = threadData->thread.loadRelaxed();
+ if (!QCoreApplicationPrivate::theMainThreadId) {
+ QCoreApplicationPrivate::theMainThread.storeRelease(threadData->thread.loadRelaxed());
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(threadData->threadId.loadRelaxed());
} else {
HANDLE realHandle = INVALID_HANDLE_VALUE;
DuplicateHandle(GetCurrentProcess(),
@@ -313,7 +314,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) noexcept
d->running = false;
d->finished = true;
d->isInFinish = false;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
if (!d->waiters) {
CloseHandle(d->handle);
@@ -390,7 +391,7 @@ void QThread::start(Priority priority)
d->finished = false;
d->exited = false;
d->returnCode = 0;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
/*
NOTE: we create the thread in the suspended state, set the
diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp
index ae584656fe..c7531111da 100644
--- a/src/corelib/thread/qthreadpool.cpp
+++ b/src/corelib/thread/qthreadpool.cpp
@@ -258,7 +258,7 @@ void QThreadPoolPrivate::startThread(QRunnable *runnable)
/*!
\internal
- Helper function only to be called from waitForDone(int)
+ Helper function only to be called from waitForDone()
Deletes all current threads.
*/
@@ -285,22 +285,17 @@ void QThreadPoolPrivate::reset()
/*!
\internal
- Helper function only to be called from waitForDone(int)
+ Helper function only to be called from the public waitForDone()
*/
bool QThreadPoolPrivate::waitForDone(const QDeadlineTimer &timer)
{
+ QMutexLocker locker(&mutex);
while (!(queue.isEmpty() && activeThreads == 0) && !timer.hasExpired())
noActiveThreads.wait(&mutex, timer);
- return queue.isEmpty() && activeThreads == 0;
-}
-
-bool QThreadPoolPrivate::waitForDone(int msecs)
-{
- QMutexLocker locker(&mutex);
- QDeadlineTimer timer(msecs);
- if (!waitForDone(timer))
+ if (!queue.isEmpty() || activeThreads)
return false;
+
reset();
// New jobs might have started during reset, but return anyway
// as the active thread and task count did reach 0 once, and
@@ -598,18 +593,17 @@ bool QThreadPool::tryStart(QRunnable *runnable)
int QThreadPool::expiryTimeout() const
{
+ using namespace std::chrono;
Q_D(const QThreadPool);
QMutexLocker locker(&d->mutex);
- return d->expiryTimeout;
+ return duration_cast<milliseconds>(d->expiryTimeout).count();
}
void QThreadPool::setExpiryTimeout(int expiryTimeout)
{
Q_D(QThreadPool);
QMutexLocker locker(&d->mutex);
- if (d->expiryTimeout == expiryTimeout)
- return;
- d->expiryTimeout = expiryTimeout;
+ d->expiryTimeout = std::chrono::milliseconds(expiryTimeout);
}
/*! \property QThreadPool::maxThreadCount
@@ -808,15 +802,24 @@ void QThreadPool::startOnReservedThread(QRunnable *runnable)
*/
/*!
+ \fn bool QThreadPool::waitForDone(int msecs)
Waits up to \a msecs milliseconds for all threads to exit and removes all
threads from the thread pool. Returns \c true if all threads were removed;
- otherwise it returns \c false. If \a msecs is -1 (the default), the timeout
- is ignored (waits for the last thread to exit).
+ otherwise it returns \c false. If \a msecs is -1, this function waits for
+ the last thread to exit.
+*/
+
+/*!
+ \since 6.8
+
+ Waits until \a deadline expires for all threads to exit and removes all
+ threads from the thread pool. Returns \c true if all threads were removed;
+ otherwise it returns \c false.
*/
-bool QThreadPool::waitForDone(int msecs)
+bool QThreadPool::waitForDone(QDeadlineTimer deadline)
{
Q_D(QThreadPool);
- return d->waitForDone(msecs);
+ return d->waitForDone(deadline);
}
/*!
diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h
index a097ace14b..0640f41587 100644
--- a/src/corelib/thread/qthreadpool.h
+++ b/src/corelib/thread/qthreadpool.h
@@ -9,7 +9,9 @@
#include <QtCore/qthread.h>
#include <QtCore/qrunnable.h>
+#if QT_CORE_REMOVED_SINCE(6, 6)
#include <functional>
+#endif
QT_REQUIRE_CONFIG(thread);
@@ -70,7 +72,9 @@ public:
void reserveThread();
void releaseThread();
- bool waitForDone(int msecs = -1);
+ QT_CORE_INLINE_SINCE(6, 8)
+ bool waitForDone(int msecs);
+ bool waitForDone(QDeadlineTimer deadline = QDeadlineTimer::Forever);
void clear();
@@ -101,6 +105,13 @@ void QThreadPool::startOnReservedThread(Callable &&functionToRun)
startOnReservedThread(QRunnable::create(std::forward<Callable>(functionToRun)));
}
+#if QT_CORE_INLINE_IMPL_SINCE(6, 8)
+bool QThreadPool::waitForDone(int msecs)
+{
+ return waitForDone(QDeadlineTimer(msecs));
+}
+#endif
+
QT_END_NAMESPACE
#endif
diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h
index 67c703fabd..7910592f70 100644
--- a/src/corelib/thread/qthreadpool_p.h
+++ b/src/corelib/thread/qthreadpool_p.h
@@ -128,7 +128,6 @@ public:
{ return qMax(requestedMaxThreadCount, 1); } // documentation says we start at least one
void startThread(QRunnable *runnable = nullptr);
void reset();
- bool waitForDone(int msecs);
bool waitForDone(const QDeadlineTimer &timer);
void clear();
void stealAndRunRunnable(QRunnable *runnable);
@@ -144,7 +143,7 @@ public:
QWaitCondition noActiveThreads;
QString objectName;
- int expiryTimeout = 30000;
+ std::chrono::duration<int, std::milli> expiryTimeout = std::chrono::seconds(30);
int requestedMaxThreadCount = QThread::idealThreadCount(); // don't use this directly
int reservedThreads = 0;
int activeThreads = 0;
diff --git a/src/corelib/time/qcalendar.cpp b/src/corelib/time/qcalendar.cpp
index 415203ee17..c87d4b7cf3 100644
--- a/src/corelib/time/qcalendar.cpp
+++ b/src/corelib/time/qcalendar.cpp
@@ -498,8 +498,8 @@ Q_GLOBAL_STATIC(QtPrivate::QCalendarRegistry, calendarRegistry);
base-classes for custom calendar backends, but cannot be instantiated
themselves.
- \sa calendarId(), QDate, QDateTime, QDateEdit,
- QDateTimeEdit, QCalendarWidget
+ \sa calendarId(), QDate, QDateTime, QDateEdit, QDateTimeEdit,
+ QCalendarWidget, {The Low-Level API: Extending Qt Applications}
*/
/*!
diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h
index e1c0d29e2a..a9fefc4c22 100644
--- a/src/corelib/time/qdatetime.h
+++ b/src/corelib/time/qdatetime.h
@@ -529,7 +529,7 @@ public:
QT_POST_CXX17_API_IN_EXPORTED_CLASS
static QDateTime fromStdLocalTime(const std::chrono::local_time<std::chrono::milliseconds> &time)
{
- QDateTime result(QDate(1970, 1, 1), QTime(0, 0, 0));
+ QDateTime result(QDate(1970, 1, 1), QTime(0, 0, 0), TransitionResolution::LegacyBehavior);
return result.addMSecs(time.time_since_epoch().count());
}
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index 78520a51aa..cce32e7ad2 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -334,7 +334,7 @@ int QDateTimeParser::sectionPos(int sectionIndex) const
return sectionPos(sectionNode(sectionIndex));
}
-int QDateTimeParser::sectionPos(const SectionNode &sn) const
+int QDateTimeParser::sectionPos(SectionNode sn) const
{
switch (sn.type) {
case FirstSection: return 0;
@@ -2314,11 +2314,9 @@ QString QDateTimeParser::getAmPmText(AmPm ap, Case cs) const
/*
\internal
-
- I give arg2 preference because arg1 is always a QDateTime.
*/
-bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2)
+bool operator==(QDateTimeParser::SectionNode s1, QDateTimeParser::SectionNode s2)
{
return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count);
}
diff --git a/src/corelib/time/qdatetimeparser_p.h b/src/corelib/time/qdatetimeparser_p.h
index faf383f3d7..30e9e4d524 100644
--- a/src/corelib/time/qdatetimeparser_p.h
+++ b/src/corelib/time/qdatetimeparser_p.h
@@ -212,7 +212,7 @@ protected: // for the benefit of QDateTimeEditPrivate
int sectionSize(int index) const;
int sectionMaxSize(int index) const;
int sectionPos(int index) const;
- int sectionPos(const SectionNode &sn) const;
+ int sectionPos(SectionNode sn) const;
const SectionNode &sectionNode(int index) const;
Section sectionType(int index) const;
@@ -265,7 +265,7 @@ protected: // for the benefit of QDateTimeEditPrivate
};
Q_DECLARE_TYPEINFO(QDateTimeParser::SectionNode, Q_PRIMITIVE_TYPE);
-Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2);
+Q_CORE_EXPORT bool operator==(QDateTimeParser::SectionNode s1, QDateTimeParser::SectionNode s2);
Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections)
Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo)
diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp
index 558cb53a08..3a68277a6c 100644
--- a/src/corelib/time/qtimezone.cpp
+++ b/src/corelib/time/qtimezone.cpp
@@ -908,7 +908,7 @@ QString QTimeZone::displayName(const QDateTime &atDateTime, NameType nameType,
return systemTimeZone().displayName(atDateTime, nameType, locale);
case Qt::UTC:
case Qt::OffsetFromUTC:
- return QUtcTimeZonePrivate(d.s.offset).QTimeZonePrivate::displayName(
+ return QUtcTimeZonePrivate(d.s.offset).displayName(
atDateTime.toMSecsSinceEpoch(), nameType, locale);
case Qt::TimeZone:
Q_UNREACHABLE();
diff --git a/src/corelib/time/qtimezonelocale.cpp b/src/corelib/time/qtimezonelocale.cpp
index 5757e55d28..cf3a84b317 100644
--- a/src/corelib/time/qtimezonelocale.cpp
+++ b/src/corelib/time/qtimezonelocale.cpp
@@ -4,7 +4,9 @@
#include <private/qtimezonelocale_p.h>
#include <private/qtimezoneprivate_p.h>
-#if !QT_CONFIG(icu) // Use data generated from CLDR:
+#if !QT_CONFIG(icu)
+# include <private/qdatetime_p.h>
+// Use data generated from CLDR:
# include <private/qtimezonelocale_data_p.h>
# include <private/qtimezoneprivate_data_p.h>
#endif
@@ -12,9 +14,90 @@
QT_BEGIN_NAMESPACE
#if QT_CONFIG(icu) // Get data from ICU:
+namespace {
+
+// Convert TimeType and NameType into ICU UCalendarDisplayNameType
+constexpr UCalendarDisplayNameType ucalDisplayNameType(QTimeZone::TimeType timeType,
+ QTimeZone::NameType nameType)
+{
+ // TODO ICU C UCalendarDisplayNameType does not support full set of C++ TimeZone::EDisplayType
+ // For now, treat Generic as Standard
+ switch (nameType) {
+ case QTimeZone::OffsetName:
+ Q_UNREACHABLE(); // Callers of ucalTimeZoneDisplayName() should take care of OffsetName.
+ case QTimeZone::ShortName:
+ return timeType == QTimeZone::DaylightTime ? UCAL_SHORT_DST : UCAL_SHORT_STANDARD;
+ case QTimeZone::DefaultName:
+ case QTimeZone::LongName:
+ return timeType == QTimeZone::DaylightTime ? UCAL_DST : UCAL_STANDARD;
+ }
+ Q_UNREACHABLE_RETURN(UCAL_STANDARD);
+}
+
+} // nameless namespace
+
namespace QtTimeZoneLocale {
+// Qt wrapper around ucal_getTimeZoneDisplayName()
+// Used directly by ICU backend; indirectly by TZ (see below).
+QString ucalTimeZoneDisplayName(UCalendar *ucal,
+ QTimeZone::TimeType timeType,
+ QTimeZone::NameType nameType,
+ const QByteArray &localeCode)
+{
+ constexpr int32_t BigNameLength = 50;
+ int32_t size = BigNameLength;
+ QString result(size, Qt::Uninitialized);
+ auto dst = [&result]() { return reinterpret_cast<UChar *>(result.data()); };
+ UErrorCode status = U_ZERO_ERROR;
+ const UCalendarDisplayNameType utype = ucalDisplayNameType(timeType, nameType);
+
+ // size = ucal_getTimeZoneDisplayName(cal, type, locale, result, resultLength, status)
+ size = ucal_getTimeZoneDisplayName(ucal, utype, localeCode.constData(),
+ dst(), size, &status);
+
+ // If overflow, then resize and retry
+ if (size > BigNameLength || status == U_BUFFER_OVERFLOW_ERROR) {
+ result.resize(size);
+ status = U_ZERO_ERROR;
+ size = ucal_getTimeZoneDisplayName(ucal, utype, localeCode.constData(),
+ dst(), size, &status);
+ }
+
+ if (!U_SUCCESS(status))
+ return QString();
+
+ // Resize and return:
+ result.resize(size);
+ return result;
+}
+
} // QtTimeZoneLocale
+
+// Used by TZ backends when ICU is available:
+QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc,
+ QTimeZone::TimeType timeType,
+ QTimeZone::NameType nameType,
+ const QLocale &locale) const
+{
+ Q_UNUSED(atMSecsSinceEpoch);
+ // TODO: use CLDR data for the offset name.
+ // No ICU API for offset formats, so fall back to our ISO one, even if
+ // locale isn't C:
+ if (nameType == QTimeZone::OffsetName)
+ return isoOffsetFormat(offsetFromUtc);
+
+ const QString id = QString::fromUtf8(m_id);
+ const QByteArray loc = locale.name().toUtf8();
+ UErrorCode status = U_ZERO_ERROR;
+ UCalendar *ucal = ucal_open(reinterpret_cast<const UChar *>(id.data()), id.size(),
+ loc.constData(), UCAL_DEFAULT, &status);
+ if (ucal && U_SUCCESS(status)) {
+ auto tidier = qScopeGuard([ucal]() { ucal_close(ucal); });
+ return QtTimeZoneLocale::ucalTimeZoneDisplayName(ucal, timeType, nameType, loc);
+ }
+ return QString();
+}
#else // No ICU, use QTZ[LP}_data_p.h data for feature timezone_locale.
namespace {
using namespace QtTimeZoneLocale; // QTZL_data_p.h
@@ -24,6 +107,20 @@ using namespace QtTimeZoneCldr; // QTZP_data_p.h
// Accessors for the QTZP_data_p.h
} // nameless namespace
+
+QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc,
+ QTimeZone::TimeType timeType,
+ QTimeZone::NameType nameType,
+ const QLocale &locale) const
+{
+ Q_ASSERT(nameType != QTimeZone::OffsetName || locale.language() != QLocale::C);
+ // Get data from QTZ[LP]_data_p.h
+
+ Q_UNUSED(atMSecsSinceEpoch);
+ Q_UNUSED(offsetFromUtc);
+ Q_UNUSED(timeType);
+ return QString();
+}
#endif // ICU
QT_END_NAMESPACE
diff --git a/src/corelib/time/qtimezonelocale_p.h b/src/corelib/time/qtimezonelocale_p.h
index adc8e83b35..6e6c6b51fd 100644
--- a/src/corelib/time/qtimezonelocale_p.h
+++ b/src/corelib/time/qtimezonelocale_p.h
@@ -14,18 +14,31 @@
//
// We mean it.
//
+#include <private/qglobal_p.h>
+#include <QtCore/qstring.h>
#include <QtCore/qtimezone.h>
+#if QT_CONFIG(icu)
+#include <unicode/ucal.h>
+#endif
+
QT_REQUIRE_CONFIG(timezone);
QT_REQUIRE_CONFIG(timezone_locale);
+QT_BEGIN_NAMESPACE
+
namespace QtTimeZoneLocale {
#if QT_CONFIG(icu)
+QString ucalTimeZoneDisplayName(UCalendar *ucal, QTimeZone::TimeType timeType,
+ QTimeZone::NameType nameType,
+ const QString &localeCode);
#else
// Define data types for QTZL_data_p.h
#endif
}
+QT_END_NAMESPACE
+
#endif // QTIMEZONELOCALE_P_H
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp
index 2ad0d874b6..f3dc43df6a 100644
--- a/src/corelib/time/qtimezoneprivate.cpp
+++ b/src/corelib/time/qtimezoneprivate.cpp
@@ -5,6 +5,9 @@
#include "qtimezone.h"
#include "qtimezoneprivate_p.h"
+#if QT_CONFIG(timezone_locale)
+# include "qtimezonelocale_p.h"
+#endif
#include "qtimezoneprivate_data_p.h"
#include <qdatastream.h>
@@ -172,22 +175,37 @@ QString QTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch,
QTimeZone::NameType nameType,
const QLocale &locale) const
{
- if (nameType == QTimeZone::OffsetName)
- return isoOffsetFormat(offsetFromUtc(atMSecsSinceEpoch));
-
- if (isDaylightTime(atMSecsSinceEpoch))
- return displayName(QTimeZone::DaylightTime, nameType, locale);
- else
- return displayName(QTimeZone::StandardTime, nameType, locale);
+ const Data tran = data(atMSecsSinceEpoch);
+ if (tran.atMSecsSinceEpoch != invalidMSecs()) {
+ if (nameType == QTimeZone::OffsetName && locale.language() == QLocale::C)
+ return isoOffsetFormat(tran.offsetFromUtc);
+ if (nameType == QTimeZone::ShortName && isDataLocale(locale))
+ return tran.abbreviation;
+
+ QTimeZone::TimeType timeType
+ = tran.daylightTimeOffset != 0 ? QTimeZone::DaylightTime : QTimeZone::StandardTime;
+#if QT_CONFIG(timezone_locale)
+ return localeName(atMSecsSinceEpoch, tran.offsetFromUtc, timeType, nameType, locale);
+#else
+ return displayName(timeType, nameType, locale);
+#endif
+ }
+ return QString();
}
QString QTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const
{
- Q_UNUSED(timeType);
- Q_UNUSED(nameType);
- Q_UNUSED(locale);
+ const Data tran = data(timeType);
+ if (tran.atMSecsSinceEpoch != invalidMSecs()) {
+ if (nameType == QTimeZone::OffsetName && isDataLocale(locale))
+ return isoOffsetFormat(tran.offsetFromUtc);
+
+#if QT_CONFIG(timezone_locale)
+ return localeName(tran.atMSecsSinceEpoch, tran.offsetFromUtc, timeType, nameType, locale);
+#endif
+ }
return QString();
}
@@ -227,6 +245,56 @@ bool QTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const
return false;
}
+QTimeZonePrivate::Data QTimeZonePrivate::data(QTimeZone::TimeType timeType) const
+{
+ // True if tran is valid and has the DST-ness to match timeType:
+ const auto validMatch = [timeType](const QTimeZonePrivate::Data &tran) {
+ return tran.atMSecsSinceEpoch != invalidMSecs()
+ && ((timeType == QTimeZone::DaylightTime) != (tran.daylightTimeOffset == 0));
+ };
+
+ // Get current tran, use if suitable:
+ const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch();
+ QTimeZonePrivate::Data tran = data(currentMSecs);
+ if (validMatch(tran))
+ return tran;
+
+ if (hasTransitions()) {
+ // Otherwise, next tran probably flips DST-ness:
+ tran = nextTransition(currentMSecs);
+ if (validMatch(tran))
+ return tran;
+
+ // Failing that, prev (or present, if current MSecs is exactly a
+ // transition moment) tran defines what data() got us and the one before
+ // that probably flips DST-ness; failing that, keep marching backwards
+ // in search of a DST interval:
+ tran = previousTransition(currentMSecs + 1);
+ while (tran.atMSecsSinceEpoch != invalidMSecs()) {
+ tran = previousTransition(tran.atMSecsSinceEpoch);
+ if (validMatch(tran))
+ return tran;
+ }
+ }
+ return {};
+}
+
+/*!
+ \internal
+
+ Returns true if the abbreviation given in data()'s returns is appropriate
+ for use in the given \a locale.
+
+ Base implementation assumes data() corresponds to the system locale; derived
+ classes should override if their data() is something else (such as
+ C/English).
+*/
+bool QTimeZonePrivate::isDataLocale(const QLocale &locale) const
+{
+ // Guess data is for the system locale unless backend overrides that.
+ return locale == QLocale::system();
+}
+
QTimeZonePrivate::Data QTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
{
Q_UNUSED(forMSecsSinceEpoch);
@@ -906,6 +974,19 @@ QTimeZonePrivate::Data QUtcTimeZonePrivate::data(qint64 forMSecsSinceEpoch) cons
return d;
}
+// Override to shortcut past base's complications:
+QTimeZonePrivate::Data QUtcTimeZonePrivate::data(QTimeZone::TimeType timeType) const
+{
+ Q_UNUSED(timeType);
+ return data(QDateTime::currentMSecsSinceEpoch());
+}
+
+bool QUtcTimeZonePrivate::isDataLocale(const QLocale &locale) const
+{
+ // Officially only supports C locale names; these are surely also viable for English.
+ return locale.language() == QLocale::C || locale.language() == QLocale::English;
+}
+
void QUtcTimeZonePrivate::init(const QByteArray &zoneId)
{
m_id = zoneId;
@@ -933,6 +1014,15 @@ QString QUtcTimeZonePrivate::comment() const
return m_comment;
}
+// Override to bypass complications in base-class:
+QString QUtcTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch,
+ QTimeZone::NameType nameType,
+ const QLocale &locale) const
+{
+ Q_UNUSED(atMSecsSinceEpoch);
+ return displayName(QTimeZone::StandardTime, nameType, locale);
+}
+
QString QUtcTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const
diff --git a/src/corelib/time/qtimezoneprivate_data_p.h b/src/corelib/time/qtimezoneprivate_data_p.h
index 659605b224..5174f06a0d 100644
--- a/src/corelib/time/qtimezoneprivate_data_p.h
+++ b/src/corelib/time/qtimezoneprivate_data_p.h
@@ -74,27 +74,6 @@ struct UtcData
constexpr QByteArrayView id() const; // Space-joined list of IANA IDs
};
-/*
- COPYRIGHT AND PERMISSION NOTICE
-
- Copyright © 1991-2012 Unicode, Inc. All rights reserved. Distributed under
- the Terms of Use in http://www.unicode.org/copyright.html.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of the Unicode data files and any associated documentation (the "Data
- Files") or Unicode software and any associated documentation (the "Software")
- to deal in the Data Files or Software without restriction, including without
- limitation the rights to use, copy, modify, merge, publish, distribute, and/or
- sell copies of the Data Files or Software, and to permit persons to whom the
- Data Files or Software are furnished to do so, provided that (a) the above
- copyright notice(s) and this permission notice appear with all copies of the
- Data Files or Software, (b) both the above copyright notice(s) and this
- permission notice appear in associated documentation, and (c) there is clear
- notice in each modified Data File or in the Software as well as in the
- documentation associated with the Data File(s) or Software that the data or
- software has been modified.
-*/
-
// GENERATED PART STARTS HERE
/*
diff --git a/src/corelib/time/qtimezoneprivate_icu.cpp b/src/corelib/time/qtimezoneprivate_icu.cpp
index 1a3baa70d0..a9fe68b83c 100644
--- a/src/corelib/time/qtimezoneprivate_icu.cpp
+++ b/src/corelib/time/qtimezoneprivate_icu.cpp
@@ -4,6 +4,7 @@
#include "qtimezone.h"
#include "qtimezoneprivate_p.h"
+#include "qtimezonelocale_p.h"
#include <unicode/ucal.h>
@@ -22,27 +23,6 @@ QT_BEGIN_NAMESPACE
// ICU utilities
-// Convert TimeType and NameType into ICU UCalendarDisplayNameType
-static UCalendarDisplayNameType ucalDisplayNameType(QTimeZone::TimeType timeType, QTimeZone::NameType nameType)
-{
- // TODO ICU C UCalendarDisplayNameType does not support full set of C++ TimeZone::EDisplayType
- switch (nameType) {
- case QTimeZone::ShortName :
- case QTimeZone::OffsetName :
- if (timeType == QTimeZone::DaylightTime)
- return UCAL_SHORT_DST;
- // Includes GenericTime
- return UCAL_SHORT_STANDARD;
- case QTimeZone::DefaultName :
- case QTimeZone::LongName :
- if (timeType == QTimeZone::DaylightTime)
- return UCAL_DST;
- // Includes GenericTime
- return UCAL_STANDARD;
- }
- return UCAL_STANDARD;
-}
-
// Qt wrapper around ucal_getDefaultTimeZone()
static QByteArray ucalDefaultTimeZoneId()
{
@@ -69,44 +49,6 @@ static QByteArray ucalDefaultTimeZoneId()
return QByteArray();
}
-// Qt wrapper around ucal_getTimeZoneDisplayName()
-static QString ucalTimeZoneDisplayName(UCalendar *ucal, QTimeZone::TimeType timeType,
- QTimeZone::NameType nameType,
- const QString &localeCode)
-{
- int32_t size = 50;
- QString result(size, Qt::Uninitialized);
- UErrorCode status = U_ZERO_ERROR;
-
- // size = ucal_getTimeZoneDisplayName(cal, type, locale, result, resultLength, status)
- size = ucal_getTimeZoneDisplayName(ucal,
- ucalDisplayNameType(timeType, nameType),
- localeCode.toUtf8(),
- reinterpret_cast<UChar *>(result.data()),
- size,
- &status);
-
- // If overflow, then resize and retry
- if (status == U_BUFFER_OVERFLOW_ERROR) {
- result.resize(size);
- status = U_ZERO_ERROR;
- size = ucal_getTimeZoneDisplayName(ucal,
- ucalDisplayNameType(timeType, nameType),
- localeCode.toUtf8(),
- reinterpret_cast<UChar *>(result.data()),
- size,
- &status);
- }
-
- // If successful on first or second go, resize and return
- if (U_SUCCESS(status)) {
- result.resize(size);
- return result;
- }
-
- return QString();
-}
-
// Qt wrapper around ucal_get() for offsets
static bool ucalOffsetsAtTime(UCalendar *m_ucal, qint64 atMSecsSinceEpoch,
int *utcOffset, int *dstOffset)
@@ -203,13 +145,11 @@ static QTimeZonePrivate::Data ucalTimeZoneTransition(UCalendar *m_ucal,
tran.offsetFromUtc = utc + dst;
tran.standardTimeOffset = utc;
tran.daylightTimeOffset = dst;
- // TODO No ICU API, use short name instead
- if (dst == 0)
- tran.abbreviation = ucalTimeZoneDisplayName(m_ucal, QTimeZone::StandardTime,
- QTimeZone::ShortName, QLocale().name());
- else
- tran.abbreviation = ucalTimeZoneDisplayName(m_ucal, QTimeZone::DaylightTime,
- QTimeZone::ShortName, QLocale().name());
+ // TODO No ICU API, use short name as abbreviation.
+ QTimeZone::TimeType timeType = dst == 0 ? QTimeZone::StandardTime : QTimeZone::DaylightTime;
+ using namespace QtTimeZoneLocale;
+ tran.abbreviation = ucalTimeZoneDisplayName(m_ucal, timeType,
+ QTimeZone::ShortName, QLocale().name());
return tran;
}
#endif // U_ICU_VERSION_SHORT
@@ -317,6 +257,7 @@ QString QIcuTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
}
// Technically this may be suspect, if locale isn't QLocale(), since that's
// what we used when constructing m_ucal; does ICU cope with inconsistency ?
+ using namespace QtTimeZoneLocale;
return ucalTimeZoneDisplayName(m_ucal, timeType, nameType, locale.name());
}
diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h
index 4ad51f44e7..5d57ed7558 100644
--- a/src/corelib/time/qtimezoneprivate_p.h
+++ b/src/corelib/time/qtimezoneprivate_p.h
@@ -99,6 +99,8 @@ public:
virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
virtual Data data(qint64 forMSecsSinceEpoch) const;
+ virtual Data data(QTimeZone::TimeType timeType) const;
+ virtual bool isDataLocale(const QLocale &locale) const;
QDateTimePrivate::ZoneState stateAtZoneTime(qint64 forLocalMSecs,
QDateTimePrivate::TransitionOptions resolve) const;
@@ -150,6 +152,15 @@ public:
return QByteArrayLiteral("UTC");
}
+#if QT_CONFIG(timezone_locale)
+private:
+ // Defined in qtimezonelocale.cpp
+ QString localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc,
+ QTimeZone::TimeType timeType,
+ QTimeZone::NameType nameType,
+ const QLocale &locale) const;
+#endif // L10n helpers.
+
protected:
QByteArray m_id;
};
@@ -179,10 +190,15 @@ public:
QUtcTimeZonePrivate *clone() const override;
Data data(qint64 forMSecsSinceEpoch) const override;
+ Data data(QTimeZone::TimeType timeType) const override;
+ bool isDataLocale(const QLocale &locale) const override;
QLocale::Territory territory() const override;
QString comment() const override;
+ QString displayName(qint64 atMSecsSinceEpoch,
+ QTimeZone::NameType nameType,
+ const QLocale &locale) const override;
QString displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const override;
@@ -213,7 +229,10 @@ private:
int m_offsetFromUtc;
};
-#if QT_CONFIG(icu)
+// TODO: shuffle (almost reverse) order of and rework #if-ery here to use #elif
+// and match the #if-ery in each of QTZ's newBackendTimeZone() cascades for
+// backend selection.
+#if QT_CONFIG(icu) && !defined(Q_OS_UNIX)
class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate
{
public:
@@ -237,6 +256,7 @@ public:
bool hasDaylightTime() const override;
bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
+ using QTimeZonePrivate::data;
Data data(qint64 forMSecsSinceEpoch) const override;
bool hasTransitions() const override;
@@ -255,7 +275,7 @@ private:
UCalendar *m_ucal;
};
-#endif
+#endif // ICU not on Unix.
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
struct QTzTransitionTime
@@ -303,6 +323,7 @@ public:
QLocale::Territory territory() const override;
QString comment() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const override;
@@ -316,6 +337,8 @@ public:
bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
Data data(qint64 forMSecsSinceEpoch) const override;
+ Data data(QTimeZone::TimeType timeType) const override;
+ bool isDataLocale(const QLocale &locale) const override;
bool hasTransitions() const override;
Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
@@ -333,14 +356,6 @@ private:
Data dataForTzTransition(QTzTransitionTime tran) const;
Data dataFromRule(QTzTransitionRule rule, qint64 msecsSinceEpoch) const;
-#if QT_CONFIG(icu)
-# ifdef __cpp_lib_is_final
- static_assert(std::is_final<QIcuTimeZonePrivate>::value,
- "if QIcuTimeZonePrivate isn't final, we may need to specialize "
- "QExplicitlySharedDataPointer::clone() to call QTimeZonePrivate::clone()");
-# endif
- mutable QExplicitlySharedDataPointer<const QIcuTimeZonePrivate> m_icu;
-#endif
QTzTimeZoneCacheEntry cached_data;
const QList<QTzTransitionTime> &tranCache() const { return cached_data.m_tranTimes; }
};
@@ -361,6 +376,7 @@ public:
QString comment() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const override;
QString abbreviation(qint64 atMSecsSinceEpoch) const override;
@@ -372,6 +388,7 @@ public:
bool hasDaylightTime() const override;
bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
+ using QTimeZonePrivate::data;
Data data(qint64 forMSecsSinceEpoch) const override;
bool hasTransitions() const override;
@@ -414,6 +431,7 @@ public:
QString comment() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const override;
QString abbreviation(qint64 atMSecsSinceEpoch) const override;
@@ -425,6 +443,7 @@ public:
bool hasDaylightTime() const override;
bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
+ using QTimeZonePrivate::data;
Data data(qint64 forMSecsSinceEpoch) const override;
bool hasTransitions() const override;
@@ -462,6 +481,7 @@ public:
QAndroidTimeZonePrivate *clone() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const override;
QString abbreviation(qint64 atMSecsSinceEpoch) const override;
@@ -473,6 +493,7 @@ public:
bool hasDaylightTime() const override;
bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
+ using QTimeZonePrivate::data;
Data data(qint64 forMSecsSinceEpoch) const override;
QByteArray systemTimeZoneId() const override;
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp
index f6156fe93e..8d14e75193 100644
--- a/src/corelib/time/qtimezoneprivate_tz.cpp
+++ b/src/corelib/time/qtimezoneprivate_tz.cpp
@@ -33,10 +33,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-#if QT_CONFIG(icu)
-Q_CONSTINIT static QBasicMutex s_icu_mutex;
-#endif
-
/*
Private
@@ -771,9 +767,6 @@ QTzTimeZonePrivate::~QTzTimeZonePrivate()
QTzTimeZonePrivate *QTzTimeZonePrivate::clone() const
{
-#if QT_CONFIG(icu)
- const auto lock = qt_scoped_lock(s_icu_mutex);
-#endif
return new QTzTimeZonePrivate(*this);
}
@@ -1007,15 +1000,7 @@ QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId)
if (m_id.isEmpty()) {
// This can only happen for the system zone, when we've read the
// contents of /etc/localtime because it wasn't a symlink.
-#if QT_CONFIG(icu)
- // Use ICU's system zone, if only to avoid using the abbreviation as ID
- // (ICU might mis-recognize it) in displayName().
- m_icu = new QIcuTimeZonePrivate();
- // Use its ID, as an alternate source of data:
- m_id = m_icu->id();
- if (!m_id.isEmpty())
- return;
-#endif
+ // TODO: use CLDR generic abbreviation for the zone.
m_id = abbreviation(QDateTime::currentMSecsSinceEpoch()).toUtf8();
}
}
@@ -1034,70 +1019,19 @@ QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const
{
- // TZ DB lacks localized names (it only has IANA IDs), so delegate to ICU
- // for those, when available.
-#if QT_CONFIG(icu)
- {
- auto lock = qt_scoped_lock(s_icu_mutex);
- // TODO Some valid TZ names are not valid ICU names, use translation table?
- if (!m_icu)
- m_icu = new QIcuTimeZonePrivate(m_id);
- if (m_icu->isValid())
- return m_icu->displayName(timeType, nameType, locale);
- }
-#else
- Q_UNUSED(timeType);
- Q_UNUSED(nameType);
- Q_UNUSED(locale);
-#endif
- // If ICU is unavailable, fall back to abbreviations.
- // Abbreviations don't have GenericTime
- if (timeType == QTimeZone::GenericTime)
- timeType = QTimeZone::StandardTime;
-
- // Get current tran, if valid and is what we want, then use it
- const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch();
- QTimeZonePrivate::Data tran = data(currentMSecs);
- if (tran.atMSecsSinceEpoch != invalidMSecs()
- && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)
- || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {
- return tran.abbreviation;
- }
-
- // Otherwise get next tran and if valid and is what we want, then use it
- tran = nextTransition(currentMSecs);
- if (tran.atMSecsSinceEpoch != invalidMSecs()
- && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)
- || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {
- return tran.abbreviation;
- }
-
- // Otherwise get prev tran and if valid and is what we want, then use it
- tran = previousTransition(currentMSecs);
- if (tran.atMSecsSinceEpoch != invalidMSecs())
- tran = previousTransition(tran.atMSecsSinceEpoch);
- if (tran.atMSecsSinceEpoch != invalidMSecs()
- && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)
- || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {
- return tran.abbreviation;
- }
-
- // Otherwise is strange sequence, so work backwards through trans looking for first match, if any
- auto it = std::partition_point(tranCache().cbegin(), tranCache().cend(),
- [currentMSecs](const QTzTransitionTime &at) {
- return at.atMSecsSinceEpoch <= currentMSecs;
- });
-
- while (it != tranCache().cbegin()) {
- --it;
- tran = dataForTzTransition(*it);
- int offset = tran.daylightTimeOffset;
- if ((timeType == QTimeZone::DaylightTime) != (offset == 0))
- return tran.abbreviation;
+ // TZ only provides C-locale abbreviations and offset:
+ if (nameType != QTimeZone::LongName && isDataLocale(locale)) {
+ QTimeZonePrivate::Data tran = data(timeType);
+ if (tran.atMSecsSinceEpoch != invalidMSecs()) {
+ if (nameType == QTimeZone::ShortName)
+ return tran.abbreviation;
+ // Save base class repeating the data(timeType) query:
+ if (locale.language() == QLocale::C)
+ return isoOffsetFormat(tran.offsetFromUtc);
+ }
}
-
- // Otherwise if no match use current data
- return data(currentMSecs).abbreviation;
+ // Otherwise, fall back to base class (and qtimezonelocale.cpp):
+ return QTimeZonePrivate::displayName(timeType, nameType, locale);
}
QString QTzTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const
@@ -1184,6 +1118,64 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
return dataFromRule(cached_data.m_tranRules.at(last->ruleIndex), forMSecsSinceEpoch);
}
+// Overridden because the final iteration over transitions only needs to look
+// forward and backwards one transition within the POSIX rule (when there is
+// one, as is common) to settle the whole period it covers, so we can then skip
+// all other transitions of the POSIX rule and iterate tranCache() backwards
+// from its most recent transition.
+QTimeZonePrivate::Data QTzTimeZonePrivate::data(QTimeZone::TimeType timeType) const
+{
+ // True if tran is valid and has the DST-ness to match timeType:
+ const auto validMatch = [timeType](const QTimeZonePrivate::Data &tran) {
+ return tran.atMSecsSinceEpoch != invalidMSecs()
+ && ((timeType == QTimeZone::DaylightTime) != (tran.daylightTimeOffset == 0));
+ };
+
+ // Get current tran, use if suitable:
+ const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch();
+ QTimeZonePrivate::Data tran = data(currentMSecs);
+ if (validMatch(tran))
+ return tran;
+
+ // Otherwise, next tran probably flips DST-ness:
+ tran = nextTransition(currentMSecs);
+ if (validMatch(tran))
+ return tran;
+
+ // Failing that, prev (or present, if current MSecs is eactly a transition
+ // moment) tran defines what data() got us and the one before that probably
+ // flips DST-ness:
+ tran = previousTransition(currentMSecs + 1);
+ if (tran.atMSecsSinceEpoch != invalidMSecs())
+ tran = previousTransition(tran.atMSecsSinceEpoch);
+ if (validMatch(tran))
+ return tran;
+
+ // Otherwise, we can look backwards through transitions for a match; if we
+ // have a POSIX rule, it clearly doesn't do DST (or we'd have hit it by
+ // now), so we only need to look in the tranCache() up to now.
+ const auto untilNow = [currentMSecs](const QTzTransitionTime &at) {
+ return at.atMSecsSinceEpoch <= currentMSecs;
+ };
+ auto it = std::partition_point(tranCache().cbegin(), tranCache().cend(), untilNow);
+ // That's the end or first future transition; we don't want to look at it,
+ // but at all those before it.
+ while (it != tranCache().cbegin()) {
+ --it;
+ tran = dataForTzTransition(*it);
+ if ((timeType == QTimeZone::DaylightTime) != (tran.daylightTimeOffset == 0))
+ return tran;
+ }
+
+ return {};
+}
+
+bool QTzTimeZonePrivate::isDataLocale(const QLocale &locale) const
+{
+ // TZ data uses English / C locale names:
+ return locale.language() == QLocale::C || locale.language() == QLocale::English;
+}
+
bool QTzTimeZonePrivate::hasTransitions() const
{
return true;
diff --git a/src/corelib/tools/qatomicscopedvaluerollback.h b/src/corelib/tools/qatomicscopedvaluerollback.h
index 41e919a3c6..8f653acba5 100644
--- a/src/corelib/tools/qatomicscopedvaluerollback.h
+++ b/src/corelib/tools/qatomicscopedvaluerollback.h
@@ -104,15 +104,12 @@ public:
std::memory_order mo = std::memory_order_seq_cst)
: QAtomicScopedValueRollback(var._q_value, value, mo) {}
-#if __cpp_constexpr >= 201907L
- constexpr
-#endif
~QAtomicScopedValueRollback()
{
m_atomic.store(m_value, store_part(m_mo));
}
- constexpr void commit()
+ void commit()
{
m_value = m_atomic.load(load_part(m_mo));
}
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index e311fee51f..e4276d383d 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -23,6 +23,8 @@ QT_BEGIN_NAMESPACE
\ingroup shared
\reentrant
+ \compares equality
+
A QBitArray is an array that gives access to individual bits and
provides operators (\l{operator&()}{AND}, \l{operator|()}{OR},
\l{operator^()}{XOR}, and \l{operator~()}{NOT}) that work on
@@ -499,17 +501,17 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
fast and never fails.
*/
-/*! \fn bool QBitArray::operator==(const QBitArray &other) const
+/*! \fn bool QBitArray::operator==(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is equal to this bit array; otherwise
+ Returns \c true if \a lhs is equal to \a rhs bit array; otherwise
returns \c false.
\sa operator!=()
*/
-/*! \fn bool QBitArray::operator!=(const QBitArray &other) const
+/*! \fn bool QBitArray::operator!=(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is not equal to this bit array;
+ Returns \c true if \a lhs is not equal to \a rhs bit array;
otherwise returns \c false.
\sa operator==()
diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h
index 4f99e693eb..b9c36b5320 100644
--- a/src/corelib/tools/qbitarray.h
+++ b/src/corelib/tools/qbitarray.h
@@ -116,8 +116,10 @@ public:
QBitArray operator~() const;
#endif
- inline bool operator==(const QBitArray &other) const { return d == other.d; }
- inline bool operator!=(const QBitArray &other) const { return d != other.d; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QBitArray &other) const { return comparesEqual(d, other.d); }
+ inline bool operator!=(const QBitArray &other) const { return !operator==(other); }
+#endif
bool fill(bool aval, qsizetype asize = -1)
{ *this = QBitArray((asize < 0 ? this->size() : asize), aval); return true; }
@@ -134,6 +136,13 @@ public:
typedef QByteArray::DataPointer DataPtr;
inline DataPtr &data_ptr() { return d.data_ptr(); }
inline const DataPtr &data_ptr() const { return d.data_ptr(); }
+
+private:
+ friend bool comparesEqual(const QBitArray &lhs, const QBitArray &rhs) noexcept
+ {
+ return lhs.d == rhs.d;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QBitArray)
};
class QT6_ONLY(Q_CORE_EXPORT) QBitRef
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index d8b3367de3..52602a0256 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -1153,32 +1153,37 @@ QEasingCurve::~QEasingCurve()
*/
/*!
- Compare this easing curve with \a other and returns \c true if they are
- equal. It will also compare the properties of a curve.
+ \fn bool QEasingCurve::operator==(const QEasingCurve &lhs, const QEasingCurve &rhs)
+
+ Compares easing curve \a lhs with \a rhs and returns \c true if they are
+ equal; otherwise returns \c false.
+ It will also compare the properties of the curves.
*/
-bool QEasingCurve::operator==(const QEasingCurve &other) const
+bool comparesEqual(const QEasingCurve &lhs, const QEasingCurve &rhs) noexcept
{
- bool res = d_ptr->func == other.d_ptr->func
- && d_ptr->type == other.d_ptr->type;
+ bool res = lhs.d_ptr->func == rhs.d_ptr->func
+ && lhs.d_ptr->type == rhs.d_ptr->type;
if (res) {
- if (d_ptr->config && other.d_ptr->config) {
+ if (lhs.d_ptr->config && rhs.d_ptr->config) {
// catch the config content
- res = d_ptr->config->operator==(*(other.d_ptr->config));
+ res = lhs.d_ptr->config->operator==(*(rhs.d_ptr->config));
- } else if (d_ptr->config || other.d_ptr->config) {
+ } else if (lhs.d_ptr->config || rhs.d_ptr->config) {
// one one has a config object, which could contain default values
- res = qFuzzyCompare(amplitude(), other.amplitude())
- && qFuzzyCompare(period(), other.period())
- && qFuzzyCompare(overshoot(), other.overshoot());
+ res = qFuzzyCompare(lhs.amplitude(), rhs.amplitude())
+ && qFuzzyCompare(lhs.period(), rhs.period())
+ && qFuzzyCompare(lhs.overshoot(), rhs.overshoot());
}
}
return res;
}
/*!
- \fn bool QEasingCurve::operator!=(const QEasingCurve &other) const
- Compare this easing curve with \a other and returns \c true if they are not equal.
- It will also compare the properties of a curve.
+ \fn bool QEasingCurve::operator!=(const QEasingCurve &lhs, const QEasingCurve &rhs)
+
+ Compares easing curve \a lhs with \a rhs and returns \c true if they are
+ not equal; otherwise returns \c false.
+ It will also compare the properties of the curves.
\sa operator==()
*/
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index 5b112d7d7d..61e9aa247d 100644
--- a/src/corelib/tools/qeasingcurve.h
+++ b/src/corelib/tools/qeasingcurve.h
@@ -8,6 +8,7 @@
QT_REQUIRE_CONFIG(easingcurve);
+#include <QtCore/qcompare.h>
#include <QtCore/qlist.h>
#include <QtCore/qobjectdefs.h>
@@ -47,9 +48,11 @@ public:
void swap(QEasingCurve &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QEasingCurve &other) const;
inline bool operator!=(const QEasingCurve &other) const
{ return !(this->operator==(other)); }
+#endif
qreal amplitude() const;
void setAmplitude(qreal amplitude);
@@ -81,6 +84,11 @@ private:
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QEasingCurve &);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QEasingCurve &);
#endif
+ friend Q_CORE_EXPORT bool
+ comparesEqual(const QEasingCurve &lhs, const QEasingCurve &rhs) noexcept;
+#if !QT_CORE_REMOVED_SINCE(6, 8)
+ Q_DECLARE_EQUALITY_COMPARABLE(QEasingCurve)
+#endif
};
Q_DECLARE_SHARED(QEasingCurve)
diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp
index 9216b8875b..e313b06aa9 100644
--- a/src/corelib/tools/qline.cpp
+++ b/src/corelib/tools/qline.cpp
@@ -14,6 +14,9 @@ QT_BEGIN_NAMESPACE
\class QLine
\inmodule QtCore
\ingroup painting
+ \compares equality
+ \compareswith equality QLineF
+ \endcompareswith
\brief The QLine class provides a two-dimensional vector using
integer precision.
@@ -133,18 +136,18 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool QLine::operator!=(const QLine &line) const
+ \fn bool QLine::operator!=(const QLine &lhs, const QLine &rhs)
- Returns \c true if the given \a line is not the same as \e this line.
+ Returns \c true if the line \a lhs is not the same as line \a rhs.
A line is different from another line if any of their start or
end points differ, or the internal order of the points is different.
*/
/*!
- \fn bool QLine::operator==(const QLine &line) const
+ \fn bool QLine::operator==(const QLine &lhs, const QLine &rhs)
- Returns \c true if the given \a line is the same as \e this line.
+ Returns \c true if the line \a lhs is the same as line \a rhs.
A line is identical to another line if the start and end points
are identical, and the internal order of the points is the same.
@@ -288,6 +291,9 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
\class QLineF
\inmodule QtCore
\ingroup painting
+ \compares equality
+ \compareswith equality QLine
+ \endcompareswith
\brief The QLineF class provides a two-dimensional vector using
floating point precision.
@@ -508,18 +514,18 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
*/
/*!
- \fn bool QLineF::operator!=(const QLineF &line) const
+ \fn bool QLineF::operator!=(const QLineF &lhs, const QLineF &rhs)
- Returns \c true if the given \a line is not the same as \e this line.
+ Returns \c true if the line \a lhs is not the same as line \a rhs.
A line is different from another line if their start or end points
differ, or the internal order of the points is different.
*/
/*!
- \fn bool QLineF::operator==(const QLineF &line) const
+ \fn bool QLineF::operator==(const QLineF &lhs, const QLineF &rhs)
- Returns \c true if the given \a line is the same as this line.
+ Returns \c true if the line \a lhs is the same as line \a rhs.
A line is identical to another line if the start and end points
are identical, and the internal order of the points is the same.
@@ -781,6 +787,25 @@ qreal QLineF::angleTo(const QLineF &l) const
return delta_normalized;
}
+/*!
+ \fn bool QLineF::qFuzzyCompare(const QLineF &lhs, const QLineF &rhs)
+ \since 6.8
+
+ Returns \c true if line \a lhs is approximately equal to line \a rhs;
+ otherwise returns \c false.
+
+ The lines are considered approximately equal if their start and end
+ points are approximately equal.
+*/
+
+/*!
+ \fn bool QLineF::qFuzzyIsNull(const QLineF &line)
+ \since 6.8
+
+ Returns \c true if the start point of line \a line is approximately
+ equal to its end point; otherwise returns \c false.
+*/
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QLineF &p)
{
diff --git a/src/corelib/tools/qline.h b/src/corelib/tools/qline.h
index e23ffbe9d5..03dac30e16 100644
--- a/src/corelib/tools/qline.h
+++ b/src/corelib/tools/qline.h
@@ -48,12 +48,20 @@ public:
inline void setPoints(const QPoint &p1, const QPoint &p2);
inline void setLine(int x1, int y1, int x2, int y2);
+#if QT_CORE_REMOVED_SINCE(6, 8)
constexpr inline bool operator==(const QLine &d) const noexcept;
- constexpr inline bool operator!=(const QLine &d) const noexcept { return !(*this == d); }
+ constexpr inline bool operator!=(const QLine &d) const noexcept { return !operator==(d); }
+#endif
[[nodiscard]] constexpr inline QLineF toLineF() const noexcept;
private:
+ friend constexpr bool comparesEqual(const QLine &lhs, const QLine &rhs) noexcept
+ { return lhs.pt1 == rhs.pt1 && lhs.pt2 == rhs.pt2; }
+#if !QT_CORE_REMOVED_SINCE(6, 8)
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QLine)
+#endif
+
QPoint pt1, pt2;
};
Q_DECLARE_TYPEINFO(QLine, Q_PRIMITIVE_TYPE);
@@ -161,10 +169,12 @@ inline void QLine::setLine(int aX1, int aY1, int aX2, int aY2)
pt2 = QPoint(aX2, aY2);
}
+#if QT_CORE_REMOVED_SINCE(6, 8)
constexpr inline bool QLine::operator==(const QLine &d) const noexcept
{
- return pt1 == d.pt1 && pt2 == d.pt2;
+ return comparesEqual(*this, d);
}
+#endif
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug d, const QLine &p);
@@ -233,12 +243,30 @@ public:
inline void setPoints(const QPointF &p1, const QPointF &p2);
inline void setLine(qreal x1, qreal y1, qreal x2, qreal y2);
+#if QT_CORE_REMOVED_SINCE(6, 8)
constexpr inline bool operator==(const QLineF &d) const;
- constexpr inline bool operator!=(const QLineF &d) const { return !(*this == d); }
+ constexpr inline bool operator!=(const QLineF &d) const { return !operator==(d); }
+#endif
constexpr QLine toLine() const;
private:
+ friend constexpr bool comparesEqual(const QLineF &lhs, const QLineF &rhs) noexcept
+ { return lhs.pt1 == rhs.pt1 && lhs.pt2 == rhs.pt2; }
+#if !QT_CORE_REMOVED_SINCE(6, 8)
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QLineF)
+#endif
+
+ friend constexpr bool comparesEqual(const QLineF &lhs, const QLine &rhs) noexcept
+ { return comparesEqual(lhs, rhs.toLineF()); }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QLineF, QLine)
+
+ friend constexpr bool qFuzzyCompare(const QLineF &lhs, const QLineF &rhs) noexcept
+ { return qFuzzyCompare(lhs.pt1, rhs.pt1) && qFuzzyCompare(lhs.pt2, rhs.pt2); }
+
+ friend constexpr bool qFuzzyIsNull(const QLineF &line) noexcept
+ { return qFuzzyCompare(line.pt1, line.pt2); }
+
QPointF pt1, pt2;
};
Q_DECLARE_TYPEINFO(QLineF, Q_PRIMITIVE_TYPE);
@@ -283,7 +311,7 @@ constexpr inline qreal QLineF::y2() const
constexpr inline bool QLineF::isNull() const
{
- return qFuzzyCompare(pt1.x(), pt2.x()) && qFuzzyCompare(pt1.y(), pt2.y());
+ return qFuzzyCompare(pt1, pt2);
}
constexpr inline QPointF QLineF::p1() const
@@ -383,12 +411,12 @@ inline void QLineF::setLine(qreal aX1, qreal aY1, qreal aX2, qreal aY2)
pt2 = QPointF(aX2, aY2);
}
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
constexpr inline bool QLineF::operator==(const QLineF &d) const
{
- return pt1 == d.pt1 && pt2 == d.pt2;
+ return comparesEqual(*this, d);
}
-
+#endif
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/corelib/tools/qmargins.cpp b/src/corelib/tools/qmargins.cpp
index 1d2cb7d6e5..c4cd0da30d 100644
--- a/src/corelib/tools/qmargins.cpp
+++ b/src/corelib/tools/qmargins.cpp
@@ -14,6 +14,10 @@ QT_BEGIN_NAMESPACE
\ingroup painting
\since 4.6
+ \compares equality
+ \compareswith equality QMarginsF
+ \endcompareswith
+
\brief The QMargins class defines the four margins of a rectangle.
QMargin defines a set of four margins; left, top, right, and bottom,
@@ -107,15 +111,15 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool QMargins::operator==(const QMargins &m1, const QMargins &m2)
+ \fn bool QMargins::operator==(const QMargins &lhs, const QMargins &rhs)
- Returns \c true if \a m1 and \a m2 are equal; otherwise returns \c false.
+ Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false.
*/
/*!
- \fn bool QMargins::operator!=(const QMargins &m1, const QMargins &m2)
+ \fn bool QMargins::operator!=(const QMargins &lhs, const QMargins &rhs)
- Returns \c true if \a m1 and \a m2 are different; otherwise returns \c false.
+ Returns \c true if \a lhs and \a rhs are different; otherwise returns \c false.
*/
/*!
@@ -438,6 +442,10 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\ingroup painting
\since 5.3
+ \compares equality
+ \compareswith equality QMargins
+ \endcompareswith
+
\brief The QMarginsF class defines the four margins of a rectangle.
QMarginsF defines a set of four margins; left, top, right, and bottom,
@@ -746,6 +754,22 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\sa QMarginsF(), QMargins::toMarginsF()
*/
+/*!
+ \fn bool QMarginsF::qFuzzyCompare(const QMarginsF &lhs, const QMarginsF &rhs)
+ \since 6.8
+
+ Returns \c true if \a lhs is approximately equal to \a rhs;
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QMarginsF::qFuzzyIsNull(const QMarginsF &margins)
+ \since 6.8
+
+ Returns \c true if all components of margsins \a margins are
+ approximately equal to zero; otherwise returns \c false.
+*/
+
/*****************************************************************************
QMarginsF stream functions
*****************************************************************************/
diff --git a/src/corelib/tools/qmargins.h b/src/corelib/tools/qmargins.h
index f8d7150dfd..3b29860d66 100644
--- a/src/corelib/tools/qmargins.h
+++ b/src/corelib/tools/qmargins.h
@@ -4,6 +4,7 @@
#ifndef QMARGINS_H
#define QMARGINS_H
+#include <QtCore/qcompare.h>
#include <QtCore/qnamespace.h>
#include <QtCore/q20type_traits.h>
@@ -54,19 +55,14 @@ private:
int m_right;
int m_bottom;
- friend constexpr inline bool operator==(const QMargins &m1, const QMargins &m2) noexcept
+ friend constexpr bool comparesEqual(const QMargins &lhs, const QMargins &rhs) noexcept
{
- return
- m1.m_left == m2.m_left &&
- m1.m_top == m2.m_top &&
- m1.m_right == m2.m_right &&
- m1.m_bottom == m2.m_bottom;
- }
-
- friend constexpr inline bool operator!=(const QMargins &m1, const QMargins &m2) noexcept
- {
- return !(m1 == m2);
+ return lhs.m_left == rhs.m_left
+ && lhs.m_top == rhs.m_top
+ && lhs.m_right == rhs.m_right
+ && lhs.m_bottom == rhs.m_bottom;
}
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QMargins)
template <std::size_t I,
typename M,
@@ -304,18 +300,35 @@ private:
qreal m_right;
qreal m_bottom;
- friend constexpr inline bool operator==(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_FLOAT_COMPARE
+ friend constexpr bool qFuzzyCompare(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
- return qFuzzyCompare(lhs.left(), rhs.left())
- && qFuzzyCompare(lhs.top(), rhs.top())
- && qFuzzyCompare(lhs.right(), rhs.right())
- && qFuzzyCompare(lhs.bottom(), rhs.bottom());
+ return ((!lhs.m_left || !rhs.m_left) ? qFuzzyIsNull(lhs.m_left - rhs.m_left)
+ : qFuzzyCompare(lhs.m_left, rhs.m_left))
+ && ((!lhs.m_top || !rhs.m_top) ? qFuzzyIsNull(lhs.m_top - rhs.m_top)
+ : qFuzzyCompare(lhs.m_top, rhs.m_top))
+ && ((!lhs.m_right || !rhs.m_right) ? qFuzzyIsNull(lhs.m_right - rhs.m_right)
+ : qFuzzyCompare(lhs.m_right, rhs.m_right))
+ && ((!lhs.m_bottom || !rhs.m_bottom) ? qFuzzyIsNull(lhs.m_bottom - rhs.m_bottom)
+ : qFuzzyCompare(lhs.m_bottom, rhs.m_bottom));
+ }
+ QT_WARNING_POP
+ friend constexpr bool qFuzzyIsNull(const QMarginsF &m) noexcept
+ {
+ return qFuzzyIsNull(m.m_left) && qFuzzyIsNull(m.m_top)
+ && qFuzzyIsNull(m.m_right) && qFuzzyIsNull(m.m_bottom);
}
- friend constexpr inline bool operator!=(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
+ friend constexpr bool comparesEqual(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
- return !(lhs == rhs);
+ return qFuzzyCompare(lhs, rhs);
}
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QMarginsF)
+
+ friend constexpr bool comparesEqual(const QMarginsF &lhs, const QMargins &rhs) noexcept
+ { return comparesEqual(lhs, rhs.toMarginsF()); }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QMarginsF, QMargins)
template <std::size_t I,
typename M,
diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp
index d1f3b12a68..775a354469 100644
--- a/src/corelib/tools/qpoint.cpp
+++ b/src/corelib/tools/qpoint.cpp
@@ -15,6 +15,10 @@ QT_BEGIN_NAMESPACE
\ingroup painting
\reentrant
+ \compares equality
+ \compareswith equality QPointF
+ \endcompareswith
+
\brief The QPoint class defines a point in the plane using integer
precision.
@@ -208,16 +212,17 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool QPoint::operator==(const QPoint &p1, const QPoint &p2)
+ \fn bool QPoint::operator==(const QPoint &lhs, const QPoint &rhs)
- Returns \c true if \a p1 and \a p2 are equal; otherwise returns
- false.
+ Returns \c true if \a lhs and \a rhs are equal; otherwise returns
+ \c false.
*/
/*!
- \fn bool QPoint::operator!=(const QPoint &p1, const QPoint &p2)
+ \fn bool QPoint::operator!=(const QPoint &lhs, const QPoint &rhs)
- Returns \c true if \a p1 and \a p2 are not equal; otherwise returns \c false.
+ Returns \c true if \a lhs and \a rhs are not equal; otherwise returns
+ \c false.
*/
/*!
@@ -463,6 +468,10 @@ size_t qHash(QPoint key, size_t seed) noexcept
\ingroup painting
\reentrant
+ \compares equality
+ \compareswith equality QPoint
+ \endcompareswith
+
\brief The QPointF class defines a point in the plane using
floating point precision.
@@ -730,9 +739,9 @@ size_t qHash(QPoint key, size_t seed) noexcept
*/
/*!
- \fn bool QPointF::operator==(const QPointF &p1, const QPointF &p2)
+ \fn bool QPointF::operator==(const QPointF &lhs, const QPointF &rhs)
- Returns \c true if \a p1 is approximately equal to \a p2; otherwise
+ Returns \c true if \a lhs is approximately equal to \a rhs; otherwise
returns \c false.
\warning This function does not check for strict equality; instead,
@@ -742,9 +751,9 @@ size_t qHash(QPoint key, size_t seed) noexcept
*/
/*!
- \fn bool QPointF::operator!=(const QPointF &p1, const QPointF &p2);
+ \fn bool QPointF::operator!=(const QPointF &lhs, const QPointF &rhs)
- Returns \c true if \a p1 is sufficiently different from \a p2;
+ Returns \c true if \a lhs is sufficiently different from \a rhs;
otherwise returns \c false.
\warning This function does not check for strict inequality; instead,
@@ -753,6 +762,26 @@ size_t qHash(QPoint key, size_t seed) noexcept
\sa qFuzzyCompare
*/
+/*!
+ \fn bool QPointF::qFuzzyCompare(const QPointF &p1, const QPointF &p2)
+ \since 6.8
+
+ Returns \c true if \a p1 is approximately equal to \a p2; otherwise
+ returns \c false.
+
+ \sa qFuzzyIsNull
+*/
+
+/*!
+ \fn bool QPointF::qFuzzyIsNull(const QPointF &point)
+ \since 6.8
+
+ Returns \c true if \a point is approximately equal to a point
+ \c {(0.0, 0.0)}.
+
+ \sa qFuzzyCompare
+*/
+
#ifndef QT_NO_DATASTREAM
/*!
\fn QDataStream &operator<<(QDataStream &stream, const QPointF &point)
diff --git a/src/corelib/tools/qpoint.h b/src/corelib/tools/qpoint.h
index 7df4d49005..50b4c864be 100644
--- a/src/corelib/tools/qpoint.h
+++ b/src/corelib/tools/qpoint.h
@@ -4,7 +4,9 @@
#ifndef QPOINT_H
#define QPOINT_H
+#include <QtCore/qcompare.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qnumeric.h>
#include <QtCore/q20type_traits.h>
#include <QtCore/q23utility.h>
@@ -51,10 +53,10 @@ public:
constexpr static inline int dotProduct(const QPoint &p1, const QPoint &p2)
{ return p1.xp * p2.xp + p1.yp * p2.yp; }
- friend constexpr inline bool operator==(const QPoint &p1, const QPoint &p2) noexcept
+private:
+ friend constexpr bool comparesEqual(const QPoint &p1, const QPoint &p2) noexcept
{ return p1.xp == p2.xp && p1.yp == p2.yp; }
- friend constexpr inline bool operator!=(const QPoint &p1, const QPoint &p2) noexcept
- { return p1.xp != p2.xp || p1.yp != p2.yp; }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QPoint)
friend constexpr inline QPoint operator+(const QPoint &p1, const QPoint &p2) noexcept
{ return QPoint(p1.xp + p2.xp, p1.yp + p2.yp); }
friend constexpr inline QPoint operator-(const QPoint &p1, const QPoint &p2) noexcept
@@ -78,6 +80,7 @@ public:
friend constexpr inline QPoint operator/(const QPoint &p, qreal c)
{ return QPoint(qRound(p.xp / c), qRound(p.yp / c)); }
+public:
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
[[nodiscard]] Q_CORE_EXPORT CGPoint toCGPoint() const noexcept;
#endif
@@ -241,19 +244,25 @@ public:
return p1.xp * p2.xp + p1.yp * p2.yp;
}
+private:
QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
- friend constexpr inline bool operator==(const QPointF &p1, const QPointF &p2)
+ friend constexpr bool qFuzzyCompare(const QPointF &p1, const QPointF &p2) noexcept
{
return ((!p1.xp || !p2.xp) ? qFuzzyIsNull(p1.xp - p2.xp) : qFuzzyCompare(p1.xp, p2.xp))
&& ((!p1.yp || !p2.yp) ? qFuzzyIsNull(p1.yp - p2.yp) : qFuzzyCompare(p1.yp, p2.yp));
}
- friend constexpr inline bool operator!=(const QPointF &p1, const QPointF &p2)
+ QT_WARNING_POP
+ friend constexpr bool qFuzzyIsNull(const QPointF &point) noexcept
{
- return !(p1 == p2);
+ return qFuzzyIsNull(point.xp) && qFuzzyIsNull(point.yp);
}
- QT_WARNING_POP
-
+ friend constexpr bool comparesEqual(const QPointF &p1, const QPointF &p2) noexcept
+ { return qFuzzyCompare(p1, p2); }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QPointF)
+ friend constexpr bool comparesEqual(const QPointF &p1, const QPoint &p2) noexcept
+ { return comparesEqual(p1, p2.toPointF()); }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QPointF, QPoint)
friend constexpr inline QPointF operator+(const QPointF &p1, const QPointF &p2)
{ return QPointF(p1.xp + p2.xp, p1.yp + p2.yp); }
friend constexpr inline QPointF operator-(const QPointF &p1, const QPointF &p2)
@@ -272,6 +281,7 @@ public:
return QPointF(p.xp / divisor, p.yp / divisor);
}
+public:
constexpr QPoint toPoint() const;
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp
index 6d345ce543..ce28a6d887 100644
--- a/src/corelib/tools/qrect.cpp
+++ b/src/corelib/tools/qrect.cpp
@@ -15,6 +15,10 @@ QT_BEGIN_NAMESPACE
\ingroup painting
\reentrant
+ \compares equality
+ \compareswith equality QRectF
+ \endcompareswith
+
\brief The QRect class defines a rectangle in the plane using
integer precision.
@@ -1105,18 +1109,18 @@ bool QRect::intersects(const QRect &r) const noexcept
}
/*!
- \fn bool QRect::operator==(const QRect &r1, const QRect &r2)
+ \fn bool QRect::operator==(const QRect &lhs, const QRect &rhs)
- Returns \c true if the rectangles \a r1 and \a r2 are equal,
+ Returns \c true if the rectangles \a lhs and \a rhs are equal,
otherwise returns \c false.
*/
/*!
- \fn bool QRect::operator!=(const QRect &r1, const QRect &r2)
+ \fn bool QRect::operator!=(const QRect &lhs, const QRect &rhs)
- Returns \c true if the rectangles \a r1 and \a r2 are different, otherwise
- returns \c false.
+ Returns \c true if the rectangles \a lhs and \a rhs are different,
+ otherwise returns \c false.
*/
/*!
@@ -1279,6 +1283,10 @@ QDebug operator<<(QDebug dbg, const QRect &r)
\ingroup painting
\reentrant
+ \compares equality
+ \compareswith equality QRect
+ \endcompareswith
+
\brief The QRectF class defines a finite rectangle in the plane using
floating point precision.
@@ -2346,10 +2354,10 @@ QRect QRectF::toAlignedRect() const noexcept
*/
/*!
- \fn bool QRectF::operator==(const QRectF &r1, const QRectF &r2)
+ \fn bool QRectF::operator==(const QRectF &lhs, const QRectF &rhs)
- Returns \c true if the rectangles \a r1 and \a r2 are \b approximately equal,
- otherwise returns \c false.
+ Returns \c true if the rectangles \a lhs and \a rhs are \b approximately
+ equal, otherwise returns \c false.
\warning This function does not check for strict equality; instead,
it uses a fuzzy comparison to compare the rectangles' coordinates.
@@ -2359,9 +2367,9 @@ QRect QRectF::toAlignedRect() const noexcept
/*!
- \fn bool QRectF::operator!=(const QRectF &r1, const QRectF &r2)
+ \fn bool QRectF::operator!=(const QRectF &lhs, const QRectF &rhs)
- Returns \c true if the rectangles \a r1 and \a r2 are sufficiently
+ Returns \c true if the rectangles \a lhs and \a rhs are sufficiently
different, otherwise returns \c false.
\warning This function does not check for strict inequality; instead,
@@ -2429,6 +2437,22 @@ QRect QRectF::toAlignedRect() const noexcept
\sa marginsRemoved(), operator+=(), marginsAdded()
*/
+/*!
+ \fn bool QRectF::qFuzzyCompare(const QRectF &lhs, const QRectF &rhs)
+ \since 6.8
+
+ Returns \c true if the rectangle \a lhs is approximately equal to the
+ rectangle \a rhs; otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QRectF::qFuzzyIsNull(const QRectF &rect)
+ \since 6.8
+
+ Returns \c true if both width and height of the rectangle \a rect are
+ approximately equal to zero; otherwise returns \c false.
+*/
+
/*****************************************************************************
QRectF stream functions
*****************************************************************************/
diff --git a/src/corelib/tools/qrect.h b/src/corelib/tools/qrect.h
index e69a217f48..fb938b0056 100644
--- a/src/corelib/tools/qrect.h
+++ b/src/corelib/tools/qrect.h
@@ -119,12 +119,13 @@ public:
[[nodiscard]] static constexpr inline QRect span(const QPoint &p1, const QPoint &p2) noexcept;
- friend constexpr inline bool operator==(const QRect &r1, const QRect &r2) noexcept
+private:
+ friend constexpr bool comparesEqual(const QRect &r1, const QRect &r2) noexcept
{ return r1.x1==r2.x1 && r1.x2==r2.x2 && r1.y1==r2.y1 && r1.y2==r2.y2; }
- friend constexpr inline bool operator!=(const QRect &r1, const QRect &r2) noexcept
- { return r1.x1!=r2.x1 || r1.x2!=r2.x2 || r1.y1!=r2.y1 || r1.y2!=r2.y2; }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QRect)
friend constexpr inline size_t qHash(const QRect &, size_t) noexcept;
+public:
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
[[nodiscard]] CGRect toCGRect() const noexcept;
#endif
@@ -572,17 +573,30 @@ public:
constexpr inline QRectF &operator+=(const QMarginsF &margins) noexcept;
constexpr inline QRectF &operator-=(const QMarginsF &margins) noexcept;
- friend constexpr inline bool operator==(const QRectF &r1, const QRectF &r2) noexcept
+private:
+ friend constexpr bool comparesEqual(const QRectF &r1, const QRectF &r2) noexcept
{
return r1.topLeft() == r2.topLeft()
&& r1.size() == r2.size();
}
- friend constexpr inline bool operator!=(const QRectF &r1, const QRectF &r2) noexcept
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QRectF)
+
+ friend constexpr bool comparesEqual(const QRectF &r1, const QRect &r2) noexcept
+ { return r1.topLeft() == r2.topLeft() && r1.size() == r2.size(); }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QRectF, QRect)
+
+ friend constexpr bool qFuzzyCompare(const QRectF &lhs, const QRectF &rhs) noexcept
{
- return r1.topLeft() != r2.topLeft()
- || r1.size() != r2.size();
+ return qFuzzyCompare(lhs.topLeft(), rhs.topLeft())
+ && qFuzzyCompare(lhs.bottomRight(), rhs.bottomRight());
}
+ friend constexpr bool qFuzzyIsNull(const QRectF &rect) noexcept
+ {
+ return qFuzzyIsNull(rect.w) && qFuzzyIsNull(rect.h);
+ }
+
+public:
[[nodiscard]] constexpr inline QRect toRect() const noexcept;
[[nodiscard]] QRect toAlignedRect() const noexcept;
diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp
index d5e8e4c71b..27ff1d164d 100644
--- a/src/corelib/tools/qsize.cpp
+++ b/src/corelib/tools/qsize.cpp
@@ -266,15 +266,15 @@ QSize QSize::scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept
*/
/*!
- \fn bool QSize::operator==(const QSize &s1, const QSize &s2)
+ \fn bool QSize::operator==(const QSize &lhs, const QSize &rhs)
- Returns \c true if \a s1 and \a s2 are equal; otherwise returns \c false.
+ Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false.
*/
/*!
- \fn bool QSize::operator!=(const QSize &s1, const QSize &s2)
+ \fn bool QSize::operator!=(const QSize &lhs, const QSize &rhs)
- Returns \c true if \a s1 and \a s2 are different; otherwise returns \c false.
+ Returns \c true if \a lhs and \a rhs are different; otherwise returns \c false.
*/
/*!
@@ -714,9 +714,9 @@ QSizeF QSizeF::scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept
*/
/*!
- \fn bool QSizeF::operator==(const QSizeF &s1, const QSizeF &s2)
+ \fn bool QSizeF::operator==(const QSizeF &lhs, const QSizeF &rhs)
- Returns \c true if \a s1 and \a s2 are approximately equal; otherwise
+ Returns \c true if \a lhs and \a rhs are approximately equal; otherwise
returns false.
\warning This function does not check for strict equality; instead,
@@ -726,9 +726,9 @@ QSizeF QSizeF::scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept
*/
/*!
- \fn bool QSizeF::operator!=(const QSizeF &s1, const QSizeF &s2)
+ \fn bool QSizeF::operator!=(const QSizeF &lhs, const QSizeF &rhs)
- Returns \c true if \a s1 and \a s2 are sufficiently different; otherwise
+ Returns \c true if \a lhs and \a rhs are sufficiently different; otherwise
returns \c false.
\warning This function does not check for strict inequality; instead,
@@ -808,7 +808,24 @@ QSizeF QSizeF::scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept
\sa expandedTo(), scale()
*/
+/*!
+ \fn bool QSizeF::qFuzzyCompare(const QSizeF &lhs, const QSizeF &rhs)
+ \since 6.8
+
+ Returns \c true if the size \a lhs is approximately equal to the
+ size \a rhs; otherwise returns \c false.
+
+ The sizes are considered approximately equal if their width and
+ height are approximately equal.
+*/
+/*!
+ \fn bool QSizeF::qFuzzyIsNull(const QSizeF &size)
+ \since 6.8
+
+ Returns \c true if both width and height of the size \a size
+ are approximately equal to zero.
+*/
/*****************************************************************************
QSizeF stream functions
diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h
index a5eaf34afe..67f7146201 100644
--- a/src/corelib/tools/qsize.h
+++ b/src/corelib/tools/qsize.h
@@ -59,10 +59,10 @@ public:
constexpr inline QSize &operator*=(qreal c) noexcept;
inline QSize &operator/=(qreal c);
- friend inline constexpr bool operator==(const QSize &s1, const QSize &s2) noexcept
+private:
+ friend constexpr bool comparesEqual(const QSize &s1, const QSize &s2) noexcept
{ return s1.wd == s2.wd && s1.ht == s2.ht; }
- friend inline constexpr bool operator!=(const QSize &s1, const QSize &s2) noexcept
- { return s1.wd != s2.wd || s1.ht != s2.ht; }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QSize)
friend inline constexpr QSize operator+(const QSize &s1, const QSize &s2) noexcept
{ return QSize(s1.wd + s2.wd, s1.ht + s2.ht); }
friend inline constexpr QSize operator-(const QSize &s1, const QSize &s2) noexcept
@@ -75,6 +75,7 @@ public:
{ Q_ASSERT(!qFuzzyIsNull(c)); return QSize(qRound(s.wd / c), qRound(s.ht / c)); }
friend inline constexpr size_t qHash(const QSize &, size_t) noexcept;
+public:
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
[[nodiscard]] CGSize toCGSize() const noexcept;
#endif
@@ -242,16 +243,25 @@ public:
constexpr inline QSizeF &operator*=(qreal c) noexcept;
inline QSizeF &operator/=(qreal c);
+private:
QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
- friend constexpr inline bool operator==(const QSizeF &s1, const QSizeF &s2)
+ friend constexpr bool qFuzzyCompare(const QSizeF &s1, const QSizeF &s2) noexcept
{
+ // Cannot use qFuzzyCompare(), because it will give incorrect results
+ // if one of the arguments is 0.0.
return ((!s1.wd || !s2.wd) ? qFuzzyIsNull(s1.wd - s2.wd) : qFuzzyCompare(s1.wd, s2.wd))
&& ((!s1.ht || !s2.ht) ? qFuzzyIsNull(s1.ht - s2.ht) : qFuzzyCompare(s1.ht, s2.ht));
}
QT_WARNING_POP
- friend constexpr inline bool operator!=(const QSizeF &s1, const QSizeF &s2)
- { return !(s1 == s2); }
+ friend constexpr bool qFuzzyIsNull(const QSizeF &size) noexcept
+ { return qFuzzyIsNull(size.wd) && qFuzzyIsNull(size.ht); }
+ friend constexpr bool comparesEqual(const QSizeF &lhs, const QSizeF &rhs) noexcept
+ { return qFuzzyCompare(lhs, rhs); }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QSizeF)
+ friend constexpr bool comparesEqual(const QSizeF &lhs, const QSize &rhs) noexcept
+ { return comparesEqual(lhs, rhs.toSizeF()); }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QSizeF, QSize)
friend constexpr inline QSizeF operator+(const QSizeF &s1, const QSizeF &s2) noexcept
{ return QSizeF(s1.wd + s2.wd, s1.ht + s2.ht); }
friend constexpr inline QSizeF operator-(const QSizeF &s1, const QSizeF &s2) noexcept
@@ -263,6 +273,7 @@ public:
friend inline QSizeF operator/(const QSizeF &s, qreal c)
{ Q_ASSERT(!qFuzzyIsNull(c)); return QSizeF(s.wd / c, s.ht / c); }
+public:
constexpr inline QSize toSize() const noexcept;
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index afc345d3be..0a579bf487 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -956,8 +956,8 @@ Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::insert_impl(qsizetype prealloc, void *arr
template <class T>
Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::erase(const_iterator abegin, const_iterator aend) -> iterator
{
- Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::insert", "The specified const_iterator argument 'abegin' is invalid");
- Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::insert", "The specified const_iterator argument 'aend' is invalid");
+ Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::erase", "The specified const_iterator argument 'abegin' is invalid");
+ Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::erase", "The specified const_iterator argument 'aend' is invalid");
qsizetype f = qsizetype(abegin - cbegin());
qsizetype l = qsizetype(aend - cbegin());
@@ -968,10 +968,11 @@ Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::erase(const_iterator abegin, const_iterat
Q_ASSERT(n > 0); // aend must be reachable from abegin
- if constexpr (QTypeInfo<T>::isComplex) {
+ if constexpr (!QTypeInfo<T>::isRelocatable) {
std::move(begin() + l, end(), QT_MAKE_CHECKED_ARRAY_ITERATOR(begin() + f, size() - f));
std::destroy(end() - n, end());
} else {
+ std::destroy(abegin, aend);
memmove(static_cast<void *>(data() + f), static_cast<const void *>(data() + l), (size() - l) * sizeof(T));
}
this->s -= n;
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 4b8ace71cc..af95875b44 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -30,6 +30,7 @@ QT_IMPL_METATYPE_EXTERN(QVersionNumber)
\brief The QVersionNumber class contains a version number with an arbitrary
number of segments.
+ \compares strong
\snippet qversionnumber/main.cpp 0
*/
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index 95217a6eff..e7ae107226 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -6,6 +6,7 @@
#ifndef QVERSIONNUMBER_H
#define QVERSIONNUMBER_H
+#include <QtCore/qcompare.h>
#include <QtCore/qcontainertools_impl.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetatype.h>
@@ -355,25 +356,20 @@ public:
[[nodiscard]] Q_CORE_EXPORT static QVersionNumber fromString(QStringView string, int *suffixIndex);
#endif
- [[nodiscard]] friend bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
- { return compare(lhs, rhs) > 0; }
-
- [[nodiscard]] friend bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
- { return compare(lhs, rhs) >= 0; }
-
- [[nodiscard]] friend bool operator< (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
- { return compare(lhs, rhs) < 0; }
-
- [[nodiscard]] friend bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
- { return compare(lhs, rhs) <= 0; }
-
- [[nodiscard]] friend bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
- { return compare(lhs, rhs) == 0; }
-
- [[nodiscard]] friend bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
- { return compare(lhs, rhs) != 0; }
-
private:
+ [[nodiscard]] friend bool comparesEqual(const QVersionNumber &lhs,
+ const QVersionNumber &rhs) noexcept
+ {
+ return compare(lhs, rhs) == 0;
+ }
+ [[nodiscard]] friend Qt::strong_ordering compareThreeWay(const QVersionNumber &lhs,
+ const QVersionNumber &rhs) noexcept
+ {
+ int c = compare(lhs, rhs);
+ return Qt::compareThreeWay(c, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QVersionNumber)
+
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
#endif
diff --git a/src/dbus/qdbusextratypes.cpp b/src/dbus/qdbusextratypes.cpp
index 61f2075443..3354e76577 100644
--- a/src/dbus/qdbusextratypes.cpp
+++ b/src/dbus/qdbusextratypes.cpp
@@ -34,6 +34,8 @@ void QDBusSignature::doCheck()
if (!QDBusUtil::isValidSignature(m_signature)) {
qWarning("QDBusSignature: invalid signature \"%s\"", qPrintable(m_signature));
m_signature.clear();
+ } else if (m_signature.isEmpty()) {
+ m_signature.detach(); // we need it to not be null
}
}
diff --git a/src/dbus/qdbusextratypes.h b/src/dbus/qdbusextratypes.h
index 1bc0f3086d..1c0826b992 100644
--- a/src/dbus/qdbusextratypes.h
+++ b/src/dbus/qdbusextratypes.h
@@ -77,7 +77,10 @@ class Q_DBUS_EXPORT QDBusSignature
{
QString m_signature;
public:
- QDBusSignature() noexcept : m_signature() {}
+ QDBusSignature() noexcept
+ {
+ m_signature.detach(); // mark non-null (empty signatures are valid)
+ }
// compiler-generated copy/move constructor/assignment operators are ok!
// compiler-generated destructor is ok!
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 89b9b2d17e..836562f496 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -151,7 +151,8 @@ static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
Q_ASSERT(d->timeouts.key(timeout, 0) == 0);
- int timerId = d->startTimer(std::chrono::milliseconds{q_dbus_timeout_get_interval(timeout)});
+ using namespace std::chrono_literals;
+ int timerId = d->startTimer(q_dbus_timeout_get_interval(timeout) * 1ms); // no overflow possible
if (!timerId)
return false;
diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp
index b2ed2586fb..d1f1a41ab0 100644
--- a/src/dbus/qdbusmarshaller.cpp
+++ b/src/dbus/qdbusmarshaller.cpp
@@ -120,7 +120,7 @@ inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
inline void QDBusMarshaller::append(const QDBusSignature &arg)
{
QByteArray data = arg.signature().toUtf8();
- if (!ba && data.isEmpty()) {
+ if (!ba && data.isNull()) {
error("Invalid signature passed in arguments"_L1);
} else {
const char *cdata = data.constData();
diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp
index 827418c487..78338aa054 100644
--- a/src/dbus/qdbusutil.cpp
+++ b/src/dbus/qdbusutil.cpp
@@ -512,14 +512,14 @@ namespace QDBusUtil
bool isValidSignature(const QString &signature)
{
QByteArray ba = signature.toLatin1();
- const char *data = ba.constData();
- while (true) {
+ const char *data = ba.constBegin();
+ const char *end = ba.constEnd();
+ while (data != end) {
data = validateSingleType(data);
if (!data)
return false;
- if (*data == '\0')
- return true;
}
+ return true;
}
/*!
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index cef71318d8..aed66563a7 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -7,7 +7,9 @@ qt_find_package(WrapPNG PROVIDED_TARGETS WrapPNG::WrapPNG)
qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
if (QT_FEATURE_gui)
- if(WIN32)
+ if(QT_QPA_PLATFORMS)
+ list(GET QT_QPA_PLATFORMS 0 _default_platform)
+ elseif(WIN32)
set(_default_platform "windows")
elseif(ANDROID)
set(_default_platform "android")
@@ -30,6 +32,11 @@ if (QT_FEATURE_gui)
endif()
set(QT_QPA_DEFAULT_PLATFORM "${_default_platform}" CACHE STRING "QPA default platform")
+ if(NOT "${QT_QPA_DEFAULT_PLATFORM}" IN_LIST QT_QPA_PLATFORMS)
+ list(APPEND QT_QPA_PLATFORMS "${QT_QPA_DEFAULT_PLATFORM}")
+ set(QT_QPA_PLATFORMS "${QT_QPA_PLATFORMS}" CACHE STRING
+ "QPA platforms deployed by default" FORCE)
+ endif()
endif()
# Silence warnings in 3rdparty code
@@ -376,6 +383,11 @@ qt_internal_extend_target(Gui CONDITION MACOS
${FWAppKit}
)
+qt_internal_extend_target(Gui CONDITION UIKIT
+ SOURCES
+ platform/ios/qiosnativeinterface.cpp
+)
+
qt_internal_extend_target(Gui CONDITION WASM
SOURCES
platform/wasm/qwasmnativeinterface.cpp
@@ -402,6 +414,12 @@ qt_internal_extend_target(Gui CONDITION APPLE
${FWImageIO}
)
+qt_internal_extend_target(Gui CONDITION QNX
+ SOURCES
+ painting/qrasterbackingstore.cpp painting/qrasterbackingstore_p.h
+ painting/qrhibackingstore.cpp painting/qrhibackingstore_p.h
+)
+
qt_internal_extend_target(Gui CONDITION QT_FEATURE_animation
SOURCES
animation/qguivariantanimation.cpp
diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp
index b3269a2a95..2cebad1453 100644
--- a/src/gui/accessible/linux/atspiadaptor.cpp
+++ b/src/gui/accessible/linux/atspiadaptor.cpp
@@ -35,6 +35,13 @@
#define ATSPI_COORD_TYPE_PARENT 2
#endif
+// ATSPI_*_VERSION defines were added in libatspi 2.50,
+// as was the AtspiLive enum; define values here for older versions
+#if !defined(ATSPI_MAJOR_VERSION) || !defined(ATSPI_MINOR_VERSION) || ATSPI_MAJOR_VERSION < 2 || ATSPI_MINOR_VERSION < 50
+#define ATSPI_LIVE_POLITE 1
+#define ATSPI_LIVE_ASSERTIVE 2
+#endif
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -47,6 +54,7 @@ AtSpiAdaptor::AtSpiAdaptor(DBusConnection *connection, QObject *parent)
, sendFocus(0)
, sendObject(0)
, sendObject_active_descendant_changed(0)
+ , sendObject_announcement(0)
, sendObject_attributes_changed(0)
, sendObject_bounds_changed(0)
, sendObject_children_changed(0)
@@ -678,6 +686,8 @@ void AtSpiAdaptor::setBitFlag(const QString &flag)
if (false) {
} else if (right.startsWith("ActiveDescendantChanged"_L1)) {
sendObject_active_descendant_changed = 1;
+ } else if (right.startsWith("Announcement"_L1)) {
+ sendObject_announcement = 1;
} else if (right.startsWith("AttributesChanged"_L1)) {
sendObject_attributes_changed = 1;
} else if (right.startsWith("BoundsChanged"_L1)) {
@@ -929,6 +939,26 @@ void AtSpiAdaptor::notifyStateChange(QAccessibleInterface *interface, const QStr
sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "StateChanged"_L1, stateArgs);
}
+void AtSpiAdaptor::sendAnnouncement(QAccessibleAnnouncementEvent *event)
+{
+ QAccessibleInterface *iface = event->accessibleInterface();
+ if (!iface) {
+ qCWarning(lcAccessibilityAtspi, "Announcement event has no accessible set.");
+ return;
+ }
+ if (!iface->isValid()) {
+ qCWarning(lcAccessibilityAtspi) << "Announcement event with invalid accessible: " << iface;
+ return;
+ }
+
+ const QString path = pathForInterface(iface);
+ const QString message = event->message();
+ const QAccessible::AnnouncementPriority prio = event->priority();
+ const int politeness = (prio == QAccessible::AnnouncementPriority::Assertive) ? ATSPI_LIVE_ASSERTIVE : ATSPI_LIVE_POLITE;
+
+ const QVariantList args = packDBusSignalArguments(QString(), politeness, 0, QVariant::fromValue(QDBusVariant(message)));
+ sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "Announcement"_L1, args);
+}
/*!
This function gets called when Qt notifies about accessibility updates.
@@ -1003,6 +1033,14 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event)
sendFocusChanged(event->accessibleInterface());
break;
}
+
+ case QAccessible::Announcement: {
+ if (sendObject || sendObject_announcement) {
+ QAccessibleAnnouncementEvent *announcementEvent = static_cast<QAccessibleAnnouncementEvent*>(event);
+ sendAnnouncement(announcementEvent);
+ }
+ break;
+ }
case QAccessible::TextInserted:
case QAccessible::TextRemoved:
case QAccessible::TextUpdated: {
diff --git a/src/gui/accessible/linux/atspiadaptor_p.h b/src/gui/accessible/linux/atspiadaptor_p.h
index 3a890f3d7d..aab15d4501 100644
--- a/src/gui/accessible/linux/atspiadaptor_p.h
+++ b/src/gui/accessible/linux/atspiadaptor_p.h
@@ -16,7 +16,7 @@
// We mean it.
//
-#include <atspi/atspi-constants.h>
+#include <atspi/atspi.h>
#include <QtGui/private/qtguiglobal_p.h>
#include <QtDBus/qdbusvirtualobject.h>
@@ -85,6 +85,8 @@ private:
void notifyStateChange(QAccessibleInterface *interface, const QString& state, int value);
+ void sendAnnouncement(QAccessibleAnnouncementEvent *event);
+
// accessible helper functions
AtspiRole getRole(QAccessibleInterface *interface) const;
QSpiRelationArray relationSet(QAccessibleInterface *interface, const QDBusConnection &connection) const;
@@ -130,6 +132,7 @@ private:
// all of object
uint sendObject : 1;
uint sendObject_active_descendant_changed : 1;
+ uint sendObject_announcement : 1;
uint sendObject_attributes_changed : 1;
uint sendObject_bounds_changed : 1;
uint sendObject_children_changed : 1;
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp
index 46bca16dad..b037279e8b 100644
--- a/src/gui/accessible/qaccessible.cpp
+++ b/src/gui/accessible/qaccessible.cpp
@@ -173,6 +173,7 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\value ActionChanged An action has been changed.
\value ActiveDescendantChanged
\value Alert A system alert (e.g., a message from a QMessageBox)
+ \value [since 6.8] Announcement The announcement of a message is requested.
\value AttributeChanged
\value ContextHelpEnd Context help (QWhatsThis) for an object is finished.
\value ContextHelpStart Context help (QWhatsThis) for an object is initiated.
@@ -449,6 +450,30 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\sa QAccessibleAttributesInterface
*/
+/*! \enum QAccessible::AnnouncementPriority
+ This enum describes the priority for announcements used by the
+ \l QAccessibleAnnouncementEvent.
+ \since 6.8
+
+ With \a QAccessible::AnouncementPriority::Polite, assistive technologies
+ should announce the message at the next graceful opportunity such as at the
+ end of speaking the current sentence or when the user pauses typing.
+
+ When specifying \a QAccessible::AnouncementPriority::Assertive, assistive
+ technologies should notify the user immediately.
+
+ Because an interruption might disorient users or cause them to not complete
+ their current task, \a QAccessible::AnouncementPriority::Assertive should
+ not be used unless the interruption is imperative.
+
+ \value Polite The announcement has normal priority.
+ \value Assertive The announcement has high priority and should notify
+ the user immediately, even if that means interrupting the user's
+ current task.
+
+ \sa QAccessibleAnnouncementEvent
+*/
+
/*!
\enum QAccessible::InterfaceType
@@ -1778,7 +1803,56 @@ QAccessibleTextSelectionEvent::~QAccessibleTextSelectionEvent()
{
}
+/*!
+ \since 6.8
+ \class QAccessibleAnnouncementEvent
+ \ingroup accessibility
+ \inmodule QtGui
+
+ \brief The QAccessibleAnnouncementEvent is used to request the announcement
+ of a given message by assistive technologies.
+
+ This class is used with \l QAccessible::updateAccessibility().
+*/
+
+/*! \fn QAccessibleAnnouncementEvent::QAccessibleAnnouncementEvent(QObject *object, const QString &message)
+
+ Constructs a new QAccessibleAnnouncementEvent event for \a object
+ to request the announcement of \a message with priority \l QAccessible::AnnouncementPriority::Polite.
+
+ \l QAccessibleAnnouncementEvent::setPriority can be used to adjust the priority.
+*/
+/*! \fn QAccessibleAnnouncementEvent::QAccessibleAnnouncementEvent(QAccessibleInterface *iface, const QString &message)
+
+ Constructs a new QAccessibleAnnouncementEvent event for \a iface
+ to request the announcement of \a message with priority \l QAccessible::AnnouncementPriority::Polite.
+
+ \l QAccessibleAnnouncementEvent::setPriority can be used to adjust the priority.
+*/
+
+/*! \fn QString QAccessibleAnnouncementEvent::message() const
+
+ Returns the message.
+*/
+
+/*! \fn QAccessible::AnnouncementPriority QAccessibleAnnouncementEvent::priority() const
+
+ Returns the priority.
+*/
+
+/*! \fn void QAccessibleAnnouncementEvent::setPriority(QAccessible::AnnouncementPriority priority)
+
+ Sets the priority with which the announcement will be requested to \a priority.
+*/
+
+
+/*!
+ \internal
+*/
+QAccessibleAnnouncementEvent::~QAccessibleAnnouncementEvent()
+{
+}
/*!
Returns the QAccessibleInterface associated with the event.
diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h
index 0a92e76c73..3d8daa4b3c 100644
--- a/src/gui/accessible/qaccessible.h
+++ b/src/gui/accessible/qaccessible.h
@@ -316,6 +316,7 @@ public:
Q_ASSERT(m_type != QAccessible::TextRemoved);
Q_ASSERT(m_type != QAccessible::TextUpdated);
Q_ASSERT(m_type != QAccessible::TableModelChanged);
+ Q_ASSERT(m_type != QAccessible::Announcement);
}
inline QAccessibleEvent(QAccessibleInterface *iface, QAccessible::Event typ)
@@ -330,6 +331,7 @@ public:
Q_ASSERT(m_type != QAccessible::TextRemoved);
Q_ASSERT(m_type != QAccessible::TextUpdated);
Q_ASSERT(m_type != QAccessible::TableModelChanged);
+ Q_ASSERT(m_type != QAccessible::Announcement);
m_uniqueId = QAccessible::uniqueId(iface);
m_object = iface->object();
}
@@ -605,6 +607,36 @@ protected:
int m_lastColumn;
};
+class Q_GUI_EXPORT QAccessibleAnnouncementEvent : public QAccessibleEvent
+{
+public:
+ inline QAccessibleAnnouncementEvent(QObject *object, const QString &message)
+ : QAccessibleEvent(object, QAccessible::InvalidEvent)
+ , m_message(message)
+ , m_priority(QAccessible::AnnouncementPriority::Polite)
+ {
+ m_type = QAccessible::Announcement;
+ }
+
+ inline QAccessibleAnnouncementEvent(QAccessibleInterface *iface, const QString &message)
+ : QAccessibleEvent(iface, QAccessible::InvalidEvent)
+ , m_message(message)
+ , m_priority(QAccessible::AnnouncementPriority::Polite)
+ {
+ m_type = QAccessible::Announcement;
+ }
+
+ ~QAccessibleAnnouncementEvent();
+
+ QString message() const { return m_message; }
+ QAccessible::AnnouncementPriority priority() const { return m_priority; }
+ void setPriority(QAccessible::AnnouncementPriority priority) { m_priority = priority; };
+
+protected:
+ QString m_message;
+ QAccessible::AnnouncementPriority m_priority;
+};
+
#ifndef Q_QDOC
#define QAccessibleInterface_iid "org.qt-project.Qt.QAccessibleInterface"
Q_DECLARE_INTERFACE(QAccessibleInterface, QAccessibleInterface_iid)
diff --git a/src/gui/accessible/qaccessible_base.h b/src/gui/accessible/qaccessible_base.h
index 2d2b1de316..1a7b75c7f5 100644
--- a/src/gui/accessible/qaccessible_base.h
+++ b/src/gui/accessible/qaccessible_base.h
@@ -101,6 +101,7 @@ public:
HelpChanged = 0x80A0,
DefaultActionChanged = 0x80B0,
AcceleratorChanged = 0x80C0,
+ Announcement = 0x80D0,
InvalidEvent
};
@@ -367,6 +368,11 @@ public:
Level,
};
+ enum class AnnouncementPriority {
+ Polite,
+ Assertive
+ };
+
typedef QAccessibleInterface*(*InterfaceFactory)(const QString &key, QObject*);
typedef void(*UpdateHandler)(QAccessibleEvent *event);
typedef void(*RootObjectHandler)(QObject*);
diff --git a/src/gui/compat/removed_api.cpp b/src/gui/compat/removed_api.cpp
index a64580e9e1..a642c33c42 100644
--- a/src/gui/compat/removed_api.cpp
+++ b/src/gui/compat/removed_api.cpp
@@ -7,6 +7,17 @@
QT_USE_NAMESPACE
+#if QT_GUI_REMOVED_SINCE(6, 4)
+
+#include "qpagesize.h" // removed duplicate declaration of op==
+ // (still caused an symbol on some platforms)
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_GUI_REMOVED_SINCE(6, 4)
+
#if QT_GUI_REMOVED_SINCE(6, 6)
#include "qpixmapcache.h" // inlined API
@@ -26,8 +37,34 @@ bool Qt::mightBeRichText(const QString& text)
return Qt::mightBeRichText(qToStringViewIgnoringNull(text));
}
+#endif // QT_GUI_REMOVED_SINCE(6, 7)
+
+#if QT_GUI_REMOVED_SINCE(6, 8)
+
+#include "qpagelayout.h"
+
+bool QPageLayout::setMargins(const QMarginsF &margins)
+{
+ return setMargins(margins, OutOfBoundsPolicy::Reject);
+}
+
+bool QPageLayout::setLeftMargin(qreal leftMargin)
+{
+ return setLeftMargin(leftMargin, OutOfBoundsPolicy::Reject);
+}
+
+bool QPageLayout::setRightMargin(qreal rightMargin)
+{
+ return setRightMargin(rightMargin, OutOfBoundsPolicy::Reject);
+}
+
+bool QPageLayout::setTopMargin(qreal topMargin)
+{
+ return setTopMargin(topMargin, OutOfBoundsPolicy::Reject);
+}
+
// #include "qotherheader.h"
// // implement removed functions from qotherheader.h
// order sections alphabetically
-#endif // QT_GUI_REMOVED_SINCE(6, 7)
+#endif // QT_GUI_REMOVED_SINCE(6, 8)
diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake
index e1d8efb292..da08863ac6 100644
--- a/src/gui/configure.cmake
+++ b/src/gui/configure.cmake
@@ -893,7 +893,7 @@ qt_feature("jpeg" PRIVATE
CONDITION QT_FEATURE_imageformatplugin
DISABLE INPUT_libjpeg STREQUAL 'no'
)
-qt_feature_definition("jpeg" "QT_NO_IMAGEFORMAT_JPEG" NEGATE)
+qt_feature_definition("jpeg" "QT_NO_IMAGEFORMAT_JPEG" NEGATE VALUE "1")
qt_feature("system-jpeg" PRIVATE
LABEL " Using system libjpeg"
CONDITION QT_FEATURE_jpeg AND JPEG_FOUND
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index 086ac37a07..3fc29ee10d 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -160,15 +160,16 @@ static inline int area(const QSize &s) { return s.width() * s.height(); }
// the 2x pixmaps then.)
static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
{
-
+ const auto scaleA = pa->pixmap.devicePixelRatio();
+ const auto scaleB = pb->pixmap.devicePixelRatio();
// scale: we can only differentiate on scale if the scale differs
- if (pa->scale != pb->scale) {
+ if (scaleA != scaleB) {
// Score the pixmaps: 0 is an exact scale match, positive
// scores have more detail than requested, negative scores
// have less detail than requested.
- qreal ascore = pa->scale - scale;
- qreal bscore = pb->scale - scale;
+ qreal ascore = scaleA - scale;
+ qreal bscore = scaleB - scale;
// always prefer positive scores to prevent upscaling
if ((ascore < 0) != (bscore < 0))
@@ -201,13 +202,14 @@ static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale
QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
{
QPixmapIconEngineEntry *pe = nullptr;
- for (int i = 0; i < pixmaps.size(); ++i)
- if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) {
+ for (auto &entry : pixmaps) {
+ if (entry.mode == mode && entry.state == state) {
if (pe)
- pe = bestSizeScaleMatch(size, scale, &pixmaps[i], pe);
+ pe = bestSizeScaleMatch(size, scale, &entry, pe);
else
- pe = &pixmaps[i];
+ pe = &entry;
}
+ }
return pe;
}
@@ -278,7 +280,7 @@ QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIc
pm = pe->pixmap;
if (pm.isNull()) {
- int idx = pixmaps.size();
+ auto idx = pixmaps.size();
while (--idx >= 0) {
if (pe == &pixmaps.at(idx)) {
pixmaps.remove(idx);
@@ -369,7 +371,7 @@ void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon
{
if (!pixmap.isNull()) {
QPixmapIconEngineEntry *pe = tryMatch(pixmap.size(), pixmap.devicePixelRatio(), mode, state);
- if (pe && pe->size == pixmap.size() && pe->scale == pixmap.devicePixelRatio()) {
+ if (pe && pe->size == pixmap.size() && pe->pixmap.devicePixelRatio() == pixmap.devicePixelRatio()) {
pe->pixmap = pixmap;
pe->fileName.clear();
} else {
@@ -387,7 +389,7 @@ static inline int origIcoDepth(const QImage &image)
static inline int findBySize(const QList<QImage> &images, const QSize &size)
{
- for (int i = 0; i < images.size(); ++i) {
+ for (qsizetype i = 0; i < images.size(); ++i) {
if (images.at(i).size() == size)
return i;
}
diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h
index c5bf120620..dfce2d5b53 100644
--- a/src/gui/image/qicon_p.h
+++ b/src/gui/image/qicon_p.h
@@ -49,24 +49,22 @@ public:
struct QPixmapIconEngineEntry
{
- QPixmapIconEngineEntry():scale(1), mode(QIcon::Normal), state(QIcon::Off){}
- QPixmapIconEngineEntry(const QPixmap &pm, QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off)
- :pixmap(pm), size(pm.size()), scale(pm.devicePixelRatio()), mode(m), state(s){}
- QPixmapIconEngineEntry(const QString &file, const QSize &sz = QSize(), QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off)
- :fileName(file), size(sz), scale(1), mode(m), state(s){}
- QPixmapIconEngineEntry(const QString &file, const QImage &image, QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off);
+ QPixmapIconEngineEntry() = default;
+ QPixmapIconEngineEntry(const QPixmap &pm, QIcon::Mode m, QIcon::State s)
+ : pixmap(pm), size(pm.size()), mode(m), state(s) {}
+ QPixmapIconEngineEntry(const QString &file, const QSize &sz, QIcon::Mode m, QIcon::State s)
+ : fileName(file), size(sz), mode(m), state(s) {}
+ QPixmapIconEngineEntry(const QString &file, const QImage &image, QIcon::Mode m, QIcon::State s);
QPixmap pixmap;
QString fileName;
QSize size;
- qreal scale;
- QIcon::Mode mode;
- QIcon::State state;
- bool isNull() const {return (fileName.isEmpty() && pixmap.isNull()); }
+ QIcon::Mode mode = QIcon::Normal;
+ QIcon::State state = QIcon::Off;
};
Q_DECLARE_TYPEINFO(QPixmapIconEngineEntry, Q_RELOCATABLE_TYPE);
inline QPixmapIconEngineEntry::QPixmapIconEngineEntry(const QString &file, const QImage &image, QIcon::Mode m, QIcon::State s)
- : fileName(file), size(image.size()), scale(image.devicePixelRatio()), mode(m), state(s)
+ : fileName(file), size(image.size()), mode(m), state(s)
{
pixmap.convertFromImage(image);
}
diff --git a/src/gui/image/qiconengine.h b/src/gui/image/qiconengine.h
index 61411b0660..f5c5184608 100644
--- a/src/gui/image/qiconengine.h
+++ b/src/gui/image/qiconengine.h
@@ -18,6 +18,7 @@ public:
virtual ~QIconEngine();
virtual void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) = 0;
virtual QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ // ### Qt7: add qreal scale argument and remove scaledPixmap
virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
virtual void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state);
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 3bbf21320e..a24d7ccde7 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -1093,7 +1093,6 @@ QImage &QImage::operator=(const QImage &image)
/*!
\fn void QImage::swap(QImage &other)
- \since 4.8
Swaps image \a other with this image. This operation is very
fast and never fails.
@@ -1412,7 +1411,6 @@ int QImage::depth() const
}
/*!
- \since 4.6
\fn int QImage::colorCount() const
Returns the size of the color table for the image.
@@ -1676,7 +1674,6 @@ const uchar *QImage::scanLine(int i) const
shared pixel data, because the returned data is const.
\sa scanLine(), constBits()
- \since 4.7
*/
const uchar *QImage::constScanLine(int i) const
{
@@ -1732,7 +1729,6 @@ const uchar *QImage::bits() const
shared pixel data, because the returned data is const.
\sa bits(), constScanLine()
- \since 4.7
*/
const uchar *QImage::constBits() const
{
@@ -1839,7 +1835,6 @@ void QImage::fill(uint pixel)
/*!
\fn void QImage::fill(Qt::GlobalColor color)
\overload
- \since 4.8
Fills the image with the given \a color, described as a standard global
color.
@@ -1865,8 +1860,6 @@ void QImage::fill(Qt::GlobalColor color)
If the depth of the image is 8, the image will be filled with the
index corresponding the \a color in the color table if present; it
will otherwise be filled with 0.
-
- \since 4.8
*/
void QImage::fill(const QColor &color)
@@ -2123,7 +2116,6 @@ void QImage::invertPixels(InvertMode mode)
#endif
/*!
- \since 4.6
Resizes the color table to contain \a colorCount entries.
If the color table is expanded, all the extra colors will be set to
@@ -4607,7 +4599,6 @@ bool QImage::hasAlphaChannel() const
}
/*!
- \since 4.7
Returns the number of bit planes in the image.
The number of bit planes is the number of bits of color and
diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp
index 435f1dced9..0d13639d35 100644
--- a/src/gui/image/qmovie.cpp
+++ b/src/gui/image/qmovie.cpp
@@ -319,7 +319,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
// For an animated image format, QImageIOHandler::nextImageDelay() should
// provide the time to wait until showing the next frame; but multi-frame
// formats are not expected to provide this value, so use 1000 ms by default.
- const int nextFrameDelay = supportsAnimation ? reader->nextImageDelay() : 1000;
+ const auto nextFrameDelay = [&]() { return supportsAnimation ? reader->nextImageDelay() : 1000; };
if (cacheMode == QMovie::CacheNone) {
if (frameNumber != currentFrameNumber+1) {
@@ -363,7 +363,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
}
if (frameNumber > greatestFrameNumber)
greatestFrameNumber = frameNumber;
- return QFrameInfo(QPixmap::fromImage(std::move(anImage)), nextFrameDelay);
+ return QFrameInfo(QPixmap::fromImage(std::move(anImage)), nextFrameDelay());
} else if (frameNumber != 0) {
// We've read all frames now. Return an end marker
haveReadAll = true;
@@ -391,7 +391,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
return QFrameInfo(); // Invalid
}
greatestFrameNumber = i;
- QFrameInfo info(QPixmap::fromImage(std::move(anImage)), nextFrameDelay);
+ QFrameInfo info(QPixmap::fromImage(std::move(anImage)), nextFrameDelay());
// Cache it!
frameMap.insert(i, info);
if (i == frameNumber) {
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 89b8d5303b..afef16f867 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -289,7 +289,6 @@ QPixmap QPixmap::copy(const QRect &rect) const
/*!
\fn QPixmap::scroll(int dx, int dy, int x, int y, int width, int height, QRegion *exposed)
- \since 4.6
This convenience function is equivalent to calling QPixmap::scroll(\a dx,
\a dy, QRect(\a x, \a y, \a width, \a height), \a exposed).
@@ -298,8 +297,6 @@ QPixmap QPixmap::copy(const QRect &rect) const
*/
/*!
- \since 4.6
-
Scrolls the area \a rect of this pixmap by (\a dx, \a dy). The exposed
region is left unchanged. You can optionally pass a pointer to an empty
QRegion to get the region that is \a exposed by the scroll operation.
@@ -371,7 +368,6 @@ QPixmap &QPixmap::operator=(const QPixmap &pixmap)
/*!
\fn void QPixmap::swap(QPixmap &other)
- \since 4.8
Swaps pixmap \a other with this pixmap. This operation is very
fast and never fails.
@@ -970,12 +966,7 @@ bool QPixmap::isDetached() const
Passing 0 for \a flags sets all the default options. Returns \c true
if the result is that this pixmap is not null.
- Note: this function was part of Qt 3 support in Qt 4.6 and earlier.
- It has been promoted to official API status in 4.7 to support updating
- the pixmap's image without creating a new QPixmap as fromImage() would.
-
\sa fromImage()
- \since 4.7
*/
bool QPixmap::convertFromImage(const QImage &image, Qt::ImageConversionFlags flags)
{
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 636956aafa..5228ac9477 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1531,7 +1531,7 @@ void QGuiApplicationPrivate::createPlatformIntegration()
init_platform(QLatin1StringView(platformName), platformPluginPath, platformThemeName, argc, argv);
if (const QPlatformTheme *theme = platformTheme())
- QStyleHintsPrivate::get(QGuiApplication::styleHints())->setColorScheme(theme->colorScheme());
+ QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(theme->colorScheme());
if (!icon.isEmpty())
forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
@@ -2643,28 +2643,18 @@ void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::
QIconPrivate::clearIconCache();
- QStyleHintsPrivate::get(QGuiApplication::styleHints())->setColorScheme(colorScheme());
-
QEvent themeChangeEvent(QEvent::ThemeChange);
const QWindowList windows = tce->window ? QWindowList{tce->window} : window_list;
for (auto *window : windows)
QGuiApplication::sendSpontaneousEvent(window, &themeChangeEvent);
}
-/*!
- \internal
- \brief QGuiApplicationPrivate::colorScheme
- \return the platform theme's color scheme
- or Qt::ColorScheme::Unknown if a platform theme cannot be established
- */
-Qt::ColorScheme QGuiApplicationPrivate::colorScheme()
-{
- return platformTheme() ? platformTheme()->colorScheme()
- : Qt::ColorScheme::Unknown;
-}
-
void QGuiApplicationPrivate::handleThemeChanged()
{
+ const auto newColorScheme = platformTheme() ? platformTheme()->colorScheme()
+ : Qt::ColorScheme::Unknown;
+ QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(newColorScheme);
+
updatePalette();
QIconLoader::instance()->updateSystemTheme();
@@ -3457,6 +3447,15 @@ void QGuiApplicationPrivate::updatePalette()
}
}
+QEvent::Type QGuiApplicationPrivate::contextMenuEventType()
+{
+ switch (QGuiApplication::styleHints()->contextMenuTrigger()) {
+ case Qt::ContextMenuTrigger::Press: return QEvent::MouseButtonPress;
+ case Qt::ContextMenuTrigger::Release: return QEvent::MouseButtonRelease;
+ }
+ return QEvent::None;
+}
+
void QGuiApplicationPrivate::clearPalette()
{
delete app_pal;
@@ -3675,9 +3674,13 @@ void QGuiApplicationPrivate::notifyWindowIconChanged()
The default is \c true.
- If this property is \c true, the applications quits when the last visible
- \l{Primary and Secondary Windows}{primary window} (i.e. top level window
- with no transient parent) is closed.
+ If this property is \c true, the application will attempt to
+ quit when the last visible \l{Primary and Secondary Windows}{primary window}
+ (i.e. top level window with no transient parent) is closed.
+
+ Note that attempting a quit may not necessarily result in the
+ application quitting, for example if there still are active
+ QEventLoopLocker instances, or the QEvent::Quit event is ignored.
\sa quit(), QWindow::close()
*/
@@ -3733,7 +3736,13 @@ bool QGuiApplicationPrivate::lastWindowClosed() const
bool QGuiApplicationPrivate::canQuitAutomatically()
{
- if (quitOnLastWindowClosed && !lastWindowClosed())
+ // The automatic quit functionality is triggered by
+ // both QEventLoopLocker and maybeLastWindowClosed.
+ // Although the former is a QCoreApplication feature
+ // we don't want to quit the application when there
+ // are open windows, regardless of whether the app
+ // also quits automatically on maybeLastWindowClosed.
+ if (!lastWindowClosed())
return false;
return QCoreApplicationPrivate::canQuitAutomatically();
@@ -4392,6 +4401,9 @@ void *QGuiApplication::resolveInterface(const char *name, int revision) const
#if QT_CONFIG(wayland)
QT_NATIVE_INTERFACE_RETURN_IF(QWaylandApplication, platformNativeInterface());
#endif
+#if defined(Q_OS_VISIONOS)
+ QT_NATIVE_INTERFACE_RETURN_IF(QVisionOSApplication, platformIntegration);
+#endif
return QCoreApplication::resolveInterface(name, revision);
}
diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h
index 14bce88c62..23d7fb3d65 100644
--- a/src/gui/kernel/qguiapplication.h
+++ b/src/gui/kernel/qguiapplication.h
@@ -42,7 +42,7 @@ class Q_GUI_EXPORT QGuiApplication : public QCoreApplication
Q_PROPERTY(QString desktopFileName READ desktopFileName WRITE setDesktopFileName)
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection
NOTIFY layoutDirectionChanged)
- Q_PROPERTY(QString platformName READ platformName STORED false)
+ Q_PROPERTY(QString platformName READ platformName STORED false CONSTANT)
Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed
WRITE setQuitOnLastWindowClosed)
Q_PROPERTY(QScreen *primaryScreen READ primaryScreen NOTIFY primaryScreenChanged STORED false)
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 58c3f33394..39c490c581 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -323,7 +323,7 @@ public:
static void updatePalette();
- static Qt::ColorScheme colorScheme();
+ static QEvent::Type contextMenuEventType();
protected:
virtual void handleThemeChanged();
@@ -403,8 +403,6 @@ struct Q_GUI_EXPORT QWindowsApplication
virtual bool isWinTabEnabled() const = 0;
virtual bool setWinTabEnabled(bool enabled) = 0;
- virtual bool isDarkMode() const = 0;
-
virtual DarkModeHandling darkModeHandling() const = 0;
virtual void setDarkModeHandling(DarkModeHandling handling) = 0;
diff --git a/src/gui/kernel/qguiapplication_platform.h b/src/gui/kernel/qguiapplication_platform.h
index 545bf75c84..d9ff01bf14 100644
--- a/src/gui/kernel/qguiapplication_platform.h
+++ b/src/gui/kernel/qguiapplication_platform.h
@@ -32,6 +32,22 @@ struct wl_pointer;
struct wl_touch;
#endif
+#if defined(Q_OS_VISIONOS) || defined(Q_QDOC)
+# ifdef __OBJC__
+Q_FORWARD_DECLARE_OBJC_CLASS(CP_OBJECT_cp_layer_renderer_capabilities);
+typedef CP_OBJECT_cp_layer_renderer_capabilities *cp_layer_renderer_capabilities_t;
+Q_FORWARD_DECLARE_OBJC_CLASS(CP_OBJECT_cp_layer_renderer_configuration);
+typedef CP_OBJECT_cp_layer_renderer_configuration *cp_layer_renderer_configuration_t;
+Q_FORWARD_DECLARE_OBJC_CLASS(CP_OBJECT_cp_layer_renderer);
+typedef CP_OBJECT_cp_layer_renderer *cp_layer_renderer_t;
+# else
+typedef struct cp_layer_renderer_capabilities_s *cp_layer_renderer_capabilities_t;
+typedef struct cp_layer_renderer_configuration_s *cp_layer_renderer_configuration_t;
+typedef struct cp_layer_renderer_s *cp_layer_renderer_t;
+# endif
+#endif
+
+
QT_BEGIN_NAMESPACE
namespace QNativeInterface
@@ -61,6 +77,20 @@ struct Q_GUI_EXPORT QWaylandApplication
};
#endif
+#if defined(Q_OS_VISIONOS) || defined(Q_QDOC)
+struct Q_GUI_EXPORT QVisionOSApplication
+{
+ QT_DECLARE_NATIVE_INTERFACE(QVisionOSApplication, 1, QGuiApplication)
+ struct ImmersiveSpaceCompositorLayer {
+ virtual void configure(cp_layer_renderer_capabilities_t, cp_layer_renderer_configuration_t) const {}
+ virtual void render(cp_layer_renderer_t) = 0;
+ };
+ virtual void setImmersiveSpaceCompositorLayer(ImmersiveSpaceCompositorLayer *layer) = 0;
+ virtual void openImmersiveSpace() = 0;
+ virtual void dismissImmersiveSpace() = 0;
+};
+#endif
+
} // QNativeInterface
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp
index fe72e7782f..78a1660355 100644
--- a/src/gui/kernel/qguivariant.cpp
+++ b/src/gui/kernel/qguivariant.cpp
@@ -78,7 +78,9 @@ static constexpr struct : QMetaTypeModuleHelper
// either two nullptrs from canConvert, or two valid pointers
Q_ASSERT(onlyCheck || (bool(from) && bool(to)));
+#if QT_CONFIG(shortcut)
using Int = int;
+#endif
switch (makePair(toTypeId, fromTypeId)) {
QMETATYPE_CONVERTER(QByteArray, QColor,
result = source.name(source.alpha() != 255 ?
diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h
index 189f31fd0a..d6deb8a72a 100644
--- a/src/gui/kernel/qhighdpiscaling_p.h
+++ b/src/gui/kernel/qhighdpiscaling_p.h
@@ -172,7 +172,7 @@ inline QMargins scale(const QMargins &margins, qreal scaleFactor, QPoint origin
template<typename T>
QList<T> scale(const QList<T> &list, qreal scaleFactor, QPoint origin = QPoint(0, 0))
{
- if (!QHighDpiScaling::isActive())
+ if (qFuzzyCompare(scaleFactor, qreal(1)))
return list;
QList<T> scaled;
@@ -184,7 +184,7 @@ QList<T> scale(const QList<T> &list, qreal scaleFactor, QPoint origin = QPoint(0
inline QRegion scale(const QRegion &region, qreal scaleFactor, QPoint origin = QPoint(0, 0))
{
- if (!QHighDpiScaling::isActive())
+ if (qFuzzyCompare(scaleFactor, qreal(1)))
return region;
QRegion scaled = region.translated(-origin);
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 02781f4aa0..dd41318f72 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -170,6 +170,9 @@ QOpenGLContext *QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context
qWarning("No QTLS available. currentContext won't work");
return nullptr;
}
+ if (!context)
+ return nullptr;
+
threadContext = new QGuiGLThreadContext;
qwindow_context_storage()->setLocalData(threadContext);
}
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index 48978b849a..3d1319615e 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -447,6 +447,11 @@ Qt::ColorScheme QPlatformTheme::colorScheme() const
return Qt::ColorScheme::Unknown;
}
+void QPlatformTheme::requestColorScheme(Qt::ColorScheme scheme)
+{
+ Q_UNUSED(scheme);
+}
+
const QPalette *QPlatformTheme::palette(Palette type) const
{
Q_D(const QPlatformTheme);
diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h
index c0193947b9..d007a19675 100644
--- a/src/gui/kernel/qplatformtheme.h
+++ b/src/gui/kernel/qplatformtheme.h
@@ -295,6 +295,7 @@ public:
#endif
virtual Qt::ColorScheme colorScheme() const;
+ virtual void requestColorScheme(Qt::ColorScheme scheme);
virtual const QPalette *palette(Palette type = SystemPalette) const;
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index 3baa48247b..5c0ae2ee2a 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -778,6 +778,15 @@ void QPlatformWindow::deliverUpdateRequest()
QWindow *w = window();
QWindowPrivate *wp = qt_window_private(w);
+
+ // We expect that the platform plugins send DevicePixelRatioChange events.
+ // As a fail-safe make a final check here to make sure the cached DPR value is
+ // always up to date before delivering the update request.
+ if (wp->updateDevicePixelRatio()) {
+ qWarning() << "The cached device pixel ratio value was stale on window update. "
+ << "Please file a QTBUG which explains how to reproduce.";
+ }
+
wp->updateRequestPending = false;
QEvent request(QEvent::UpdateRequest);
QCoreApplication::sendEvent(w, &request);
diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp
index 5becae76c6..73c6199733 100644
--- a/src/gui/kernel/qstylehints.cpp
+++ b/src/gui/kernel/qstylehints.cpp
@@ -123,8 +123,29 @@ int QStyleHints::touchDoubleTapDistance() const
/*!
\property QStyleHints::colorScheme
- \brief the color scheme of the platform theme.
- \sa Qt::ColorScheme
+ \brief the color scheme used by the application.
+
+ By default, this follows the system's default color scheme (also known as appearance),
+ and changes when the system color scheme changes (e.g. during dusk or dawn).
+ Setting the color scheme to an explicit value will override the system setting and
+ ignore any changes to the system's color scheme. However, doing so is a hint to the
+ system, and overriding the color scheme is not supported on all platforms.
+
+ Resetting this property, or setting it to \l{Qt::ColorScheme::Unknown}, will remove
+ the override and make the application follow the system default again. The property
+ value will change to the color scheme the system currently has.
+
+ When this property changes, Qt will read the system palette and update the default
+ palette, but won't overwrite palette entries that have been explicitly set by the
+ application. When the colorSchemeChange() signal gets emitted, the old palette is
+ still in effect.
+
+ Application-specific colors should be selected to work well with the effective
+ palette, taking the current color scheme into account. To update application-
+ specific colors when the effective palette changes, handle
+ \l{QEvent::}{PaletteChange} or \l{QEvent::}{ApplicationPaletteChange} events.
+
+ \sa Qt::ColorScheme, QGuiApplication::palette(), QEvent::PaletteChange
\since 6.5
*/
Qt::ColorScheme QStyleHints::colorScheme() const
@@ -134,6 +155,30 @@ Qt::ColorScheme QStyleHints::colorScheme() const
}
/*!
+ \since 6.8
+
+ Sets the color scheme used by the application to an explicit \a scheme, or
+ revert to the system's current color scheme if \a scheme is Qt::ColorScheme::Unknown.
+*/
+void QStyleHints::setColorScheme(Qt::ColorScheme scheme)
+{
+ if (!QCoreApplication::instance()) {
+ qWarning("Must construct a QGuiApplication before accessing a platform theme hint.");
+ return;
+ }
+ if (QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ theme->requestColorScheme(scheme);
+}
+
+/*!
+ \fn void QStyleHints::unsetColorScheme()
+ \since 6.8
+
+ Restores the color scheme to the system's current color scheme.
+*/
+
+
+/*!
Sets the \a mousePressAndHoldInterval.
\internal
\sa mousePressAndHoldInterval()
@@ -398,6 +443,40 @@ void QStyleHints::setShowShortcutsInContextMenus(bool s)
}
/*!
+ \property QStyleHints::contextMenuTrigger
+ \since 6.8
+ \brief mouse event used to trigger a context menu event.
+
+ The default on UNIX systems is to show context menu on mouse button press event, while on
+ Windows it is the mouse button release event. This property can be used to override the default
+ platform behavior.
+
+ \note Developers must use this property with great care, as it changes the default interaction
+ mode that their users will expect on the platform that they are running on.
+
+ \sa Qt::ContextMenuTrigger
+*/
+Qt::ContextMenuTrigger QStyleHints::contextMenuTrigger() const
+{
+ Q_D(const QStyleHints);
+ if (d->m_contextMenuTrigger == -1) {
+ return themeableHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool()
+ ? Qt::ContextMenuTrigger::Release
+ : Qt::ContextMenuTrigger::Press;
+ }
+ return Qt::ContextMenuTrigger(d->m_contextMenuTrigger);
+}
+
+void QStyleHints::setContextMenuTrigger(Qt::ContextMenuTrigger contextMenuTrigger)
+{
+ Q_D(QStyleHints);
+ const Qt::ContextMenuTrigger currentTrigger = this->contextMenuTrigger();
+ d->m_contextMenuTrigger = int(contextMenuTrigger);
+ if (currentTrigger != contextMenuTrigger)
+ emit contextMenuTriggerChanged(contextMenuTrigger);
+}
+
+/*!
\property QStyleHints::passwordMaskDelay
\brief the time, in milliseconds, a typed letter is displayed unshrouded
in a text input field in password mode.
@@ -595,11 +674,15 @@ int QStyleHints::mouseQuickSelectionThreshold() const
/*!
\internal
- QStyleHintsPrivate::setColorScheme - set a new color scheme.
+ QStyleHintsPrivate::updateColorScheme - set a new color scheme.
+
+ This function is called by the QPA plugin when the system theme changes. This in
+ turn might be the result of an explicit request of a color scheme via setColorScheme.
+
Set \a colorScheme as the new color scheme of the QStyleHints.
The colorSchemeChanged signal will be emitted if present and new color scheme differ.
*/
-void QStyleHintsPrivate::setColorScheme(Qt::ColorScheme colorScheme)
+void QStyleHintsPrivate::updateColorScheme(Qt::ColorScheme colorScheme)
{
if (m_colorScheme == colorScheme)
return;
diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h
index 969bec4b35..97ef59f3cf 100644
--- a/src/gui/kernel/qstylehints.h
+++ b/src/gui/kernel/qstylehints.h
@@ -36,6 +36,8 @@ class Q_GUI_EXPORT QStyleHints : public QObject
Q_PROPERTY(bool showIsMaximized READ showIsMaximized STORED false CONSTANT FINAL)
Q_PROPERTY(bool showShortcutsInContextMenus READ showShortcutsInContextMenus
WRITE setShowShortcutsInContextMenus NOTIFY showShortcutsInContextMenusChanged FINAL)
+ Q_PROPERTY(Qt::ContextMenuTrigger contextMenuTrigger READ contextMenuTrigger WRITE
+ setContextMenuTrigger NOTIFY contextMenuTriggerChanged FINAL)
Q_PROPERTY(int startDragDistance READ startDragDistance NOTIFY startDragDistanceChanged FINAL)
Q_PROPERTY(int startDragTime READ startDragTime NOTIFY startDragTimeChanged FINAL)
Q_PROPERTY(int startDragVelocity READ startDragVelocity STORED false CONSTANT FINAL)
@@ -52,7 +54,8 @@ class Q_GUI_EXPORT QStyleHints : public QObject
Q_PROPERTY(int mouseDoubleClickDistance READ mouseDoubleClickDistance STORED false CONSTANT
FINAL)
Q_PROPERTY(int touchDoubleTapDistance READ touchDoubleTapDistance STORED false CONSTANT FINAL)
- Q_PROPERTY(Qt::ColorScheme colorScheme READ colorScheme NOTIFY colorSchemeChanged FINAL)
+ Q_PROPERTY(Qt::ColorScheme colorScheme READ colorScheme WRITE setColorScheme
+ RESET unsetColorScheme NOTIFY colorSchemeChanged FINAL)
public:
void setMouseDoubleClickInterval(int mouseDoubleClickInterval);
@@ -79,6 +82,8 @@ public:
bool showIsMaximized() const;
bool showShortcutsInContextMenus() const;
void setShowShortcutsInContextMenus(bool showShortcutsInContextMenus);
+ Qt::ContextMenuTrigger contextMenuTrigger() const;
+ void setContextMenuTrigger(Qt::ContextMenuTrigger contextMenuTrigger);
int passwordMaskDelay() const;
QChar passwordMaskCharacter() const;
qreal fontSmoothingGamma() const;
@@ -94,6 +99,8 @@ public:
void setMouseQuickSelectionThreshold(int threshold);
int mouseQuickSelectionThreshold() const;
Qt::ColorScheme colorScheme() const;
+ void setColorScheme(Qt::ColorScheme scheme);
+ void unsetColorScheme() { setColorScheme(Qt::ColorScheme::Unknown); }
Q_SIGNALS:
void cursorFlashTimeChanged(int cursorFlashTime);
@@ -105,6 +112,7 @@ Q_SIGNALS:
void tabFocusBehaviorChanged(Qt::TabFocusBehavior tabFocusBehavior);
void useHoverEffectsChanged(bool useHoverEffects);
void showShortcutsInContextMenusChanged(bool);
+ void contextMenuTriggerChanged(Qt::ContextMenuTrigger contextMenuTrigger);
void wheelScrollLinesChanged(int scrollLines);
void mouseQuickSelectionThresholdChanged(int threshold);
void colorSchemeChanged(Qt::ColorScheme colorScheme);
diff --git a/src/gui/kernel/qstylehints_p.h b/src/gui/kernel/qstylehints_p.h
index c58386d7a3..497bf95cbf 100644
--- a/src/gui/kernel/qstylehints_p.h
+++ b/src/gui/kernel/qstylehints_p.h
@@ -35,13 +35,14 @@ public:
int m_tabFocusBehavior = -1;
int m_uiEffects = -1;
int m_showShortcutsInContextMenus = -1;
+ int m_contextMenuTrigger = -1;
int m_wheelScrollLines = -1;
int m_mouseQuickSelectionThreshold = -1;
int m_mouseDoubleClickDistance = -1;
int m_touchDoubleTapDistance = -1;
Qt::ColorScheme colorScheme() const { return m_colorScheme; }
- void setColorScheme(Qt::ColorScheme colorScheme);
+ void updateColorScheme(Qt::ColorScheme colorScheme);
static QStyleHintsPrivate *get(QStyleHints *q);
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index b40fd7e8e8..7c885032c7 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -2654,16 +2654,14 @@ bool QWindow::event(QEvent *ev)
This logic could be simplified by always synthesizing events in
QGuiApplicationPrivate, or perhaps even in each QPA plugin. See QTBUG-93486.
*/
- static const QEvent::Type contextMenuTrigger =
- QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
- QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
auto asMouseEvent = [](QEvent *ev) {
const auto t = ev->type();
return t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease
? static_cast<QMouseEvent *>(ev) : nullptr ;
};
- if (QMouseEvent *me = asMouseEvent(ev); me &&
- ev->type() == contextMenuTrigger && me->button() == Qt::RightButton) {
+ if (QMouseEvent *me = asMouseEvent(ev);
+ me && ev->type() == QGuiApplicationPrivate::contextMenuEventType()
+ && me->button() == Qt::RightButton) {
QContextMenuEvent e(QContextMenuEvent::Mouse, me->position().toPoint(),
me->globalPosition().toPoint(), me->modifiers());
QGuiApplication::sendEvent(this, &e);
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index a9716847a1..40ab06af8b 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -76,6 +76,16 @@ public:
void setTransientParent(QWindow *parent);
virtual void clearFocusObject();
+
+ enum class FocusTarget {
+ First,
+ Last,
+ Current,
+ Next,
+ Prev
+ };
+ virtual void setFocusToTarget(FocusTarget, Qt::FocusReason) {}
+
virtual QRectF closestAcceptableGeometry(const QRectF &rect) const;
void setMinOrMaxSize(QSize *oldSizeMember, const QSize &size,
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 2304ee2256..3b709ec77b 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -50,6 +50,7 @@ public:
QScopedPointer<QImage> highDpiBackingstore;
QRegion staticContents;
QSize size;
+ QSize nativeSize;
bool downscale = qEnvironmentVariableIntValue("QT_WIDGETS_HIGHDPI_DOWNSCALE") > 0;
};
@@ -115,14 +116,13 @@ QWindow* QBackingStore::window() const
void QBackingStore::beginPaint(const QRegion &region)
{
- const qreal dpr = d_ptr->backingStoreDevicePixelRatio();
+ const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
- if (d_ptr->highDpiBackingstore &&
- d_ptr->highDpiBackingstore->devicePixelRatio() != dpr)
+ if (d_ptr->nativeSize != QHighDpi::scale(size(), toNativeFactor))
resize(size());
QPlatformBackingStore *platformBackingStore = handle();
- platformBackingStore->beginPaint(QHighDpi::scale(region, d_ptr->deviceIndependentToNativeFactor()));
+ platformBackingStore->beginPaint(QHighDpi::scale(region, toNativeFactor));
// When QtGui is applying a high-dpi scale factor the backing store
// creates a "large" backing store image. This image needs to be
@@ -131,18 +131,20 @@ void QBackingStore::beginPaint(const QRegion &region)
// the image data to avoid having the new devicePixelRatio be propagated
// back to the platform plugin.
QPaintDevice *device = platformBackingStore->paintDevice();
- if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) {
+ if (!qFuzzyCompare(toNativeFactor, qreal(1)) && device->devType() == QInternal::Image) {
QImage *source = static_cast<QImage *>(device);
const bool needsNewImage = d_ptr->highDpiBackingstore.isNull()
- || source->data_ptr() != d_ptr->highDpiBackingstore->data_ptr()
+ || source->constBits() != d_ptr->highDpiBackingstore->constBits()
|| source->size() != d_ptr->highDpiBackingstore->size()
- || source->devicePixelRatio() != d_ptr->highDpiBackingstore->devicePixelRatio();
- if (needsNewImage) {
+ || source->bytesPerLine() != d_ptr->highDpiBackingstore->bytesPerLine()
+ || source->format() != d_ptr->highDpiBackingstore->format();
+ if (needsNewImage)
d_ptr->highDpiBackingstore.reset(
new QImage(source->bits(), source->width(), source->height(), source->bytesPerLine(), source->format()));
- d_ptr->highDpiBackingstore->setDevicePixelRatio(dpr);
- }
+ d_ptr->highDpiBackingstore->setDevicePixelRatio(d_ptr->backingStoreDevicePixelRatio());
+ } else {
+ d_ptr->highDpiBackingstore.reset();
}
}
@@ -156,7 +158,7 @@ QPaintDevice *QBackingStore::paintDevice()
{
QPaintDevice *device = handle()->paintDevice();
- if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image)
+ if (!qFuzzyCompare(d_ptr->deviceIndependentToNativeFactor(), qreal(1)) && device->devType() == QInternal::Image)
return d_ptr->highDpiBackingstore.data();
return device;
@@ -229,9 +231,10 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
*/
void QBackingStore::resize(const QSize &size)
{
- d_ptr->size = size;
const qreal factor = d_ptr->deviceIndependentToNativeFactor();
- handle()->resize(QHighDpi::scale(size, factor), QHighDpi::scale(d_ptr->staticContents, factor));
+ d_ptr->size = size;
+ d_ptr->nativeSize = QHighDpi::scale(size, factor);
+ handle()->resize(d_ptr->nativeSize, QHighDpi::scale(d_ptr->staticContents, factor));
}
/*!
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 7a1d34a408..f21e6ec738 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -448,11 +448,15 @@ QColorTransform QColorSpacePrivate::transformationToXYZ() const
transform.d = ptr;
ptr->colorSpaceIn = this;
ptr->colorSpaceOut = this;
- // Convert to XYZ relative to our white point, not the regular D50 white point.
if (isThreeComponentMatrix())
- ptr->colorMatrix = QColorMatrix::chromaticAdaptation(whitePoint).inverted() * toXyz;
+ ptr->colorMatrix = toXyz;
else
ptr->colorMatrix = QColorMatrix::identity();
+ // Convert to XYZ relative to our white point, not the regular D50 white point.
+ if (!chad.isNull())
+ ptr->colorMatrix = chad.inverted() * ptr->colorMatrix;
+ else if (!whitePoint.isNull())
+ ptr->colorMatrix = QColorMatrix::chromaticAdaptation(whitePoint).inverted() * ptr->colorMatrix;
return transform;
}
diff --git a/src/gui/painting/qcolortransfertable_p.h b/src/gui/painting/qcolortransfertable_p.h
index 51c9cff6d6..ce6ad0c4b2 100644
--- a/src/gui/painting/qcolortransfertable_p.h
+++ b/src/gui/painting/qcolortransfertable_p.h
@@ -101,7 +101,7 @@ public:
return x;
x = std::clamp(x, 0.0f, 1.0f);
x *= m_tableSize - 1;
- const uint32_t lo = static_cast<uint32_t>(std::floor(x));
+ const uint32_t lo = static_cast<uint32_t>(x);
const uint32_t hi = std::min(lo + 1, m_tableSize - 1);
const float frac = x - lo;
if (!m_table16.isEmpty())
@@ -120,36 +120,10 @@ public:
return 0.0f;
if (x >= 1.0f)
return 1.0f;
- if (!m_table16.isEmpty()) {
- const float v = x * 65535.0f;
- uint32_t i = static_cast<uint32_t>(std::floor(resultLargerThan * (m_tableSize - 1)));
- auto it = std::lower_bound(m_table16.cbegin() + i, m_table16.cend(), v);
- i = it - m_table16.cbegin();
- if (i == 0)
- return 0.0f;
- if (i >= m_tableSize - 1)
- return 1.0f;
- const float y1 = m_table16[i - 1];
- const float y2 = m_table16[i];
- Q_ASSERT(v >= y1 && v <= y2);
- const float fr = (v - y1) / (y2 - y1);
- return (i + fr) * (1.0f / (m_tableSize - 1));
- }
- if (!m_table8.isEmpty()) {
- const float v = x * 255.0f;
- uint32_t i = static_cast<uint32_t>(std::floor(resultLargerThan * (m_tableSize - 1)));
- auto it = std::lower_bound(m_table8.cbegin() + i, m_table8.cend(), v);
- i = it - m_table8.cbegin();
- if (i == 0)
- return 0.0f;
- if (i >= m_tableSize - 1)
- return 1.0f;
- const float y1 = m_table8[i - 1];
- const float y2 = m_table8[i];
- Q_ASSERT(v >= y1 && v <= y2);
- const float fr = (v - y1) / (y2 - y1);
- return (i + fr) * (1.0f / (m_tableSize - 1));
- }
+ if (!m_table16.isEmpty())
+ return inverseLookup(x * 65535.0f, resultLargerThan, m_table16, m_tableSize - 1);
+ if (!m_table8.isEmpty())
+ return inverseLookup(x * 255.0f, resultLargerThan, m_table8, m_tableSize - 1);
return x;
}
@@ -213,6 +187,24 @@ public:
uint32_t m_tableSize = 0;
QList<uint8_t> m_table8;
QList<uint16_t> m_table16;
+private:
+ template<typename T>
+ static float inverseLookup(float needle, float resultLargerThan, const QList<T> &table, quint32 tableMax)
+ {
+ uint32_t i = static_cast<uint32_t>(resultLargerThan * tableMax);
+ auto it = std::lower_bound(table.cbegin() + i, table.cend(), needle);
+ i = it - table.cbegin();
+ if (i == 0)
+ return 0.0f;
+ if (i >= tableMax)
+ return 1.0f;
+ const float y1 = table[i - 1];
+ const float y2 = table[i];
+ Q_ASSERT(needle >= y1 && needle <= y2);
+ const float fr = (needle - y1) / (y2 - y1);
+ return (i + fr) * (1.0f / tableMax);
+ }
+
};
inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable &t2)
diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp
index aac07bdc09..33b1dcdeb0 100644
--- a/src/gui/painting/qcolortransform.cpp
+++ b/src/gui/painting/qcolortransform.cpp
@@ -1640,7 +1640,7 @@ void QColorTransformPrivate::applyConvertIn(const S *src, QColorVector *buffer,
loadUnpremultiplied(buffer, src, len, this);
if (!colorSpaceOut->isThreeComponentMatrix())
- applyMatrix<DoClamp>(buffer, len, colorMatrix); // colorMatrix should have the first half only.
+ applyMatrix<DoClamp>(buffer, len, colorSpaceIn->toXyz);
return;
}
}
@@ -1666,7 +1666,7 @@ void QColorTransformPrivate::applyConvertOut(D *dst, const S *src, QColorVector
// Avoid compiling this part for D=QCmyk32:
if constexpr (!std::is_same_v<D, QCmyk32>) {
if (colorSpaceOut->isThreeComponentMatrix()) {
- applyMatrix<doClamp>(buffer, len, colorMatrix); // colorMatrix should have the latter half only.
+ applyMatrix<doClamp>(buffer, len, colorMatrix);
if constexpr (std::is_same_v<S, QCmyk32>) {
storeOpaque(dst, buffer, len, this);
@@ -1695,14 +1695,34 @@ void QColorTransformPrivate::applyConvertOut(D *dst, const S *src, QColorVector
storeUnpremultipliedLUT(dst, src, buffer, len);
}
-template<typename D, typename S>
-void QColorTransformPrivate::applyElementListTransform(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+/*!
+ \internal
+ Adapt Profile Connecting Color spaces.
+*/
+void QColorTransformPrivate::pcsAdapt(QColorVector *buffer, qsizetype count) const
{
- Q_ASSERT(!colorSpaceIn->isThreeComponentMatrix() || !colorSpaceOut->isThreeComponentMatrix());
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < count; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < count; ++j)
+ buffer[j] = buffer[j].labToXyz();
+ }
+}
- if (!colorMatrix.isValid())
- return;
+/*!
+ \internal
+ Applies the color transformation on \a count S pixels starting from
+ \a src and stores the result in \a dst as D pixels .
+ Assumes unpremultiplied data by default. Set \a flags to change defaults.
+
+ \sa prepare()
+*/
+template<typename D, typename S>
+void QColorTransformPrivate::apply(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+{
if (colorSpaceIn->isThreeComponentMatrix())
updateLutsIn();
if (colorSpaceOut->isThreeComponentMatrix())
@@ -1715,14 +1735,7 @@ void QColorTransformPrivate::applyElementListTransform(D *dst, const S *src, qsi
applyConvertIn(src + i, buffer, len, flags);
- // Match Profile Connection Spaces (PCS):
- if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].xyzToLab();
- } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].labToXyz();
- }
+ pcsAdapt(buffer, len);
applyConvertOut(dst + i, src + i, buffer, len, flags);
@@ -1730,64 +1743,6 @@ void QColorTransformPrivate::applyElementListTransform(D *dst, const S *src, qsi
}
}
-template<typename D, typename S>
-void QColorTransformPrivate::applyThreeComponentMatrix(D *dst, const S *src, qsizetype count, TransformFlags flags) const
-{
- Q_ASSERT(colorSpaceIn->isThreeComponentMatrix() && colorSpaceOut->isThreeComponentMatrix());
-
- if (!colorMatrix.isValid())
- return;
-
- updateLutsIn();
- updateLutsOut();
-
- bool doApplyMatrix = !colorMatrix.isIdentity();
- constexpr ApplyMatrixForm doClamp = (std::is_same_v<D, QRgbaFloat16> || std::is_same_v<D, QRgbaFloat32>) ? DoNotClamp : DoClamp;
-
- QUninitialized<QColorVector, WorkBlockSize> buffer;
- qsizetype i = 0;
- while (i < count) {
- const qsizetype len = qMin(count - i, WorkBlockSize);
- if (flags & InputPremultiplied)
- loadPremultiplied(buffer, src + i, len, this);
- else
- loadUnpremultiplied(buffer, src + i, len, this);
-
- if (doApplyMatrix)
- applyMatrix<doClamp>(buffer, len, colorMatrix);
- else
- clampIfNeeded<doClamp>(buffer, len);
-
- if (flags & InputOpaque)
- storeOpaque(dst + i, buffer, len, this);
- else if (flags & OutputPremultiplied)
- storePremultiplied(dst + i, src + i, buffer, len, this);
- else
- storeUnpremultiplied(dst + i, src + i, buffer, len, this);
-
- i += len;
- }
-}
-
-/*!
- \internal
- Applies the color transformation on \a count S pixels starting from
- \a src and stores the result in \a dst as D pixels .
-
- Assumes unpremultiplied data by default. Set \a flags to change defaults.
-
- \sa prepare()
-*/
-template<typename D, typename S>
-void QColorTransformPrivate::apply(D *dst, const S *src, qsizetype count, TransformFlags flags) const
-{
- if constexpr (!std::is_same_v<D, QCmyk32> && !std::is_same_v<S, QCmyk32>) {
- if (isThreeComponentMatrix())
- return applyThreeComponentMatrix<D, S>(dst, src, count, flags);
- }
- applyElementListTransform<D, S>(dst, src, count, flags);
-}
-
/*!
\internal
Is to be called on a color-transform to XYZ, returns only luminance values.
@@ -1970,15 +1925,6 @@ template void QColorTransformPrivate::apply<QRgbaFloat32, QCmyk32>(QRgbaFloat32
template void QColorTransformPrivate::apply<QRgbaFloat32, QRgba64>(QRgbaFloat32 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QRgbaFloat32, QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src, qsizetype count, TransformFlags flags) const;
-bool QColorTransformPrivate::isThreeComponentMatrix() const
-{
- if (colorSpaceIn && !colorSpaceIn->isThreeComponentMatrix())
- return false;
- if (colorSpaceOut && !colorSpaceOut->isThreeComponentMatrix())
- return false;
- return true;
-}
-
/*!
\internal
*/
@@ -1991,7 +1937,7 @@ bool QColorTransformPrivate::isIdentity() const
if (colorSpaceIn && colorSpaceOut) {
if (colorSpaceIn->equals(colorSpaceOut.constData()))
return true;
- if (!isThreeComponentMatrix())
+ if (!colorSpaceIn->isThreeComponentMatrix() || !colorSpaceOut->isThreeComponentMatrix())
return false;
if (colorSpaceIn->transferFunction != colorSpaceOut->transferFunction)
return false;
@@ -2001,7 +1947,9 @@ bool QColorTransformPrivate::isIdentity() const
&& colorSpaceIn->trc[2] == colorSpaceOut->trc[2];
}
} else {
- if (!isThreeComponentMatrix())
+ if (colorSpaceIn && !colorSpaceIn->isThreeComponentMatrix())
+ return false;
+ if (colorSpaceOut && !colorSpaceOut->isThreeComponentMatrix())
return false;
if (colorSpaceIn && colorSpaceIn->transferFunction != QColorSpace::TransferFunction::Linear)
return false;
diff --git a/src/gui/painting/qcolortransform_p.h b/src/gui/painting/qcolortransform_p.h
index 59ea6a2405..c74fe100eb 100644
--- a/src/gui/painting/qcolortransform_p.h
+++ b/src/gui/painting/qcolortransform_p.h
@@ -37,7 +37,6 @@ public:
void updateLutsIn() const;
void updateLutsOut() const;
bool isIdentity() const;
- bool isThreeComponentMatrix() const;
Q_GUI_EXPORT void prepare();
enum TransformFlag {
@@ -60,14 +59,11 @@ public:
void applyReturnGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
private:
+ void pcsAdapt(QColorVector *buffer, qsizetype len) const;
template<typename S>
void applyConvertIn(const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const;
template<typename D, typename S>
void applyConvertOut(D *dst, const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const;
- template<typename D, typename S>
- void applyElementListTransform(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
- template<typename D, typename S>
- void applyThreeComponentMatrix(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index 59f941b017..a2786fbb8b 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -559,6 +559,8 @@ static bool parseXyzData(const QByteArray &data, const TagEntry &tagEntry, QColo
static quint32 parseTRC(const QByteArrayView &tagData, QColorTrc &gamma, QColorTransferTable::Type type = QColorTransferTable::TwoWay)
{
+ if (tagData.size() < 12)
+ return 0;
const GenericTagData trcData = qFromUnaligned<GenericTagData>(tagData.constData());
if (trcData.type == quint32(Tag::curv)) {
Q_STATIC_ASSERT(sizeof(CurvTagData) == 12);
@@ -778,6 +780,10 @@ static bool parseLutData(const QByteArray &data, const TagEntry &tagEntry, QColo
qCWarning(lcIcc) << "Undersized lut8/lut16 tag, no room for tables";
return false;
}
+ if (colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && clutTableSize == 0) {
+ qCWarning(lcIcc) << "Cmyk conversion must have a CLUT";
+ return false;
+ }
const uint8_t *tableData = reinterpret_cast<const uint8_t *>(data.constData() + tagEntry.offset + sizeof(T));
@@ -997,6 +1003,9 @@ static bool parseMabData(const QByteArray &data, const TagEntry &tagEntry, QColo
const uint8_t *clutTable = reinterpret_cast<const uint8_t *>(data.constData() + tagEntry.offset + mab.clutOffset + 20);
parseCLUT(clutTable, (1.f/255.f), &clutElement, mab.outputChannels);
}
+ } else if (colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk) {
+ qCWarning(lcIcc) << "Cmyk conversion must have a CLUT";
+ return false;
}
if (isAb) {
@@ -1060,6 +1069,8 @@ static bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString
// Either 'desc' (ICCv2) or 'mluc' (ICCv4)
if (tag.type == quint32(Tag::desc)) {
+ if (tagEntry.size < sizeof(DescTagData))
+ return false;
Q_STATIC_ASSERT(sizeof(DescTagData) == 12);
const DescTagData desc = qFromUnaligned<DescTagData>(data.constData() + tagEntry.offset);
const quint32 len = desc.asciiDescriptionLength;
@@ -1280,7 +1291,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
qCWarning(lcIcc) << "fromIccProfile: failed tag offset sanity 2";
return false;
}
- if (tagTable.size < 12) {
+ if (tagTable.size < 8) {
qCWarning(lcIcc) << "fromIccProfile: failed minimal tag size sanity";
return false;
}
diff --git a/src/gui/painting/qpagelayout.cpp b/src/gui/painting/qpagelayout.cpp
index ec505f2cce..e60f464d6e 100644
--- a/src/gui/painting/qpagelayout.cpp
+++ b/src/gui/painting/qpagelayout.cpp
@@ -79,7 +79,7 @@ public:
bool isValid() const;
- void clampMargins(const QMarginsF &margins);
+ QMarginsF clampMargins(const QMarginsF &margins) const;
QMarginsF margins(QPageLayout::Unit units) const;
QMarginsF marginsPoints() const;
@@ -151,12 +151,12 @@ bool QPageLayoutPrivate::isValid() const
return m_pageSize.isValid();
}
-void QPageLayoutPrivate::clampMargins(const QMarginsF &margins)
+QMarginsF QPageLayoutPrivate::clampMargins(const QMarginsF &margins) const
{
- m_margins = QMarginsF(qBound(m_minMargins.left(), margins.left(), m_maxMargins.left()),
- qBound(m_minMargins.top(), margins.top(), m_maxMargins.top()),
- qBound(m_minMargins.right(), margins.right(), m_maxMargins.right()),
- qBound(m_minMargins.bottom(), margins.bottom(), m_maxMargins.bottom()));
+ return QMarginsF(qBound(m_minMargins.left(), margins.left(), m_maxMargins.left()),
+ qBound(m_minMargins.top(), margins.top(), m_maxMargins.top()),
+ qBound(m_minMargins.right(), margins.right(), m_maxMargins.right()),
+ qBound(m_minMargins.bottom(), margins.bottom(), m_maxMargins.bottom()));
}
QMarginsF QPageLayoutPrivate::margins(QPageLayout::Unit units) const
@@ -182,7 +182,7 @@ void QPageLayoutPrivate::setDefaultMargins(const QMarginsF &minMargins)
qMax(m_fullSize.width() - m_minMargins.left(), qreal(0)),
qMax(m_fullSize.height() - m_minMargins.top(), qreal(0)));
if (m_mode == QPageLayout::StandardMode)
- clampMargins(m_margins);
+ m_margins = clampMargins(m_margins);
}
QSizeF QPageLayoutPrivate::fullSizeUnits(QPageLayout::Unit units) const
@@ -288,6 +288,27 @@ QRectF QPageLayoutPrivate::paintRect() const
\value StandardMode Paint Rect includes margins, margins must fall between the minimum and maximum.
\value FullPageMode Paint Rect excludes margins, margins can be any value and must be managed manually.
+
+ In StandardMode, when setting margins, use \l{QPageLayout::OutOfBoundsPolicy::}{Clamp} to
+ automatically clamp the margins to fall between the minimum and maximum
+ allowed values.
+
+ \sa OutOfBoundsPolicy
+*/
+
+/*!
+ \enum QPageLayout::OutOfBoundsPolicy
+ \since 6.8
+
+ Defines the policy for margins that are out of bounds
+
+ \value Reject The margins must fall within the minimum and maximum values,
+ otherwise they will be rejected.
+ \value Clamp The margins are clamped between the minimum and maximum
+ values to ensure they are valid.
+
+ \note The policy has no effect in \l{QPageLayout::Mode}{FullPageMode},
+ where all margins are accepted.
*/
/*!
@@ -525,39 +546,52 @@ QPageLayout::Unit QPageLayout::units() const
}
/*!
- Sets the page margins of the page layout to \a margins
+ Sets the page margins of the page layout to \a margins.
Returns true if the margins were successfully set.
The units used are those currently defined for the layout. To use different
units then call setUnits() first.
- If in the default StandardMode then all the new margins must fall between the
- minimum margins set and the maximum margins allowed by the page size,
- otherwise the margins will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa margins(), units()
*/
-bool QPageLayout::setMargins(const QMarginsF &margins)
+bool QPageLayout::setMargins(const QMarginsF &margins, OutOfBoundsPolicy outOfBoundsPolicy)
{
if (d->m_mode == FullPageMode) {
- d.detach();
- d->m_margins = margins;
+ if (margins != d->m_margins) {
+ d.detach();
+ d->m_margins = margins;
+ }
return true;
- } else if (margins.left() >= d->m_minMargins.left()
- && margins.right() >= d->m_minMargins.right()
- && margins.top() >= d->m_minMargins.top()
- && margins.bottom() >= d->m_minMargins.bottom()
- && margins.left() <= d->m_maxMargins.left()
- && margins.right() <= d->m_maxMargins.right()
- && margins.top() <= d->m_maxMargins.top()
- && margins.bottom() <= d->m_maxMargins.bottom()) {
- d.detach();
- d->m_margins = margins;
+ }
+
+ if (outOfBoundsPolicy == OutOfBoundsPolicy::Clamp) {
+ const QMarginsF clampedMargins = d->clampMargins(margins);
+ if (clampedMargins != d->m_margins) {
+ d.detach();
+ d->m_margins = clampedMargins;
+ }
return true;
}
+
+ if (margins.left() >= d->m_minMargins.left()
+ && margins.right() >= d->m_minMargins.right()
+ && margins.top() >= d->m_minMargins.top()
+ && margins.bottom() >= d->m_minMargins.bottom()
+ && margins.left() <= d->m_maxMargins.left()
+ && margins.right() <= d->m_maxMargins.right()
+ && margins.top() <= d->m_maxMargins.top()
+ && margins.bottom() <= d->m_maxMargins.bottom()) {
+ if (margins != d->m_margins) {
+ d.detach();
+ d->m_margins = margins;
+ }
+ return true;
+ }
+
return false;
}
@@ -568,23 +602,27 @@ bool QPageLayout::setMargins(const QMarginsF &margins)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setLeftMargin(qreal leftMargin)
+bool QPageLayout::setLeftMargin(qreal leftMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ leftMargin = qBound(d->m_minMargins.left(), leftMargin, d->m_maxMargins.left());
+
+ if (qFuzzyCompare(leftMargin, d->m_margins.left()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (leftMargin >= d->m_minMargins.left() && leftMargin <= d->m_maxMargins.left())) {
d.detach();
d->m_margins.setLeft(leftMargin);
return true;
}
+
return false;
}
@@ -595,23 +633,27 @@ bool QPageLayout::setLeftMargin(qreal leftMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setRightMargin(qreal rightMargin)
+bool QPageLayout::setRightMargin(qreal rightMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ rightMargin = qBound(d->m_minMargins.right(), rightMargin, d->m_maxMargins.right());
+
+ if (qFuzzyCompare(rightMargin, d->m_margins.right()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (rightMargin >= d->m_minMargins.right() && rightMargin <= d->m_maxMargins.right())) {
d.detach();
d->m_margins.setRight(rightMargin);
return true;
}
+
return false;
}
@@ -622,23 +664,27 @@ bool QPageLayout::setRightMargin(qreal rightMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setTopMargin(qreal topMargin)
+bool QPageLayout::setTopMargin(qreal topMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ topMargin = qBound(d->m_minMargins.top(), topMargin, d->m_maxMargins.top());
+
+ if (qFuzzyCompare(topMargin, d->m_margins.top()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (topMargin >= d->m_minMargins.top() && topMargin <= d->m_maxMargins.top())) {
d.detach();
d->m_margins.setTop(topMargin);
return true;
}
+
return false;
}
@@ -649,23 +695,27 @@ bool QPageLayout::setTopMargin(qreal topMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setBottomMargin(qreal bottomMargin)
+bool QPageLayout::setBottomMargin(qreal bottomMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ bottomMargin = qBound(d->m_minMargins.bottom(), bottomMargin, d->m_maxMargins.bottom());
+
+ if (qFuzzyCompare(bottomMargin, d->m_margins.bottom()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (bottomMargin >= d->m_minMargins.bottom() && bottomMargin <= d->m_maxMargins.bottom())) {
d.detach();
d->m_margins.setBottom(bottomMargin);
return true;
}
+
return false;
}
diff --git a/src/gui/painting/qpagelayout.h b/src/gui/painting/qpagelayout.h
index 29be2f9725..1e340b6d75 100644
--- a/src/gui/painting/qpagelayout.h
+++ b/src/gui/painting/qpagelayout.h
@@ -40,6 +40,11 @@ public:
FullPageMode // Paint Rect excludes margins
};
+ enum class OutOfBoundsPolicy {
+ Reject,
+ Clamp
+ };
+
QPageLayout();
QPageLayout(const QPageSize &pageSize, Orientation orientation,
const QMarginsF &margins, Unit units = Point,
@@ -68,11 +73,19 @@ public:
void setUnits(Unit units);
Unit units() const;
+#if QT_GUI_REMOVED_SINCE(6, 8)
bool setMargins(const QMarginsF &margins);
bool setLeftMargin(qreal leftMargin);
bool setRightMargin(qreal rightMargin);
bool setTopMargin(qreal topMargin);
bool setBottomMargin(qreal bottomMargin);
+#endif
+
+ bool setMargins(const QMarginsF &margins, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setLeftMargin(qreal leftMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setRightMargin(qreal rightMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setTopMargin(qreal topMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setBottomMargin(qreal bottomMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
QMarginsF margins() const;
QMarginsF margins(Unit units) const;
diff --git a/src/gui/painting/qpagesize.h b/src/gui/painting/qpagesize.h
index b3629bb8d2..221863aad7 100644
--- a/src/gui/painting/qpagesize.h
+++ b/src/gui/painting/qpagesize.h
@@ -203,7 +203,9 @@ public:
void swap(QPageSize &other) noexcept { d.swap(other.d); }
+#if QT_GUI_REMOVED_SINCE(6, 4)
friend Q_GUI_EXPORT bool operator==(const QPageSize &lhs, const QPageSize &rhs);
+#endif
bool isEquivalentTo(const QPageSize &other) const;
bool isValid() const;
diff --git a/src/gui/platform/ios/qiosnativeinterface.cpp b/src/gui/platform/ios/qiosnativeinterface.cpp
new file mode 100644
index 0000000000..c942709e33
--- /dev/null
+++ b/src/gui/platform/ios/qiosnativeinterface.cpp
@@ -0,0 +1,26 @@
+// 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 <QtGui/private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QNativeInterface::Private;
+
+#if defined(Q_OS_VISIONOS)
+
+/*!
+ \class QNativeInterface::QVisionOSApplication
+ \since 6.8
+ \internal
+ \preliminary
+ \brief Native interface to QGuiApplication, to be retrieved from QPlatformIntegration.
+ \inmodule QtGui
+ \ingroup native-interfaces
+*/
+
+QT_DEFINE_NATIVE_INTERFACE(QVisionOSApplication);
+
+#endif // Q_OS_VISIONOS
+
+QT_END_NAMESPACE
diff --git a/src/gui/platform/unix/qgenericunixthemes.cpp b/src/gui/platform/unix/qgenericunixthemes.cpp
index ce729a74a3..fc4b2296d2 100644
--- a/src/gui/platform/unix/qgenericunixthemes.cpp
+++ b/src/gui/platform/unix/qgenericunixthemes.cpp
@@ -957,7 +957,7 @@ Qt::ColorScheme QKdeTheme::colorScheme() const
/*!
\internal
- \brief QKdeTheme::setColorScheme - guess and set appearance for unix themes.
+ \brief QKdeTheme::updateColorScheme - guess and set appearance for unix themes.
KDE themes do not have an appearance property.
The key words "dark" or "light" should be part of the theme name.
This is, however, not a mandatory convention.
diff --git a/src/gui/platform/windows/qwindowsnativeinterface.cpp b/src/gui/platform/windows/qwindowsnativeinterface.cpp
index 7ebddb5b9d..44f230e1d3 100644
--- a/src/gui/platform/windows/qwindowsnativeinterface.cpp
+++ b/src/gui/platform/windows/qwindowsnativeinterface.cpp
@@ -181,15 +181,7 @@ QT_DEFINE_NATIVE_INTERFACE(QWindowsScreen);
\value DarkModeStyle The Windows Vista style will be turned off and
a simple dark style will be used.
- \sa isDarkMode(), setDarkModeHandling()
-*/
-
-/*!
- \fn bool QNativeInterface::Private::QWindowsApplication::isDarkMode() const = 0
- \internal
-
- Returns \c true if Windows 10 is configured to use dark mode for
- applications.
+ \sa setDarkModeHandling()
*/
/*!
diff --git a/src/gui/qt_cmdline.cmake b/src/gui/qt_cmdline.cmake
index 379cc417e7..446618ebc4 100644
--- a/src/gui/qt_cmdline.cmake
+++ b/src/gui/qt_cmdline.cmake
@@ -27,7 +27,8 @@ qt_commandline_option(opengl TYPE optionalString VALUES no yes desktop es2 dynam
qt_commandline_option(opengl-es-2 TYPE void NAME opengl VALUE es2)
qt_commandline_option(opengles3 TYPE boolean)
qt_commandline_option(openvg TYPE boolean)
-qt_commandline_option(qpa TYPE string NAME qpa_default_platform)
+qt_commandline_option(qpa TYPE string NAME qpa_platforms)
+qt_commandline_option(default-qpa TYPE string NAME qpa_default_platform)
qt_commandline_option(sm TYPE boolean NAME sessionmanager)
qt_commandline_option(tslib TYPE boolean)
qt_commandline_option(vulkan TYPE boolean)
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index 62830c291d..dcaa87a5ff 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -1096,6 +1096,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
caps.glesMultiviewMultisampleRenderToTexture = false;
}
+ caps.unpackRowLength = !caps.gles || caps.ctxMajor >= 3;
+
nativeHandlesStruct.context = ctx;
contextLost = false;
@@ -1426,7 +1428,7 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
case QRhi::PipelineCacheDataLoadSave:
return caps.programBinary;
case QRhi::ImageDataStride:
- return !caps.gles || caps.ctxMajor >= 3;
+ return caps.unpackRowLength;
case QRhi::RenderBufferImport:
return true;
case QRhi::ThreeDimensionalTextures:
@@ -2363,7 +2365,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
dataStride = bytesPerLine;
cmd.args.subImage.rowStartAlign = (dataStride & 3) ? 1 : 4;
- cmd.args.subImage.rowLength = bytesPerPixel ? dataStride / bytesPerPixel : 0;
+ cmd.args.subImage.rowLength = caps.unpackRowLength ? (bytesPerPixel ? dataStride / bytesPerPixel : 0) : 0;
cmd.args.subImage.data = data;
};
@@ -2375,7 +2377,15 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
const QPoint sp = subresDesc.sourceTopLeft();
if (!subresDesc.sourceSize().isEmpty())
size = subresDesc.sourceSize();
- img = img.copy(sp.x(), sp.y(), size.width(), size.height());
+
+ if (caps.unpackRowLength) {
+ cbD->retainImage(img);
+ // create a non-owning wrapper for the subimage
+ const uchar *data = img.constBits() + sp.y() * img.bytesPerLine() + sp.x() * (qMax(1, img.depth() / 8));
+ img = QImage(data, size.width(), size.height(), img.bytesPerLine(), img.format());
+ } else {
+ img = img.copy(sp.x(), sp.y(), size.width(), size.height());
+ }
}
setCmdByNotCompressedData(cbD->retainImage(img), size, img.bytesPerLine());
diff --git a/src/gui/rhi/qrhigles2_p.h b/src/gui/rhi/qrhigles2_p.h
index 4305186c02..4139579864 100644
--- a/src/gui/rhi/qrhigles2_p.h
+++ b/src/gui/rhi/qrhigles2_p.h
@@ -1014,7 +1014,10 @@ public:
halfAttributes(false),
multiView(false),
timestamps(false),
- objectLabel(false)
+ objectLabel(false),
+ glesMultisampleRenderToTexture(false),
+ glesMultiviewMultisampleRenderToTexture(false),
+ unpackRowLength(false)
{ }
int ctxMajor;
int ctxMinor;
@@ -1073,6 +1076,7 @@ public:
uint objectLabel : 1;
uint glesMultisampleRenderToTexture : 1;
uint glesMultiviewMultisampleRenderToTexture : 1;
+ uint unpackRowLength : 1;
} caps;
QGles2SwapChain *currentSwapChain = nullptr;
QSet<GLint> supportedCompressedFormats;
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 1c7b397193..9fadfc15fa 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -2402,6 +2402,16 @@ QRhi::FrameOpResult QRhiMetal::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
dispatch_semaphore_signal(swapChainD->d->sem[thisFrameSlot]);
}];
+#ifdef QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
+ // When Metal API validation diagnostics is enabled in Xcode the texture is
+ // released before the command buffer is done with it. Manually keep it alive
+ // to work around this.
+ id<MTLTexture> drawableTexture = [swapChainD->d->curDrawable.texture retain];
+ [swapChainD->cbWrapper.d->cb addCompletedHandler:^(id<MTLCommandBuffer>) {
+ [drawableTexture release];
+ }];
+#endif
+
const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
const bool presentsWithTransaction = swapChainD->d->layer.presentsWithTransaction;
if (!presentsWithTransaction && needsPresent) {
@@ -2579,7 +2589,6 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
int w = img.width();
int h = img.height();
int bpl = img.bytesPerLine();
- int srcOffset = 0;
if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
const int sx = subresDesc.sourceTopLeft().x();
@@ -2588,10 +2597,12 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
w = subresDesc.sourceSize().width();
h = subresDesc.sourceSize().height();
}
- if (img.depth() == 32) {
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(fullImageSizeBytes));
- srcOffset = sy * bpl + sx * 4;
- // bpl remains set to the original image's row stride
+ if (w == img.width()) {
+ const int bpc = qMax(1, img.depth() / 8);
+ Q_ASSERT(h * img.bytesPerLine() <= fullImageSizeBytes);
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs,
+ img.constBits() + sy * img.bytesPerLine() + sx * bpc,
+ h * img.bytesPerLine());
} else {
img = img.copy(sx, sy, w, h);
bpl = img.bytesPerLine();
@@ -2603,7 +2614,7 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
}
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: NSUInteger(*curOfs + srcOffset)
+ sourceOffset: NSUInteger(*curOfs)
sourceBytesPerRow: NSUInteger(bpl)
sourceBytesPerImage: 0
sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
@@ -2971,9 +2982,11 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
cbD->d->currentPassRpDesc.depthAttachment.loadAction = MTLLoadActionLoad;
cbD->d->currentPassRpDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
}
+ int colorAttCount = 0;
for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
it != itEnd; ++it)
{
+ colorAttCount += 1;
if (it->texture()) {
QRHI_RES(QMetalTexture, it->texture())->lastActiveFrameSlot = currentFrameSlot;
if (it->multiViewCount() >= 2)
@@ -2986,8 +2999,12 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
}
if (rtTex->m_desc.depthStencilBuffer())
QRHI_RES(QMetalRenderBuffer, rtTex->m_desc.depthStencilBuffer())->lastActiveFrameSlot = currentFrameSlot;
- if (rtTex->m_desc.depthTexture())
- QRHI_RES(QMetalTexture, rtTex->m_desc.depthTexture())->lastActiveFrameSlot = currentFrameSlot;
+ if (rtTex->m_desc.depthTexture()) {
+ QMetalTexture *depthTexture = QRHI_RES(QMetalTexture, rtTex->m_desc.depthTexture());
+ depthTexture->lastActiveFrameSlot = currentFrameSlot;
+ if (colorAttCount == 0 && depthTexture->arraySize() >= 2)
+ cbD->d->currentPassRpDesc.renderTargetArrayLength = NSUInteger(depthTexture->arraySize());
+ }
if (rtTex->m_desc.depthResolveTexture())
QRHI_RES(QMetalTexture, rtTex->m_desc.depthResolveTexture())->lastActiveFrameSlot = currentFrameSlot;
}
@@ -4840,7 +4857,7 @@ void QMetalGraphicsPipeline::setupAttachmentsInMetalRenderPassDescriptor(void *m
}
QRHI_RES_RHI(QRhiMetal);
- rpDesc.sampleCount = NSUInteger(rhiD->effectiveSampleCount(m_sampleCount));
+ rpDesc.rasterSampleCount = NSUInteger(rhiD->effectiveSampleCount(m_sampleCount));
}
void QMetalGraphicsPipeline::setupMetalDepthStencilDescriptor(void *metalDsDesc)
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index f0b51146cc..3dd3c57bd4 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -1598,8 +1598,8 @@ struct RenderPass2SetupHelper
#endif // VK_KHR_create_renderpass2
bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
- const QRhiColorAttachment *firstColorAttachment,
- const QRhiColorAttachment *lastColorAttachment,
+ const QRhiColorAttachment *colorAttachmentsBegin,
+ const QRhiColorAttachment *colorAttachmentsEnd,
bool preserveColor,
bool preserveDs,
bool storeDs,
@@ -1610,7 +1610,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
// attachment list layout is color (0-8), ds (0-1), resolve (0-8), ds resolve (0-1)
int multiViewCount = 0;
- for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
+ for (auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
QVkTexture *texD = QRHI_RES(QVkTexture, it->texture());
QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer());
Q_ASSERT(texD || rbD);
@@ -1662,10 +1662,14 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
rpD->attDescs.append(attDesc);
+ if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
+ multiViewCount = depthTexture->arraySize();
+ rpD->multiViewCount = multiViewCount;
+ }
}
rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
- for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
+ for (auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
if (it->resolveTexture()) {
QVkTexture *rtexD = QRHI_RES(QVkTexture, it->resolveTexture());
const VkFormat dstFormat = rtexD->vkformat;
@@ -3497,12 +3501,12 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
const int sy = subresDesc.sourceTopLeft().y();
if (!subresDesc.sourceSize().isEmpty())
size = subresDesc.sourceSize();
- if (image.depth() == 32) {
- // The staging buffer will get the full image
- // regardless, just adjust the vk
- // buffer-to-image copy start offset.
- copyInfo.bufferOffset += VkDeviceSize(sy * image.bytesPerLine() + sx * 4);
- // bufferRowLength remains set to the original image's width
+
+ if (size.width() == image.width()) {
+ // No need to make a QImage copy here, can copy from the source
+ // QImage into staging directly.
+ src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
+ copySizeBytes = size.height() * image.bytesPerLine();
} else {
image = image.copy(sx, sy, size.width(), size.height());
src = image.constBits();
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index ad8687de5d..f23d8550f0 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -773,8 +773,8 @@ public:
VkSampleCountFlagBits samples,
VkFormat colorFormat);
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
- const QRhiColorAttachment *firstColorAttachment,
- const QRhiColorAttachment *lastColorAttachment,
+ const QRhiColorAttachment *colorAttachmentsBegin,
+ const QRhiColorAttachment *colorAttachmentsEnd,
bool preserveColor,
bool preserveDs,
bool storeDs,
diff --git a/src/gui/text/coretext/qfontengine_coretext.mm b/src/gui/text/coretext/qfontengine_coretext.mm
index b6fef2fecb..1050c03d75 100644
--- a/src/gui/text/coretext/qfontengine_coretext.mm
+++ b/src/gui/text/coretext/qfontengine_coretext.mm
@@ -13,6 +13,7 @@
#include <private/qcoregraphics_p.h>
#include <private/qimage_p.h>
#include <private/qguiapplication_p.h>
+#include <private/qstringiterator_p.h>
#include <qpa/qplatformtheme.h>
#include <cmath>
@@ -274,29 +275,30 @@ glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const
return glyphIndices[0];
}
-bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
- int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
QVarLengthArray<CGGlyph> cgGlyphs(len);
CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
int glyph_pos = 0;
- for (int i = 0; i < len; ++i) {
- glyphs->glyphs[glyph_pos] = cgGlyphs[i];
- if (glyph_pos < i)
- cgGlyphs[glyph_pos] = cgGlyphs[i];
- glyph_pos++;
-
- // If it's a non-BMP char, skip the lower part of surrogate pair and go
- // directly to the next char without increasing glyph_pos
- if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate())
- ++i;
+ int mappedGlyphs = 0;
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ qsizetype idx = it.index();
+ char32_t ucs4 = it.next();
+ glyphs->glyphs[glyph_pos] = cgGlyphs[idx];
+ if (glyph_pos < idx)
+ cgGlyphs[glyph_pos] = cgGlyphs[idx];
+ if (glyphs->glyphs[glyph_pos] != 0 || isIgnorableChar(ucs4))
+ mappedGlyphs++;
+ glyph_pos++;
}
*nglyphs = glyph_pos;
@@ -305,7 +307,7 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *
if (!(flags & GlyphIndicesOnly))
loadAdvancesForGlyphs(cgGlyphs, glyphs);
- return true;
+ return mappedGlyphs;
}
glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
diff --git a/src/gui/text/coretext/qfontengine_coretext_p.h b/src/gui/text/coretext/qfontengine_coretext_p.h
index af87f5f6f3..2f388c32bc 100644
--- a/src/gui/text/coretext/qfontengine_coretext_p.h
+++ b/src/gui/text/coretext/qfontengine_coretext_p.h
@@ -38,7 +38,7 @@ public:
~QCoreTextFontEngine();
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
glyph_metrics_t boundingBox(glyph_t glyph) override;
diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp
index 72d2c72fe3..d3791f1f6e 100644
--- a/src/gui/text/freetype/qfontengine_ft.cpp
+++ b/src/gui/text/freetype/qfontengine_ft.cpp
@@ -1678,15 +1678,16 @@ glyph_t QFontEngineFT::glyphIndex(uint ucs4) const
return glyph;
}
-bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
+int QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
+ int mappedGlyphs = 0;
int glyph_pos = 0;
if (freetype->symbol_map) {
FT_Face face = freetype->face;
@@ -1719,6 +1720,8 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
if (uc < QFreetypeFace::cmapCacheSize)
freetype->cmapCache[uc] = glyph;
}
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ mappedGlyphs++;
++glyph_pos;
}
} else {
@@ -1740,6 +1743,8 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
freetype->cmapCache[uc] = glyph;
}
}
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ mappedGlyphs++;
++glyph_pos;
}
}
@@ -1750,7 +1755,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return mappedGlyphs;
}
bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const
diff --git a/src/gui/text/freetype/qfontengine_ft_p.h b/src/gui/text/freetype/qfontengine_ft_p.h
index c8e5e20d37..bdd4549827 100644
--- a/src/gui/text/freetype/qfontengine_ft_p.h
+++ b/src/gui/text/freetype/qfontengine_ft_p.h
@@ -186,7 +186,7 @@ private:
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
QPainterPath *path, QTextItem::RenderFlags flags) override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
glyph_metrics_t boundingBox(glyph_t glyph) override;
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index e5815ffce2..7886d9ba91 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -12,6 +12,7 @@
#include <qfontmetrics.h>
#include <qbrush.h>
#include <qimagereader.h>
+#include <qtextformat.h>
#include <algorithm>
@@ -35,6 +36,7 @@ struct QCssKnownValue
quint64 id;
};
+// This array is sorted alphabetically.
static const QCssKnownValue properties[NumProperties - 1] = {
{ "-qt-background-role", QtBackgroundRole },
{ "-qt-block-indent", QtBlockIndent },
@@ -46,6 +48,11 @@ static const QCssKnownValue properties[NumProperties - 1] = {
{ "-qt-list-number-suffix", QtListNumberSuffix },
{ "-qt-paragraph-type", QtParagraphType },
{ "-qt-stroke-color", QtStrokeColor },
+ { "-qt-stroke-dasharray", QtStrokeDashArray },
+ { "-qt-stroke-dashoffset", QtStrokeDashOffset },
+ { "-qt-stroke-linecap", QtStrokeLineCap },
+ { "-qt-stroke-linejoin", QtStrokeLineJoin },
+ { "-qt-stroke-miterlimit", QtStrokeMiterLimit },
{ "-qt-stroke-width", QtStrokeWidth },
{ "-qt-style-features", QtStyleFeatures },
{ "-qt-table-type", QtTableType },
@@ -159,6 +166,7 @@ static const QCssKnownValue values[NumKnownValues - 1] = {
{ "always", Value_Always },
{ "auto", Value_Auto },
{ "base", Value_Base },
+ { "beveljoin", Value_BevelJoin},
{ "bold", Value_Bold },
{ "bottom", Value_Bottom },
{ "bright-text", Value_BrightText },
@@ -175,6 +183,7 @@ static const QCssKnownValue values[NumKnownValues - 1] = {
{ "dot-dot-dash", Value_DotDotDash },
{ "dotted", Value_Dotted },
{ "double", Value_Double },
+ { "flatcap", Value_FlatCap},
{ "groove", Value_Groove },
{ "highlight", Value_Highlight },
{ "highlighted-text", Value_HighlightedText },
@@ -193,6 +202,7 @@ static const QCssKnownValue values[NumKnownValues - 1] = {
{ "mid", Value_Mid },
{ "middle", Value_Middle },
{ "midlight", Value_Midlight },
+ { "miterjoin", Value_MiterJoin},
{ "native", Value_Native },
{ "none", Value_None },
{ "normal", Value_Normal },
@@ -207,14 +217,18 @@ static const QCssKnownValue values[NumKnownValues - 1] = {
{ "pre-wrap", Value_PreWrap },
{ "ridge", Value_Ridge },
{ "right", Value_Right },
+ { "roundcap", Value_RoundCap},
+ { "roundjoin", Value_RoundJoin},
{ "selected", Value_Selected },
{ "shadow", Value_Shadow },
{ "small" , Value_Small },
{ "small-caps", Value_SmallCaps },
{ "solid", Value_Solid },
{ "square", Value_Square },
+ { "squarecap", Value_SquareCap},
{ "sub", Value_Sub },
{ "super", Value_Super },
+ { "svgmiterjoin", Value_SvgMiterJoin},
{ "text", Value_Text },
{ "top", Value_Top },
{ "transparent", Value_Transparent },
@@ -230,10 +244,10 @@ static const QCssKnownValue values[NumKnownValues - 1] = {
};
//Map id to strings as they appears in the 'values' array above
-static const short indexOfId[NumKnownValues] = { 0, 41, 48, 42, 49, 50, 55, 35, 26, 71, 72, 25, 43, 5, 64, 48,
- 29, 59, 60, 27, 52, 62, 6, 10, 39, 56, 19, 13, 17, 18, 20, 21, 51, 24, 46, 68, 37, 3, 2, 40, 63, 16,
- 11, 58, 14, 32, 65, 33, 66, 56, 67, 34, 70, 8, 28, 38, 12, 36, 61, 7, 9, 4, 69, 54, 22, 23, 30, 31,
- 1, 15, 0, 53, 45, 44 };
+static const short indexOfId[NumKnownValues] = { 0, 44, 51, 45, 52, 53, 60, 37, 28, 78, 79, 27, 46, 6, 71, 50,
+ 31, 65, 66, 29, 55, 69, 7, 11, 42, 62, 20, 14, 18, 19, 21, 23, 54, 26, 49, 75, 39, 3, 2, 43, 70, 17, 12,
+ 63, 15, 34, 72, 35, 73, 61, 74, 36, 64, 22, 56, 41, 5, 57, 67, 77, 9, 30, 40, 13, 38, 68, 8, 10, 4, 76,
+ 59, 24, 25, 32, 33, 1, 16, 0, 58, 48, 47 };
QString Value::toString() const
{
@@ -396,6 +410,8 @@ LengthData ValueExtractor::lengthValue(const Value& v)
if (data.unit != LengthData::None)
s.chop(2);
+ else if (v.type == Value::Percentage)
+ data.unit = LengthData::Percent;
data.number = s.toDouble();
return data;
@@ -409,6 +425,15 @@ static int lengthValueFromData(const LengthData& data, const QFont& f)
return qRound(qBound(double(INT_MIN) + 0.1, scale * data.number, double(INT_MAX)));
}
+QTextLength ValueExtractor::textLength(const Declaration &decl)
+{
+ const LengthData data = lengthValue(decl.d->values.at(0));
+ if (data.unit == LengthData::Percent)
+ return QTextLength(QTextLength::PercentageLength, data.number);
+
+ return QTextLength(QTextLength::FixedLength, lengthValueFromData(data, f));
+}
+
int ValueExtractor::lengthValue(const Declaration &decl)
{
if (decl.d->parsed.isValid())
@@ -1823,6 +1848,35 @@ bool Declaration::borderCollapseValue() const
return d->values.at(0).toString() == "collapse"_L1;
}
+QList<qreal> Declaration::dashArray() const
+{
+ if (d->propertyId != Property::QtStrokeDashArray || d->values.empty())
+ return QList<qreal>();
+
+ bool isValid = true;
+ QList<qreal> dashes;
+ for (int i = 0; i < d->values.size(); i++) {
+ Value v = d->values[i];
+ // Separators must be at odd indices and Numbers at even indices.
+ bool isValidSeparator = (i & 1) && v.type == Value::TermOperatorComma;
+ bool isValidNumber = !(i & 1) && v.type == Value::Number;
+ if (!isValidNumber && !isValidSeparator) {
+ isValid = false;
+ break;
+ } else if (isValidNumber) {
+ bool ok;
+ dashes.append(v.variant.toReal(&ok));
+ if (!ok) {
+ isValid = false;
+ break;
+ }
+ }
+ }
+
+ isValid &= !(dashes.size() & 1);
+ return isValid ? dashes : QList<qreal>();
+}
+
QIcon Declaration::iconValue() const
{
if (d->parsed.isValid())
diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h
index c1cfb1ac9b..ba4a611df3 100644
--- a/src/gui/text/qcssparser_p.h
+++ b/src/gui/text/qcssparser_p.h
@@ -169,6 +169,11 @@ enum Property {
QtAccent,
QtStrokeWidth,
QtStrokeColor,
+ QtStrokeLineCap,
+ QtStrokeLineJoin,
+ QtStrokeMiterLimit,
+ QtStrokeDashArray,
+ QtStrokeDashOffset,
QtForeground,
NumProperties
};
@@ -226,6 +231,13 @@ enum KnownValue {
Value_SmallCaps,
Value_Uppercase,
Value_Lowercase,
+ Value_SquareCap,
+ Value_FlatCap,
+ Value_RoundCap,
+ Value_MiterJoin,
+ Value_BevelJoin,
+ Value_RoundJoin,
+ Value_SvgMiterJoin,
/* keep these in same order as QPalette::ColorRole */
Value_FirstColorRole,
@@ -392,7 +404,7 @@ QT_CSS_DECLARE_TYPEINFO(BackgroundData, Q_RELOCATABLE_TYPE)
struct LengthData {
qreal number;
- enum { None, Px, Ex, Em } unit;
+ enum { None, Px, Ex, Em, Percent } unit;
};
QT_CSS_DECLARE_TYPEINFO(LengthData, Q_PRIMITIVE_TYPE)
@@ -451,6 +463,8 @@ struct Q_GUI_EXPORT Declaration
void borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const;
bool borderCollapseValue() const;
+
+ QList<qreal> dashArray() const;
};
QT_CSS_DECLARE_TYPEINFO(Declaration, Q_RELOCATABLE_TYPE)
@@ -835,6 +849,7 @@ struct Q_GUI_EXPORT ValueExtractor
bool extractIcon(QIcon *icon, QSize *size);
void lengthValues(const Declaration &decl, int *m);
+ QTextLength textLength(const Declaration &decl);
private:
void extractFont();
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 7fd590c355..f3a35a4269 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -1462,6 +1462,14 @@ QFont::StyleHint QFont::styleHint() const
\value NoAntialias don't antialias the fonts.
\value NoSubpixelAntialias avoid subpixel antialiasing on the fonts if possible.
\value PreferAntialias antialias if possible.
+ \value [since 6.8] ContextFontMerging If the selected font does not contain a certain character,
+ then Qt automatically chooses a similar-looking fallback font that contains the
+ character. By default this is done on a character-by-character basis. This means that in
+ certain uncommon cases, multiple fonts may be used to represent one string of text even
+ if it's in the same script. Setting \c ContextFontMerging will try finding the fallback
+ font that matches the largest subset of the input string instead. This will be more
+ expensive for strings where missing glyphs occur, but may give more consistent results.
+ If \c NoFontMerging is set, then \c ContextFontMerging will have no effect.
\value NoFontMerging If the font selected for a certain writing system
does not contain a character requested to draw, then Qt automatically chooses a similar
looking font that contains the character. The NoFontMerging flag disables this feature.
@@ -2427,9 +2435,7 @@ std::optional<QFont::Tag> QFont::Tag::fromString(QAnyStringView view) noexcept
By default, no variable axes are set.
- \note In order to use variable axes on Windows, the application has to run with either the
- FreeType or DirectWrite font databases. See the documentation for
- QGuiApplication::QGuiApplication() for more information on how to select these technologies.
+ \note On Windows, variable axes are not supported if the optional GDI font backend is in use.
\sa unsetVariableAxis
*/
@@ -3266,7 +3272,7 @@ bool QFontInfo::fixedPitch() const
QChar ch[2] = { u'i', u'm' };
QGlyphLayoutArray<2> g;
int l = 2;
- if (!engine->stringToCMap(ch, 2, &g, &l, {}))
+ if (engine->stringToCMap(ch, 2, &g, &l, {}) < 0)
Q_UNREACHABLE();
Q_ASSERT(l == 2);
engine->fontDef.fixedPitch = g.advances[0] == g.advances[1];
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index ace07780b5..66a5f7c155 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -47,6 +47,7 @@ public:
NoAntialias = 0x0100,
NoSubpixelAntialias = 0x0800,
PreferNoShaping = 0x1000,
+ ContextFontMerging = 0x2000,
NoFontMerging = 0x8000
};
Q_ENUM(StyleStrategy)
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index dff400c18b..4e78aaac2e 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -13,6 +13,7 @@
#include "qpainter.h"
#include "qpainterpath.h"
#include "qvarlengtharray.h"
+#include "qtextengine_p.h"
#include <qmath.h>
#include <qendian.h>
#include <private/qstringiterator_p.h>
@@ -1542,12 +1543,12 @@ glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
return 1;
}
-bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
int ucs4Length = 0;
@@ -1563,7 +1564,7 @@ bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return *nglyphs;
}
void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
@@ -1793,11 +1794,7 @@ QFontEngine *QFontEngineMulti::loadEngine(int at)
glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
{
glyph_t glyph = engine(0)->glyphIndex(ucs4);
- if (glyph == 0
- && ucs4 != QChar::LineSeparator
- && ucs4 != QChar::LineFeed
- && ucs4 != QChar::CarriageReturn
- && ucs4 != QChar::ParagraphSeparator) {
+ if (glyph == 0 && !isIgnorableChar(ucs4)) {
if (!m_fallbackFamiliesQueried)
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
@@ -1824,13 +1821,55 @@ glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
return glyph;
}
-bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
- QGlyphLayout *glyphs, int *nglyphs,
- QFontEngine::ShaperFlags flags) const
+int QFontEngineMulti::stringToCMap(const QChar *str, int len,
+ QGlyphLayout *glyphs, int *nglyphs,
+ QFontEngine::ShaperFlags flags) const
{
- if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags))
- return false;
+ const int originalNumGlyphs = glyphs->numGlyphs;
+ int mappedGlyphCount = engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags);
+ if (mappedGlyphCount < 0)
+ return -1;
+
+ // If ContextFontMerging is set and the match for the string was incomplete, we try all
+ // fallbacks on the full string until we find the best match.
+ bool contextFontMerging = mappedGlyphCount < *nglyphs && (fontDef.styleStrategy & QFont::ContextFontMerging);
+ if (contextFontMerging) {
+ QVarLengthGlyphLayoutArray tempLayout(len);
+ if (!m_fallbackFamiliesQueried)
+ const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
+ int maxGlyphCount = 0;
+ uchar engineIndex = 0;
+ for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
+ int numGlyphs = len;
+ const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
+ maxGlyphCount = engine(x)->stringToCMap(str, len, &tempLayout, &numGlyphs, flags);
+
+ // If we found a better match, we copy data into the main QGlyphLayout
+ if (maxGlyphCount > mappedGlyphCount) {
+ *nglyphs = numGlyphs;
+ glyphs->numGlyphs = originalNumGlyphs;
+ glyphs->copy(&tempLayout);
+ engineIndex = x;
+ if (maxGlyphCount == numGlyphs)
+ break;
+ }
+ }
+
+ if (engineIndex > 0) {
+ for (int y = 0; y < glyphs->numGlyphs; ++y) {
+ if (glyphs->glyphs[y] != 0)
+ glyphs->glyphs[y] |= (engineIndex << 24);
+ }
+ } else {
+ contextFontMerging = false;
+ }
+
+ mappedGlyphCount = maxGlyphCount;
+ }
+
+ // Fill in missing glyphs by going through string one character at the time and finding
+ // the first viable fallback.
int glyph_pos = 0;
QStringIterator it(str, str + len);
@@ -1861,15 +1900,10 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
lastFallback = -1;
}
- if (glyphs->glyphs[glyph_pos] == 0
- && ucs4 != QChar::LineSeparator
- && ucs4 != QChar::LineFeed
- && ucs4 != QChar::CarriageReturn
- && ucs4 != QChar::ParagraphSeparator
- && QChar::category(ucs4) != QChar::Other_Control) {
+ if (glyphs->glyphs[glyph_pos] == 0 && !isIgnorableChar(ucs4)) {
if (!m_fallbackFamiliesQueried)
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
- for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
+ for (int x = contextFontMerging ? 0 : 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
QFontEngine *engine = m_engines.at(x);
if (!engine) {
if (!shouldLoadFontEngineForCharacter(x, ucs4))
@@ -1946,8 +1980,7 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
*nglyphs = glyph_pos;
glyphs->numGlyphs = glyph_pos;
-
- return true;
+ return mappedGlyphCount;
}
bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
@@ -2239,7 +2272,7 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) const
QGlyphLayout g;
g.numGlyphs = nglyphs;
g.glyphs = glyphs.data();
- if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
+ if (stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly) < 0)
Q_UNREACHABLE();
for (int i = 0; i < nglyphs; i++) {
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index af44eeab3f..a0e0801354 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -76,7 +76,8 @@ public:
enum ShaperFlag {
DesignMetrics = 0x0002,
- GlyphIndicesOnly = 0x0004
+ GlyphIndicesOnly = 0x0004,
+ FullStringFallback = 0x008
};
Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
@@ -148,12 +149,20 @@ public:
}
bool isColorFont() const { return glyphFormat == Format_ARGB; }
+ static bool isIgnorableChar(char32_t ucs4)
+ {
+ return ucs4 == QChar::LineSeparator
+ || ucs4 == QChar::LineFeed
+ || ucs4 == QChar::CarriageReturn
+ || ucs4 == QChar::ParagraphSeparator
+ || QChar::category(ucs4) == QChar::Other_Control;
+ }
virtual QFixed emSquareSize() const { return ascent(); }
/* returns 0 as glyph index for non existent glyphs */
virtual glyph_t glyphIndex(uint ucs4) const = 0;
- virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0;
+ virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const {}
virtual void doKerning(QGlyphLayout *, ShaperFlags) const;
@@ -393,7 +402,7 @@ public:
~QFontEngineBox();
virtual glyph_t glyphIndex(uint ucs4) const override;
- virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si);
@@ -431,7 +440,7 @@ public:
~QFontEngineMulti();
virtual glyph_t glyphIndex(uint ucs4) const override;
- virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
virtual glyph_metrics_t boundingBox(glyph_t glyph) override;
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index c5a92f95cb..54676b3560 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -498,7 +498,7 @@ QList<quint32> QRawFont::glyphIndexesForString(const QString &text) const
QGlyphLayout glyphs;
glyphs.numGlyphs = numGlyphs;
glyphs.glyphs = glyphIndexes.data();
- if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly))
+ if (d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly) < 0)
Q_UNREACHABLE();
glyphIndexes.resize(numGlyphs);
@@ -531,7 +531,7 @@ bool QRawFont::glyphIndexesForChars(const QChar *chars, int numChars, quint32 *g
QGlyphLayout glyphs;
glyphs.numGlyphs = *numGlyphs;
glyphs.glyphs = glyphIndexes;
- return d->fontEngine->stringToCMap(chars, numChars, &glyphs, numGlyphs, QFontEngine::GlyphIndicesOnly);
+ return d->fontEngine->stringToCMap(chars, numChars, &glyphs, numGlyphs, QFontEngine::GlyphIndicesOnly) >= 0;
}
/*!
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 15a313e13d..31cb3a526a 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -2757,6 +2757,51 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
html += " -qt-stroke-width:"_L1;
html += QString::number(outlinePen.widthF());
html += "px;"_L1;
+
+ html += " -qt-stroke-linecap:"_L1;
+ if (outlinePen.capStyle() == Qt::SquareCap)
+ html += "squarecap;"_L1;
+ else if (outlinePen.capStyle() == Qt::FlatCap)
+ html += "flatcap;"_L1;
+ else if (outlinePen.capStyle() == Qt::RoundCap)
+ html += "roundcap;"_L1;
+
+ html += " -qt-stroke-linejoin:"_L1;
+ if (outlinePen.joinStyle() == Qt::MiterJoin)
+ html += "miterjoin;"_L1;
+ else if (outlinePen.joinStyle() == Qt::SvgMiterJoin)
+ html += "svgmiterjoin;"_L1;
+ else if (outlinePen.joinStyle() == Qt::BevelJoin)
+ html += "beveljoin;"_L1;
+ else if (outlinePen.joinStyle() == Qt::RoundJoin)
+ html += "roundjoin;"_L1;
+
+ if (outlinePen.joinStyle() == Qt::MiterJoin ||
+ outlinePen.joinStyle() == Qt::SvgMiterJoin) {
+ html += " -qt-stroke-miterlimit:"_L1;
+ html += QString::number(outlinePen.miterLimit());
+ html += u';';
+ }
+
+ if (outlinePen.style() == Qt::CustomDashLine && !outlinePen.dashPattern().empty()) {
+ html += " -qt-stroke-dasharray:"_L1;
+ QString dashArrayString;
+ QList<qreal> dashes = outlinePen.dashPattern();
+
+ for (int i = 0; i < dashes.length() - 1; i++) {
+ qreal dash = dashes[i];
+ dashArrayString += QString::number(dash) + u',';
+ }
+
+ dashArrayString += QString::number(dashes.last());
+ html += dashArrayString;
+ html += u';';
+
+ html += " -qt-stroke-dashoffset:"_L1;
+ html += QString::number(outlinePen.dashOffset());
+ html += u';';
+ }
+
attributesEmitted = true;
}
@@ -2944,6 +2989,17 @@ void QTextHtmlExporter::emitFragment(const QTextFragment &fragment)
html += "<img"_L1;
+ QString maxWidthCss;
+
+ if (imgFmt.hasProperty(QTextFormat::ImageMaxWidth)) {
+ auto length = imgFmt.lengthProperty(QTextFormat::ImageMaxWidth);
+ maxWidthCss += "max-width:"_L1;
+ if (length.type() == QTextLength::PercentageLength)
+ maxWidthCss += QString::number(length.rawValue()) + "%;"_L1;
+ else if (length.type() == QTextLength::FixedLength)
+ maxWidthCss += QString::number(length.rawValue()) + "px;"_L1;
+ }
+
if (imgFmt.hasProperty(QTextFormat::ImageName))
emitAttribute("src", imgFmt.name());
@@ -2960,9 +3016,11 @@ void QTextHtmlExporter::emitFragment(const QTextFragment &fragment)
emitAttribute("height", QString::number(imgFmt.height()));
if (imgFmt.verticalAlignment() == QTextCharFormat::AlignMiddle)
- html += " style=\"vertical-align: middle;\""_L1;
+ html += " style=\"vertical-align: middle;"_L1 + maxWidthCss + u'\"';
else if (imgFmt.verticalAlignment() == QTextCharFormat::AlignTop)
- html += " style=\"vertical-align: top;\""_L1;
+ html += " style=\"vertical-align: top;"_L1 + maxWidthCss + u'\"';
+ else if (!maxWidthCss.isEmpty())
+ html += " style=\""_L1 + maxWidthCss + u'\"';
if (QTextFrame *imageFrame = qobject_cast<QTextFrame *>(doc->objectForFormat(imgFmt)))
emitFloatStyle(imageFrame->frameFormat().position());
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index cb945b73ce..08512bead5 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1396,7 +1396,9 @@ void QTextEngine::shapeText(int item) const
QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading);
+#if QT_CONFIG(harfbuzz)
bool kerningEnabled;
+#endif
bool letterSpacingIsAbsolute;
bool shapingEnabled = false;
QHash<QFont::Tag, quint32> features;
@@ -1405,8 +1407,8 @@ void QTextEngine::shapeText(int item) const
if (useRawFont) {
QTextCharFormat f = format(&si);
QFont font = f.font();
- kerningEnabled = font.kerning();
# if QT_CONFIG(harfbuzz)
+ kerningEnabled = font.kerning();
shapingEnabled = QFontEngine::scriptRequiresOpenType(QChar::Script(si.analysis.script))
|| (font.styleStrategy() & QFont::PreferNoShaping) == 0;
# endif
@@ -1418,8 +1420,8 @@ void QTextEngine::shapeText(int item) const
#endif
{
QFont font = this->font(si);
- kerningEnabled = font.d->kerning;
#if QT_CONFIG(harfbuzz)
+ kerningEnabled = font.d->kerning;
shapingEnabled = QFontEngine::scriptRequiresOpenType(QChar::Script(si.analysis.script))
|| (font.d->request.styleStrategy & QFont::PreferNoShaping) == 0;
#endif
@@ -1445,7 +1447,7 @@ void QTextEngine::shapeText(int item) const
shapingEnabled
? QFontEngine::GlyphIndicesOnly
: QFontEngine::ShaperFlag(0);
- if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags))
+ if (fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags) < 0)
Q_UNREACHABLE();
}
@@ -2741,6 +2743,21 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
return true;
}
+void QGlyphLayout::copy(QGlyphLayout *oldLayout)
+{
+ Q_ASSERT(offsets != oldLayout->offsets);
+
+ int n = std::min(numGlyphs, oldLayout->numGlyphs);
+
+ memcpy(offsets, oldLayout->offsets, n * sizeof(QFixedPoint));
+ memcpy(attributes, oldLayout->attributes, n * sizeof(QGlyphAttributes));
+ memcpy(justifications, oldLayout->justifications, n * sizeof(QGlyphJustification));
+ memcpy(advances, oldLayout->advances, n * sizeof(QFixed));
+ memcpy(glyphs, oldLayout->glyphs, n * sizeof(glyph_t));
+
+ numGlyphs = n;
+}
+
// grow to the new size, copying the existing data to the new layout
void QGlyphLayout::grow(char *address, int totalGlyphs)
{
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index a829265a22..c01d3a0711 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -224,6 +224,7 @@ struct QGlyphLayout
return reinterpret_cast<char *>(offsets);
}
+ void copy(QGlyphLayout *other);
void grow(char *address, int totalGlyphs);
};
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 509b2eb7cc..dacef70812 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -405,26 +405,26 @@ Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QTextFormat &fmt
{
QMap<int, QVariant> properties = fmt.properties();
if (stream.version() < QDataStream::Qt_6_0) {
- auto it = properties.find(QTextFormat::FontLetterSpacingType);
- if (it != properties.end()) {
+ auto it = properties.constFind(QTextFormat::FontLetterSpacingType);
+ if (it != properties.cend()) {
properties[QTextFormat::OldFontLetterSpacingType] = it.value();
properties.erase(it);
}
- it = properties.find(QTextFormat::FontStretch);
- if (it != properties.end()) {
+ it = properties.constFind(QTextFormat::FontStretch);
+ if (it != properties.cend()) {
properties[QTextFormat::OldFontStretch] = it.value();
properties.erase(it);
}
- it = properties.find(QTextFormat::TextUnderlineColor);
- if (it != properties.end()) {
+ it = properties.constFind(QTextFormat::TextUnderlineColor);
+ if (it != properties.cend()) {
properties[QTextFormat::OldTextUnderlineColor] = it.value();
properties.erase(it);
}
- it = properties.find(QTextFormat::FontFamilies);
- if (it != properties.end()) {
+ it = properties.constFind(QTextFormat::FontFamilies);
+ if (it != properties.cend()) {
properties[QTextFormat::OldFontFamily] = QVariant(it.value().toStringList().constFirst());
properties.erase(it);
}
@@ -745,6 +745,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextTableCellFormat &
\value ImageWidth
\value ImageHeight
\value ImageQuality
+ \value ImageMaxWidth This enum value has been added in Qt 6.8.
Selection properties
@@ -3156,7 +3157,8 @@ QTextTableFormat::QTextTableFormat()
: QTextFrameFormat()
{
setObjectType(TableObject);
- setCellSpacing(2);
+ setCellPadding(4);
+ setBorderCollapse(true);
setBorder(1);
}
@@ -3425,7 +3427,7 @@ QTextImageFormat::QTextImageFormat(const QTextFormat &fmt)
Sets the \a width of the rectangle occupied by the image.
- \sa width(), setHeight()
+ \sa width(), setHeight(), maximumWidth()
*/
@@ -3437,6 +3439,24 @@ QTextImageFormat::QTextImageFormat(const QTextFormat &fmt)
\sa height(), setWidth()
*/
+/*!
+ \fn void QTextImageFormat::setMaximumWidth(QTextLength maximumWidth)
+
+ Sets the \a maximumWidth of the rectangle occupied by the image. This
+ can be an absolute number or a percentage of the available document size.
+
+ \sa width(), setHeight()
+*/
+
+
+/*!
+ \fn QTextLength QTextImageFormat::maximumWidth() const
+
+ Returns the maximum width of the rectangle occupied by the image.
+
+ \sa width(), setMaximumWidth()
+*/
+
/*!
\fn void QTextImageFormat::setHeight(qreal height)
diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h
index c009d328cb..2fa86ed0d1 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -241,6 +241,7 @@ public:
ImageWidth = 0x5010,
ImageHeight = 0x5011,
ImageQuality = 0x5014,
+ ImageMaxWidth = 0x5015,
// internal
/*
@@ -796,6 +797,10 @@ public:
inline qreal width() const
{ return doubleProperty(ImageWidth); }
+ inline void setMaximumWidth(QTextLength maxWidth);
+ inline QTextLength maximumWidth() const
+ { return lengthProperty(ImageMaxWidth); }
+
inline void setHeight(qreal height);
inline qreal height() const
{ return doubleProperty(ImageHeight); }
@@ -823,6 +828,9 @@ inline void QTextImageFormat::setName(const QString &aname)
inline void QTextImageFormat::setWidth(qreal awidth)
{ setProperty(ImageWidth, awidth); }
+inline void QTextImageFormat::setMaximumWidth(QTextLength maxWidth)
+{ setProperty(ImageMaxWidth, maxWidth); }
+
inline void QTextImageFormat::setHeight(qreal aheight)
{ setProperty(ImageHeight, aheight); }
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index ee92cece78..54c291b82e 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -1422,12 +1422,74 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
}
break;
}
+ case QCss::QtStrokeLineCap:
+ {
+ QPen pen = charFormat.textOutline();
+ switch (identifier) {
+ case QCss::Value_SquareCap: pen.setCapStyle(Qt::SquareCap); break;
+ case QCss::Value_FlatCap: pen.setCapStyle(Qt::FlatCap); break;
+ case QCss::Value_RoundCap: pen.setCapStyle(Qt::RoundCap); break;
+ default: break;
+ }
+ charFormat.setTextOutline(pen);
+ break;
+ }
+ case QCss::QtStrokeLineJoin:
+ {
+ QPen pen = charFormat.textOutline();
+ switch (identifier) {
+ case QCss::Value_MiterJoin: pen.setJoinStyle(Qt::MiterJoin); break;
+ case QCss::Value_BevelJoin: pen.setJoinStyle(Qt::BevelJoin); break;
+ case QCss::Value_RoundJoin: pen.setJoinStyle(Qt::RoundJoin); break;
+ case QCss::Value_SvgMiterJoin: pen.setJoinStyle(Qt::SvgMiterJoin); break;
+ default: break;
+ }
+ charFormat.setTextOutline(pen);
+ break;
+ }
+ case QCss::QtStrokeMiterLimit:
+ {
+ qreal miterLimit;
+ if (decl.realValue(&miterLimit)) {
+ QPen pen = charFormat.textOutline();
+ pen.setMiterLimit(miterLimit);
+ charFormat.setTextOutline(pen);
+ }
+ break;
+ }
+ case QCss::QtStrokeDashArray:
+ {
+ QList<qreal> dashes = decl.dashArray();
+ if (!dashes.empty()) {
+ QPen pen = charFormat.textOutline();
+ pen.setDashPattern(dashes);
+ charFormat.setTextOutline(pen);
+ }
+ break;
+ }
+ case QCss::QtStrokeDashOffset:
+ {
+ qreal dashOffset;
+ if (decl.realValue(&dashOffset)) {
+ QPen pen = charFormat.textOutline();
+ pen.setDashOffset(dashOffset);
+ charFormat.setTextOutline(pen);
+ }
+ break;
+ }
case QCss::QtForeground:
{
QBrush brush = decl.brushValue();
charFormat.setForeground(brush);
break;
}
+ case QCss::MaximumWidth:
+ if (id == Html_img) {
+ auto imageFormat = charFormat.toImageFormat();
+ imageFormat.setMaximumWidth(extractor.textLength(decl));
+ charFormat = imageFormat;
+ }
+ break;
default: break;
}
}
diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp
index 5c56c30711..920e6c689c 100644
--- a/src/gui/text/qtextimagehandler.cpp
+++ b/src/gui/text/qtextimagehandler.cpp
@@ -12,6 +12,7 @@
#include <private/qtextengine_p.h>
#include <qpalette.h>
#include <qthread.h>
+#include <limits>
QT_BEGIN_NAMESPACE
@@ -72,21 +73,40 @@ template<typename T>
static QSize getSize(QTextDocument *doc, const QTextImageFormat &format)
{
const bool hasWidth = format.hasProperty(QTextFormat::ImageWidth);
- const int width = qRound(format.width());
+ int width = qRound(format.width());
const bool hasHeight = format.hasProperty(QTextFormat::ImageHeight);
const int height = qRound(format.height());
+ const bool hasMaxWidth = format.hasProperty(QTextFormat::ImageMaxWidth);
+ const auto maxWidth = format.maximumWidth();
+
+ int effectiveMaxWidth = std::numeric_limits<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);
+ }
+
T source;
QSize size(width, height);
if (!hasWidth || !hasHeight) {
source = getAs<T>(doc, format);
- const QSizeF sourceSize = source.deviceIndependentSize();
+ QSizeF sourceSize = source.deviceIndependentSize();
+
+ if (sourceSize.width() > effectiveMaxWidth) {
+ // image is bigger than effectiveMaxWidth, scale it down
+ sourceSize.setHeight(effectiveMaxWidth * (sourceSize.height() / qreal(sourceSize.width())));
+ sourceSize.setWidth(effectiveMaxWidth);
+ }
if (!hasWidth) {
if (!hasHeight)
size.setWidth(sourceSize.width());
else
- size.setWidth(qRound(height * (sourceSize.width() / qreal(sourceSize.height()))));
+ size.setWidth(qMin(effectiveMaxWidth, qRound(height * (sourceSize.width() / qreal(sourceSize.height())))));
}
if (!hasHeight) {
if (!hasWidth)
diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp
index 975a583220..d607d38235 100644
--- a/src/gui/text/unix/qfontconfigdatabase.cpp
+++ b/src/gui/text/unix/qfontconfigdatabase.cpp
@@ -642,7 +642,7 @@ QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine,
}
namespace {
-QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool useXftConf)
+QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool preferXftConf)
{
switch (hintingPreference) {
case QFont::PreferNoHinting:
@@ -658,6 +658,13 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
if (isDprScaling())
return QFontEngine::HintNone;
+ void *hintStyleResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
+ QGuiApplication::primaryScreen());
+ int xftHintStyle = int(reinterpret_cast<qintptr>(hintStyleResource));
+ if (preferXftConf && xftHintStyle > 0)
+ return QFontEngine::HintStyle(xftHintStyle - 1);
+
int hint_style = 0;
if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultMatch) {
switch (hint_style) {
@@ -674,21 +681,21 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
break;
}
}
-
- if (useXftConf) {
- void *hintStyleResource =
- QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
- QGuiApplication::primaryScreen());
- int hintStyle = int(reinterpret_cast<qintptr>(hintStyleResource));
- if (hintStyle > 0)
- return QFontEngine::HintStyle(hintStyle - 1);
- }
+ if (xftHintStyle > 0)
+ return QFontEngine::HintStyle(xftHintStyle - 1);
return QFontEngine::HintFull;
}
-QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool useXftConf)
+QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool preferXftConf)
{
+ void *subpixelTypeResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
+ QGuiApplication::primaryScreen());
+ int xftSubpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
+ if (preferXftConf && xftSubpixelType > 0)
+ return QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
+
int subpixel = FC_RGBA_UNKNOWN;
if (FcPatternGetInteger(match, FC_RGBA, 0, &subpixel) == FcResultMatch) {
switch (subpixel) {
@@ -709,14 +716,8 @@ QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bo
}
}
- if (useXftConf) {
- void *subpixelTypeResource =
- QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
- QGuiApplication::primaryScreen());
- int subpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
- if (subpixelType > 0)
- return QFontEngine::SubpixelAntialiasingType(subpixelType - 1);
- }
+ if (xftSubpixelType > 0)
+ return QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
return QFontEngine::Subpixel_None;
}
@@ -965,20 +966,11 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
bool forcedAntialiasSetting = !antialias || isDprScaling();
const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
- bool useXftConf = false;
+ bool preferXftConf = false;
if (services) {
const QList<QByteArray> desktopEnv = services->desktopEnvironment().split(':');
- useXftConf = desktopEnv.contains("GNOME") || desktopEnv.contains("UNITY") || desktopEnv.contains("XFCE");
- }
-
- if (useXftConf && !forcedAntialiasSetting) {
- void *antialiasResource =
- QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
- QGuiApplication::primaryScreen());
- int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource));
- if (antialiasingEnabled > 0)
- antialias = antialiasingEnabled - 1;
+ preferXftConf = !(desktopEnv.contains("KDE") || desktopEnv.contains("LXQT") || desktopEnv.contains("UKUI"));
}
QFontEngine::GlyphFormat format;
@@ -1060,8 +1052,19 @@ bail:
if (!match)
match = FcFontMatch(nullptr, pattern, &result);
+ int xftAntialias = 0;
+ if (!forcedAntialiasSetting) {
+ void *antialiasResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
+ QGuiApplication::primaryScreen());
+ xftAntialias = int(reinterpret_cast<qintptr>(antialiasResource));
+ if ((preferXftConf || !match) && xftAntialias > 0) {
+ antialias = xftAntialias - 1;
+ forcedAntialiasSetting = true;
+ }
+ }
if (match) {
- engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, useXftConf));
+ engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, preferXftConf));
FcBool fc_autohint;
if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
@@ -1082,18 +1085,37 @@ bail:
if (antialias) {
QFontEngine::SubpixelAntialiasingType subpixelType = QFontEngine::Subpixel_None;
if (!(fontDef.styleStrategy & QFont::NoSubpixelAntialias))
- subpixelType = subpixelTypeFromMatch(match, useXftConf);
+ subpixelType = subpixelTypeFromMatch(match, preferXftConf);
engine->subpixelType = subpixelType;
-
- format = (subpixelType == QFontEngine::Subpixel_None)
- ? QFontEngine::Format_A8
- : QFontEngine::Format_A32;
- } else
- format = QFontEngine::Format_Mono;
+ }
FcPatternDestroy(match);
- } else
- format = antialias ? QFontEngine::Format_A8 : QFontEngine::Format_Mono;
+ } else {
+ void *hintStyleResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
+ QGuiApplication::primaryScreen());
+ int xftHintStyle = int(reinterpret_cast<qintptr>(hintStyleResource));
+ if (xftHintStyle > 0)
+ engine->setDefaultHintStyle(QFontEngine::HintStyle(xftHintStyle - 1));
+ if (antialias) {
+ engine->subpixelType = QFontEngine::Subpixel_None;
+ if (!(fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
+ void *subpixelTypeResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
+ QGuiApplication::primaryScreen());
+ int xftSubpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
+ if (xftSubpixelType > 1)
+ engine->subpixelType = QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
+ }
+ }
+ }
+ if (antialias) {
+ format = (engine->subpixelType == QFontEngine::Subpixel_None)
+ ? QFontEngine::Format_A8
+ : QFontEngine::Format_A32;
+ } else {
+ format = QFontEngine::Format_Mono;
+ }
FcPatternDestroy(pattern);
diff --git a/src/gui/text/windows/qwindowsfontengine.cpp b/src/gui/text/windows/qwindowsfontengine.cpp
index fe07897369..5de80dc8a3 100644
--- a/src/gui/text/windows/qwindowsfontengine.cpp
+++ b/src/gui/text/windows/qwindowsfontengine.cpp
@@ -132,8 +132,9 @@ void QWindowsFontEngine::getCMap()
}
}
-int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const
+int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const
{
+ *mappedGlyphs = 0;
int glyph_pos = 0;
{
if (symbol) {
@@ -143,6 +144,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
} else if (ttf) {
@@ -150,6 +153,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
while (it.hasNext()) {
const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
} else {
@@ -160,6 +165,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
glyphs->glyphs[glyph_pos] = uc;
else
glyphs->glyphs[glyph_pos] = 0;
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
}
@@ -259,7 +266,7 @@ HGDIOBJ QWindowsFontEngine::selectDesignFont() const
return SelectObject(m_fontEngineData->hdc, designFont);
}
-bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
@@ -268,12 +275,13 @@ bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *g
}
glyphs->numGlyphs = *nglyphs;
- *nglyphs = getGlyphIndexes(str, len, glyphs);
+ int mappedGlyphs;
+ *nglyphs = getGlyphIndexes(str, len, glyphs, &mappedGlyphs);
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return mappedGlyphs;
}
inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
diff --git a/src/gui/text/windows/qwindowsfontengine_p.h b/src/gui/text/windows/qwindowsfontengine_p.h
index afe8ee4ca5..07f4db3c4a 100644
--- a/src/gui/text/windows/qwindowsfontengine_p.h
+++ b/src/gui/text/windows/qwindowsfontengine_p.h
@@ -48,7 +48,7 @@ public:
QFixed emSquareSize() const override;
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override;
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override;
@@ -88,7 +88,7 @@ public:
bool hasUnreliableGlyphOutline() const override;
- int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const;
+ int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const;
void getCMap();
bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const;
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
index 2070deb296..47b8a7ee3c 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
@@ -435,13 +435,13 @@ glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const
return glyphIndex;
}
-bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
- int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
QVarLengthArray<UINT32> codePoints(len);
@@ -455,11 +455,15 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly
glyphIndices.data());
if (FAILED(hr)) {
qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__);
- return false;
+ return -1;
}
- for (int i = 0; i < actualLength; ++i)
+ int mappedGlyphs = 0;
+ for (int i = 0; i < actualLength; ++i) {
glyphs->glyphs[i] = glyphIndices.at(i);
+ if (glyphs->glyphs[i] != 0 || isIgnorableChar(codePoints.at(i)))
+ mappedGlyphs++;
+ }
*nglyphs = actualLength;
glyphs->numGlyphs = actualLength;
@@ -467,7 +471,7 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, {});
- return true;
+ return mappedGlyphs;
}
QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
index 44e466789c..d7c9a79267 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
@@ -53,8 +53,8 @@ public:
QFixed emSquareSize() const override;
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
- ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
+ ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override;
void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index 4a12f6db6f..4d98faf398 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -18,8 +18,6 @@
#include <qpa/qplatformintegration.h>
#include <qdir.h>
-#include <QtCore/private/qlocking_p.h>
-
QT_BEGIN_NAMESPACE
class QOpenUrlHandlerRegistry
@@ -36,36 +34,10 @@ public:
};
typedef QHash<QString, Handler> HandlerHash;
HandlerHash handlers;
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
- QObject context;
-
- void handlerDestroyed(QObject *handler);
-#endif
-
};
Q_GLOBAL_STATIC(QOpenUrlHandlerRegistry, handlerRegistry)
-#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
-void QOpenUrlHandlerRegistry::handlerDestroyed(QObject *handler)
-{
- const auto lock = qt_scoped_lock(mutex);
- HandlerHash::Iterator it = handlers.begin();
- while (it != handlers.end()) {
- if (it->receiver == handler) {
- it = handlers.erase(it);
- qWarning("Please call QDesktopServices::unsetUrlHandler() before destroying a "
- "registered URL handler object.\n"
- "Support for destroying a registered URL handler object is deprecated, "
- "and will be removed in Qt 6.6.");
- } else {
- ++it;
- }
- }
-}
-#endif
-
/*!
\class QDesktopServices
\brief The QDesktopServices class provides methods for accessing common desktop services.
@@ -238,10 +210,11 @@ bool QDesktopServices::openUrl(const QUrl &url)
the destruction of the handler object does not overlap with concurrent
invocations of openUrl() using it.
- \section1 iOS
+ \section1 iOS and \macos
- To use this function for receiving data from other apps on iOS you also need to
- add the custom scheme to the \c CFBundleURLSchemes list in your Info.plist file:
+ To use this function for receiving data from other apps on iOS/\macos
+ you also need to add the custom scheme to the \c CFBundleURLSchemes
+ list in your Info.plist file:
\snippet code/src_gui_util_qdesktopservices.cpp 4
@@ -256,7 +229,7 @@ bool QDesktopServices::openUrl(const QUrl &url)
\snippet code/src_gui_util_qdesktopservices.cpp 7
- iOS will search for /.well-known/apple-app-site-association on your domain,
+ iOS/\macos will search for /.well-known/apple-app-site-association on your domain,
when the application is installed. If you want to listen to
\c{https://your.domain.com/help?topic=ABCDEF} you need to provide the following
content there:
@@ -306,11 +279,6 @@ void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, c
h.receiver = receiver;
h.name = method;
registry->handlers.insert(scheme.toLower(), h);
-#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
- QObject::connect(receiver, &QObject::destroyed, &registry->context,
- [registry](QObject *obj) { registry->handlerDestroyed(obj); },
- Qt::DirectConnection);
-#endif
}
/*!
diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp
index e8648eb91d..07981e8388 100644
--- a/src/gui/util/qgridlayoutengine.cpp
+++ b/src/gui/util/qgridlayoutengine.cpp
@@ -720,7 +720,7 @@ void QGridLayoutItem::dump(int indent) const
if (q_alignment != 0)
qDebug("%*s Alignment: %x", indent, "", uint(q_alignment));
qDebug("%*s Horizontal size policy: %x Vertical size policy: %x",
- indent, "", sizePolicy(Qt::Horizontal), sizePolicy(Qt::Vertical));
+ indent, "", (unsigned int)sizePolicy(Qt::Horizontal), (unsigned int)sizePolicy(Qt::Vertical));
}
#endif
@@ -1182,7 +1182,7 @@ void QGridLayoutEngine::dump(int indent) const
{
qDebug("%*sEngine", indent, "");
- qDebug("%*s Items (%d)", indent, "", q_items.count());
+ qDebug("%*s Items (%lld)", indent, "", q_items.count());
int i;
for (i = 0; i < q_items.count(); ++i)
q_items.at(i)->dump(indent + 2);
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index 4d5c641247..e977400245 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -22,6 +22,7 @@ qt_internal_add_module(Network
access/qnetworkfile.cpp access/qnetworkfile_p.h
access/qhttpheaders.cpp access/qhttpheaders.h
access/qhttpheaderparser.cpp access/qhttpheaderparser_p.h
+ access/qhttpheadershelper.cpp access/qhttpheadershelper_p.h
access/qnetworkreply.cpp access/qnetworkreply.h access/qnetworkreply_p.h
access/qnetworkreplydataimpl.cpp access/qnetworkreplydataimpl_p.h
access/qnetworkreplyfileimpl.cpp access/qnetworkreplyfileimpl_p.h
@@ -142,6 +143,7 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_http
access/qnetworkrequestfactory.h
access/qrestaccessmanager.cpp access/qrestaccessmanager.h access/qrestaccessmanager_p.h
access/qrestreply.cpp access/qrestreply.h access/qrestreply_p.h
+ access/qsocketabstraction_p.h
socket/qhttpsocketengine.cpp socket/qhttpsocketengine_p.h
)
diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h
index fb5ff199c5..f0f18d1dd5 100644
--- a/src/network/access/http2/http2protocol_p.h
+++ b/src/network/access/http2/http2protocol_p.h
@@ -117,7 +117,7 @@ const qint32 maxSessionReceiveWindowSize((quint32(1) << 31) - 1);
// Presumably, we never use up to 100 streams so let it be 10 simultaneous:
const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / 10;
-struct Frame configurationToSettingsFrame(const QHttp2Configuration &configuration);
+struct Frame Q_AUTOTEST_EXPORT configurationToSettingsFrame(const QHttp2Configuration &configuration);
QByteArray settingsFrameToBase64(const Frame &settingsFrame);
void appendProtocolUpgradeHeaders(const QHttp2Configuration &configuration, QHttpNetworkRequest *request);
std::vector<uchar> assemble_hpack_block(const std::vector<Frame> &frames);
diff --git a/src/network/access/qabstractnetworkcache.cpp b/src/network/access/qabstractnetworkcache.cpp
index c8b940d801..3cd55d46fa 100644
--- a/src/network/access/qabstractnetworkcache.cpp
+++ b/src/network/access/qabstractnetworkcache.cpp
@@ -3,6 +3,8 @@
#include "qabstractnetworkcache.h"
#include "qabstractnetworkcache_p.h"
+#include "qnetworkrequest_p.h"
+#include "qhttpheadershelper_p.h"
#include <qdatastream.h>
#include <qdatetime.h>
@@ -28,14 +30,14 @@ public:
url == other.url
&& lastModified == other.lastModified
&& expirationDate == other.expirationDate
- && headers == other.headers
- && saveToDisk == other.saveToDisk;
+ && saveToDisk == other.saveToDisk
+ && QHttpHeadersHelper::compareStrict(headers, other.headers);
}
QUrl url;
QDateTime lastModified;
QDateTime expirationDate;
- QNetworkCacheMetaData::RawHeaderList headers;
+ QHttpHeaders headers;
QNetworkCacheMetaData::AttributesMap attributes;
bool saveToDisk;
@@ -207,21 +209,45 @@ void QNetworkCacheMetaData::setUrl(const QUrl &url)
Returns a list of all raw headers that are set in this meta data.
The list is in the same order that the headers were set.
- \sa setRawHeaders()
+ \sa setRawHeaders(), headers()
*/
QNetworkCacheMetaData::RawHeaderList QNetworkCacheMetaData::rawHeaders() const
{
- return d->headers;
+ return QNetworkHeadersPrivate::fromHttpToRaw(d->headers);
}
/*!
Sets the raw headers to \a list.
- \sa rawHeaders()
+ \sa rawHeaders(), setHeaders()
*/
void QNetworkCacheMetaData::setRawHeaders(const RawHeaderList &list)
{
- d->headers = list;
+ d->headers = QNetworkHeadersPrivate::fromRawToHttp(list);
+}
+
+/*!
+ \since 6.8
+
+ Returns headers in form of QHttpHeaders that are set in this meta data.
+
+ \sa setHeaders()
+*/
+QHttpHeaders QNetworkCacheMetaData::headers() const
+{
+ return d->headers;
+}
+
+/*!
+ \since 6.8
+
+ Sets the headers of this network cache meta data to \a headers.
+
+ \sa headers()
+*/
+void QNetworkCacheMetaData::setHeaders(const QHttpHeaders &headers)
+{
+ d->headers = headers;
}
/*!
@@ -367,7 +393,8 @@ void QNetworkCacheMetaDataPrivate::load(QDataStream &in, QNetworkCacheMetaData &
in >> p->lastModified;
in >> p->saveToDisk;
in >> p->attributes;
- in >> p->headers;
+ QNetworkCacheMetaData::RawHeaderList list; in >> list;
+ metaData.setRawHeaders(list);
}
/*!
diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h
index c70dcf737c..b12fd4f863 100644
--- a/src/network/access/qabstractnetworkcache.h
+++ b/src/network/access/qabstractnetworkcache.h
@@ -48,6 +48,9 @@ public:
RawHeaderList rawHeaders() const;
void setRawHeaders(const RawHeaderList &headers);
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &headers);
+
QDateTime lastModified() const;
void setLastModified(const QDateTime &dateTime);
diff --git a/src/network/access/qabstractprotocolhandler_p.h b/src/network/access/qabstractprotocolhandler_p.h
index ad82aae66e..da5eaeeb74 100644
--- a/src/network/access/qabstractprotocolhandler_p.h
+++ b/src/network/access/qabstractprotocolhandler_p.h
@@ -23,7 +23,7 @@ QT_BEGIN_NAMESPACE
class QHttpNetworkConnectionChannel;
class QHttpNetworkReply;
-class QAbstractSocket;
+class QIODevice;
class QHttpNetworkConnection;
class QAbstractProtocolHandler {
@@ -39,7 +39,7 @@ public:
protected:
QHttpNetworkConnectionChannel *m_channel;
QHttpNetworkReply *m_reply;
- QAbstractSocket *m_socket;
+ QIODevice *m_socket;
QHttpNetworkConnection *m_connection;
};
diff --git a/src/network/access/qhttp2connection.cpp b/src/network/access/qhttp2connection.cpp
index d9900c3157..8560e0da38 100644
--- a/src/network/access/qhttp2connection.cpp
+++ b/src/network/access/qhttp2connection.cpp
@@ -1222,8 +1222,8 @@ void QHttp2Connection::handleDATA()
sessionReceiveWindowSize -= inboundFrame.payloadSize();
- auto it = m_streams.find(streamID);
- if (it != m_streams.end() && it.value())
+ auto it = m_streams.constFind(streamID);
+ if (it != m_streams.cend() && it.value())
it.value()->handleDATA(inboundFrame);
if (sessionReceiveWindowSize < maxSessionReceiveWindowSize / 2) {
@@ -1581,9 +1581,9 @@ void QHttp2Connection::handleContinuedHEADERS()
const auto streamID = continuedFrames[0].streamID();
- const auto streamIt = m_streams.find(streamID);
+ const auto streamIt = m_streams.constFind(streamID);
if (firstFrameType == FrameType::HEADERS) {
- if (streamIt != m_streams.end()) {
+ if (streamIt != m_streams.cend()) {
QHttp2Stream *stream = streamIt.value();
if (stream->state() != QHttp2Stream::State::HalfClosedLocal
&& stream->state() != QHttp2Stream::State::ReservedRemote
@@ -1619,7 +1619,7 @@ void QHttp2Connection::handleContinuedHEADERS()
// not include a complete and valid set of header fields or the :method
// pseudo-header field identifies a method that is not safe, it MUST
// respond with a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
- if (streamIt != m_streams.end())
+ if (streamIt != m_streams.cend())
(*streamIt)->sendRST_STREAM(PROTOCOL_ERROR);
return;
}
@@ -1632,7 +1632,7 @@ void QHttp2Connection::handleContinuedHEADERS()
return connectionError(FRAME_SIZE_ERROR, "HEADERS frame too large");
}
- if (streamIt == m_streams.end()) // No more processing without a stream from here on.
+ if (streamIt == m_streams.cend()) // No more processing without a stream from here on.
return;
switch (firstFrameType) {
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 376f7251ff..d9341dc643 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -1205,12 +1205,14 @@ void QHttp2ProtocolHandler::handleAuthorization(Stream &stream)
// In this case IIS will fall back to HTTP/1.1."
// Though it might be OK to ignore this. The server shouldn't let us connect with
// HTTP/2 if it doesn't support us using it.
- } else if (!auth.isEmpty()) {
- // Somewhat mimics parts of QHttpNetworkConnectionChannel::handleStatus
- bool resend = false;
- const bool authenticateHandled = m_connection->d_func()->handleAuthenticateChallenge(
- m_socket, httpReply, isProxy, resend);
- if (authenticateHandled && resend) {
+ return false;
+ }
+ // Somewhat mimics parts of QHttpNetworkConnectionChannel::handleStatus
+ bool resend = false;
+ const bool authenticateHandled = m_connection->d_func()->handleAuthenticateChallenge(
+ m_socket, httpReply, isProxy, resend);
+ if (authenticateHandled) {
+ if (resend) {
httpReply->d_func()->eraseData();
// Add the request back in queue, we'll retry later now that
// we've gotten some username/password set on it:
@@ -1225,11 +1227,15 @@ void QHttp2ProtocolHandler::handleAuthorization(Stream &stream)
// We automatically try to send new requests when the stream is
// closed, so we don't need to call sendRequest ourselves.
return true;
- } // else: Authentication failed or was cancelled
+ } // else: we're just not resending the request.
+ // @note In the http/1.x case we (at time of writing) call close()
+ // for the connectionChannel (which is a bit weird, we could surely
+ // reuse the open socket outside "connection:close"?), but in http2
+ // we only have one channel, so we won't close anything.
} else {
- // No authentication header, but we got a 401/407 so we cannot
- // succeed. We need to emit signals for headers and data, and then
- // finishWithError.
+ // No authentication header or authentication isn't supported, but
+ // we got a 401/407 so we cannot succeed. We need to emit signals
+ // for headers and data, and then finishWithError.
emit httpReply->headerChanged();
emit httpReply->readyRead();
QNetworkReply::NetworkError error = httpReply->statusCode() == 401
diff --git a/src/network/access/qhttpheaders.h b/src/network/access/qhttpheaders.h
index 97dc415e55..260df1421b 100644
--- a/src/network/access/qhttpheaders.h
+++ b/src/network/access/qhttpheaders.h
@@ -4,7 +4,8 @@
#ifndef QHTTPHEADERS_H
#define QHTTPHEADERS_H
-#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qtnetworkglobal.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qcontainerfwd.h>
diff --git a/src/network/access/qhttpheadershelper.cpp b/src/network/access/qhttpheadershelper.cpp
new file mode 100644
index 0000000000..d3cc9e439f
--- /dev/null
+++ b/src/network/access/qhttpheadershelper.cpp
@@ -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
+
+#include "qhttpheadershelper_p.h"
+
+#include <QtNetwork/qhttpheaders.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QHttpHeadersHelper::compareStrict(const QHttpHeaders &left, const QHttpHeaders &right)
+{
+ if (left.size() != right.size())
+ return false;
+
+ for (qsizetype i = 0; i < left.size(); ++i) {
+ if (left.nameAt(i) != right.nameAt(i))
+ return false;
+ if (left.valueAt(i) != right.valueAt(i))
+ return false;
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttpheadershelper_p.h b/src/network/access/qhttpheadershelper_p.h
new file mode 100644
index 0000000000..d1e38a1a8e
--- /dev/null
+++ b/src/network/access/qhttpheadershelper_p.h
@@ -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
+
+#ifndef QHTTPHEADERSHELPER_H
+#define QHTTPHEADERSHELPER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHttpHeaders;
+
+namespace QHttpHeadersHelper {
+ Q_NETWORK_EXPORT bool compareStrict(const QHttpHeaders &left, const QHttpHeaders &right);
+};
+
+QT_END_NAMESPACE
+
+#endif // QHTTPHEADERSHELPER_H
diff --git a/src/network/access/qhttpmultipart.cpp b/src/network/access/qhttpmultipart.cpp
index 6d81f1b957..a695969f00 100644
--- a/src/network/access/qhttpmultipart.cpp
+++ b/src/network/access/qhttpmultipart.cpp
@@ -386,9 +386,12 @@ void QHttpPartPrivate::checkHeaderCreated() const
{
if (!headerCreated) {
// copied from QHttpNetworkRequestPrivate::header() and adapted
- const auto fields = allRawHeaders();
- for (const auto &[name, value] : fields)
- header += name + ": " + value + "\r\n";
+ const auto h = headers();
+ for (qsizetype i = 0; i < h.size(); ++i) {
+ const auto name = h.nameAt(i);
+ header += QByteArrayView(name.data(), name.size()) + ": " + h.valueAt(i) + "\r\n";
+ }
+
header += "\r\n";
headerCreated = true;
}
@@ -511,6 +514,48 @@ qint64 QHttpMultiPartIODevice::writeData(const char *data, qint64 maxSize)
return -1;
}
+#ifndef QT_NO_DEBUG_STREAM
+
+/*!
+ \fn QDebug QHttpPart::operator<<(QDebug debug, const QHttpPart &part)
+
+ Writes the \a part into the \a debug object for debugging purposes.
+ Unless a device is set, the size of the body is shown.
+
+ \sa {Debugging Techniques}
+ \since 6.8
+*/
+
+QDebug operator<<(QDebug debug, const QHttpPart &part)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace().noquote();
+
+ debug << "QHttpPart(headers = ["
+ << part.d->cookedHeaders
+ << "], http headers = ["
+ << part.d->httpHeaders
+ << "],";
+
+ if (part.d->bodyDevice) {
+ debug << " bodydevice = ["
+ << part.d->bodyDevice
+ << ", is open: "
+ << part.d->bodyDevice->isOpen()
+ << "]";
+ } else {
+ debug << " size of body = "
+ << part.d->body.size()
+ << " bytes";
+ }
+
+ debug << ")";
+
+ return debug;
+}
+
+#endif // QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/network/access/qhttpmultipart.h b/src/network/access/qhttpmultipart.h
index 26e5fafdf2..9732bbd99d 100644
--- a/src/network/access/qhttpmultipart.h
+++ b/src/network/access/qhttpmultipart.h
@@ -19,6 +19,7 @@ QT_BEGIN_NAMESPACE
class QHttpPartPrivate;
class QHttpMultiPart;
+class QDebug;
class Q_NETWORK_EXPORT QHttpPart
{
@@ -45,6 +46,9 @@ private:
QSharedDataPointer<QHttpPartPrivate> d;
friend class QHttpMultiPartIODevice;
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QHttpPart &httpPart);
+#endif
};
Q_DECLARE_SHARED(QHttpPart)
diff --git a/src/network/access/qhttpmultipart_p.h b/src/network/access/qhttpmultipart_p.h
index d485fcf5cd..7a12ce8424 100644
--- a/src/network/access/qhttpmultipart_p.h
+++ b/src/network/access/qhttpmultipart_p.h
@@ -18,6 +18,7 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "QtCore/qshareddata.h"
#include "qnetworkrequest_p.h" // for deriving QHttpPartPrivate from QNetworkHeadersPrivate
+#include "qhttpheadershelper_p.h"
#include "private/qobject_p.h"
#ifndef Q_OS_WASM
@@ -47,8 +48,10 @@ public:
inline bool operator==(const QHttpPartPrivate &other) const
{
- return rawHeaders == other.rawHeaders && body == other.body &&
- bodyDevice == other.bodyDevice && readPointer == other.readPointer;
+ return QHttpHeadersHelper::compareStrict(httpHeaders, other.httpHeaders)
+ && body == other.body
+ && bodyDevice == other.bodyDevice
+ && readPointer == other.readPointer;
}
void setBodyDevice(QIODevice *device) {
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 39734a9f79..501a410ae7 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -13,6 +13,7 @@
#include <qauthenticator.h>
#include <qcoreapplication.h>
#include <private/qdecompresshelper_p.h>
+#include <private/qsocketabstraction_p.h>
#include <qbuffer.h>
#include <qpair.h>
@@ -51,10 +52,11 @@ static int getPreferredActiveChannelCount(QHttpNetworkConnection::ConnectionType
QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(
quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type)
+ bool isLocalSocket, QHttpNetworkConnection::ConnectionType type)
: hostName(hostName),
port(port),
encrypt(encrypt),
+ isLocalSocket(isLocalSocket),
activeChannelCount(getPreferredActiveChannelCount(type, connectionCount)),
channelCount(connectionCount),
channels(new QHttpNetworkConnectionChannel[channelCount]),
@@ -63,6 +65,8 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(
#endif
connectionType(type)
{
+ if (isLocalSocket) // Don't try to do host lookup for local sockets
+ networkLayerState = IPv4;
// We allocate all 6 channels even if it's an HTTP/2-enabled
// connection: in case the protocol negotiation via NPN/ALPN fails,
// we will have normally working HTTP/1.1.
@@ -101,13 +105,18 @@ void QHttpNetworkConnectionPrivate::pauseConnection()
// Disable all socket notifiers
for (int i = 0; i < activeChannelCount; i++) {
- if (channels[i].socket) {
+ if (auto *absSocket = qobject_cast<QAbstractSocket *>(channels[i].socket)) {
#ifndef QT_NO_SSL
if (encrypt)
- QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
+ QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(absSocket));
else
#endif
- QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket);
+ QAbstractSocketPrivate::pauseSocketNotifiers(absSocket);
+ } else if (qobject_cast<QLocalSocket *>(channels[i].socket)) {
+ // @todo how would we do this?
+#if 0 // @todo Enable this when there is a debug category for this
+ qDebug() << "Should pause socket but there is no way to do it for local sockets";
+#endif
}
}
}
@@ -117,17 +126,21 @@ void QHttpNetworkConnectionPrivate::resumeConnection()
state = RunningState;
// Enable all socket notifiers
for (int i = 0; i < activeChannelCount; i++) {
- if (channels[i].socket) {
+ if (auto *absSocket = qobject_cast<QAbstractSocket *>(channels[i].socket)) {
#ifndef QT_NO_SSL
if (encrypt)
- QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
+ QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(absSocket));
else
#endif
- QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket);
+ QAbstractSocketPrivate::resumeSocketNotifiers(absSocket);
// Resume pending upload if needed
if (channels[i].state == QHttpNetworkConnectionChannel::WritingState)
QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection);
+ } else if (qobject_cast<QLocalSocket *>(channels[i].socket)) {
+#if 0 // @todo Enable this when there is a debug category for this
+ qDebug() << "Should resume socket but there is no way to do it for local sockets";
+#endif
}
}
@@ -135,7 +148,7 @@ void QHttpNetworkConnectionPrivate::resumeConnection()
QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
}
-int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
+int QHttpNetworkConnectionPrivate::indexOf(QIODevice *socket) const
{
for (int i = 0; i < activeChannelCount; ++i)
if (channels[i].socket == socket)
@@ -149,7 +162,7 @@ int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
// emitted. This function will check the status of the connection channels if we
// have not decided the networkLayerState and will return true if the channel error
// should be emitted by the channel.
-bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QIODevice *socket)
{
Q_Q(QHttpNetworkConnection);
@@ -319,7 +332,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
-void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket,
+void QHttpNetworkConnectionPrivate::emitReplyError(QIODevice *socket,
QHttpNetworkReply *reply,
QNetworkReply::NetworkError errorCode)
{
@@ -384,7 +397,7 @@ void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthentica
// handles the authentication for one channel and eventually re-starts the other channels
-bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply,
+bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QIODevice *socket, QHttpNetworkReply *reply,
bool isProxy, bool &resend)
{
Q_ASSERT(socket);
@@ -486,7 +499,7 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
}
// Used by the HTTP1 code-path
-QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socket,
+QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QIODevice *socket,
QHttpNetworkReply *reply)
{
ParseRedirectResult result = parseRedirectResponse(reply);
@@ -523,7 +536,9 @@ QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
// Check redirect url protocol
const QUrl priorUrl(reply->request().url());
- if (redirectUrl.scheme() == "http"_L1 || redirectUrl.scheme() == "https"_L1) {
+ const QString targetUrlScheme = redirectUrl.scheme();
+ if (targetUrlScheme == "http"_L1 || targetUrlScheme == "https"_L1
+ || targetUrlScheme.startsWith("unix"_L1)) {
switch (reply->request().redirectPolicy()) {
case QNetworkRequest::NoLessSafeRedirectPolicy:
// Here we could handle https->http redirects as InsecureProtocolError.
@@ -534,7 +549,7 @@ QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
break;
case QNetworkRequest::SameOriginRedirectPolicy:
if (priorUrl.host() != redirectUrl.host()
- || priorUrl.scheme() != redirectUrl.scheme()
+ || priorUrl.scheme() != targetUrlScheme
|| priorUrl.port() != redirectUrl.port()) {
return {{}, QNetworkReply::InsecureRedirectError};
}
@@ -550,7 +565,7 @@ QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
return {std::move(redirectUrl), QNetworkReply::NoError};
}
-void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request)
+void QHttpNetworkConnectionPrivate::createAuthorization(QIODevice *socket, QHttpNetworkRequest &request)
{
Q_ASSERT(socket);
@@ -686,7 +701,7 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair)
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
}
-bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::dequeueRequest(QIODevice *socket)
{
int i = 0;
if (socket)
@@ -740,7 +755,7 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::predictNextRequestsReply() con
}
// this is called from _q_startNextRequest and when a request has been sent down a socket from the channel
-void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
+void QHttpNetworkConnectionPrivate::fillPipeline(QIODevice *socket)
{
// return fast if there is nothing to pipeline
if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
@@ -768,7 +783,7 @@ void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
return;
// check if socket is connected
- if (socket->state() != QAbstractSocket::ConnectedState)
+ if (QSocketAbstraction::socketState(socket) != QAbstractSocket::ConnectedState)
return;
// check for resendCurrent
@@ -862,16 +877,15 @@ bool QHttpNetworkConnectionPrivate::fillPipeline(QList<HttpMessagePair> &queue,
}
-QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket, const QString &extraDetail)
+QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QIODevice *socket, const QString &extraDetail)
{
QString errorString;
switch (errorCode) {
- case QNetworkReply::HostNotFoundError:
- if (socket)
- errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(socket->peerName());
- else
- errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(hostName);
+ case QNetworkReply::HostNotFoundError: {
+ const QString peerName = socket ? QSocketAbstraction::socketPeerName(socket) : hostName;
+ errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(peerName);
break;
+ }
case QNetworkReply::ConnectionRefusedError:
errorString = QCoreApplication::translate("QHttp", "Connection refused");
break;
@@ -1024,7 +1038,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
for (int i = 0; i < activeChannelCount; ++i) {
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
if (!channels[i].socket
- || channels[i].socket->state() == QAbstractSocket::UnconnectedState) {
+ || QSocketAbstraction::socketState(channels[i].socket) == QAbstractSocket::UnconnectedState) {
if (!channels[i].ensureConnection())
continue;
}
@@ -1048,7 +1062,9 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// try to get a free AND connected socket
for (int i = 0; i < activeChannelCount; ++i) {
if (channels[i].socket) {
- if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
+ if (!channels[i].reply && !channels[i].isSocketBusy()
+ && QSocketAbstraction::socketState(channels[i].socket)
+ == QAbstractSocket::ConnectedState) {
if (dequeueRequest(channels[i].socket))
channels[i].sendRequest();
}
@@ -1068,7 +1084,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
else if (networkLayerState == IPv6)
channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol;
channels[0].ensureConnection();
- if (channels[0].socket && channels[0].socket->state() == QAbstractSocket::ConnectedState
+ if (auto *s = channels[0].socket; s
+ && QSocketAbstraction::socketState(s) == QAbstractSocket::ConnectedState
&& !channels[0].pendingEncrypt) {
if (channels[0].h2RequestsToSend.size()) {
channels[0].sendRequest();
@@ -1095,9 +1112,13 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// return fast if there is nothing to pipeline
if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
return;
- for (int i = 0; i < activeChannelCount; i++)
- if (channels[i].socket && channels[i].socket->state() == QAbstractSocket::ConnectedState)
+ for (int i = 0; i < activeChannelCount; i++) {
+ if (channels[i].socket
+ && QSocketAbstraction::socketState(channels[i].socket)
+ == QAbstractSocket::ConnectedState) {
fillPipeline(channels[i].socket);
+ }
+ }
// If there is not already any connected channels we need to connect a new one.
// We do not pair the channel with the request until we know if it is
@@ -1122,15 +1143,16 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
if (!channels[i].socket)
continue;
- if ((channels[i].socket->state() == QAbstractSocket::ConnectingState)
- || (channels[i].socket->state() == QAbstractSocket::HostLookupState)
+ using State = QAbstractSocket::SocketState;
+ if ((QSocketAbstraction::socketState(channels[i].socket) == State::ConnectingState)
+ || (QSocketAbstraction::socketState(channels[i].socket) == State::HostLookupState)
|| channels[i].pendingEncrypt) { // pendingEncrypt == "EncryptingState"
neededOpenChannels--;
continue;
}
if (!channels[i].reply && !channels[i].isSocketBusy()
- && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
+ && (QSocketAbstraction::socketState(channels[i].socket) == State::UnconnectedState)) {
channelsToConnect.push_back(i);
neededOpenChannels--;
}
@@ -1329,9 +1351,9 @@ void QHttpNetworkConnectionPrivate::_q_connectDelayedChannel()
}
QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
- quint16 port, bool encrypt, QObject *parent,
+ quint16 port, bool encrypt, bool isLocalSocket, QObject *parent,
QHttpNetworkConnection::ConnectionType connectionType)
- : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt,
+ : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt, isLocalSocket,
connectionType)), parent)
{
Q_D(QHttpNetworkConnection);
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 29bc99fc8b..5e4bce5eb0 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -64,7 +64,8 @@ public:
};
QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80,
- bool encrypt = false, QObject *parent = nullptr,
+ bool encrypt = false, bool isLocalSocket = false,
+ QObject *parent = nullptr,
ConnectionType connectionType = ConnectionTypeHTTP);
~QHttpNetworkConnection();
@@ -155,7 +156,8 @@ public:
};
QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName, quint16 port,
- bool encrypt, QHttpNetworkConnection::ConnectionType type);
+ bool encrypt, bool isLocalSocket,
+ QHttpNetworkConnection::ConnectionType type);
~QHttpNetworkConnectionPrivate();
void init();
@@ -166,18 +168,18 @@ public:
enum { ChunkSize = 4096 };
- int indexOf(QAbstractSocket *socket) const;
+ int indexOf(QIODevice *socket) const;
QHttpNetworkReply *queueRequest(const QHttpNetworkRequest &request);
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
void fillHttp2Queue();
- bool dequeueRequest(QAbstractSocket *socket);
+ bool dequeueRequest(QIODevice *socket);
void prepareRequest(HttpMessagePair &request);
void updateChannel(int i, const HttpMessagePair &messagePair);
QHttpNetworkRequest predictNextRequest() const;
QHttpNetworkReply* predictNextRequestsReply() const;
- void fillPipeline(QAbstractSocket *socket);
+ void fillPipeline(QIODevice *socket);
bool fillPipeline(QList<HttpMessagePair> &queue, QHttpNetworkConnectionChannel &channel);
// read more HTTP body after the next event loop spin
@@ -195,9 +197,9 @@ public:
void _q_hostLookupFinished(const QHostInfo &info);
void _q_connectDelayedChannel();
- void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request);
+ void createAuthorization(QIODevice *socket, QHttpNetworkRequest &request);
- QString errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket,
+ QString errorDetail(QNetworkReply::NetworkError errorCode, QIODevice *socket,
const QString &extraDetail = QString());
void removeReply(QHttpNetworkReply *reply);
@@ -205,6 +207,7 @@ public:
QString hostName;
quint16 port;
bool encrypt;
+ bool isLocalSocket;
bool delayIpv4 = true;
// Number of channels we are trying to use at the moment:
@@ -212,22 +215,22 @@ public:
// The total number of channels we reserved:
const int channelCount;
QTimer delayedConnectionTimer;
- QHttpNetworkConnectionChannel *channels; // parallel connections to the server
- bool shouldEmitChannelError(QAbstractSocket *socket);
+ QHttpNetworkConnectionChannel * const channels; // parallel connections to the server
+ bool shouldEmitChannelError(QIODevice *socket);
qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const;
qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const;
- void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode);
- bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend);
+ void emitReplyError(QIODevice *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode);
+ bool handleAuthenticateChallenge(QIODevice *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend);
struct ParseRedirectResult {
QUrl redirectUrl;
QNetworkReply::NetworkError errorCode;
};
static ParseRedirectResult parseRedirectResponse(QHttpNetworkReply *reply);
// Used by the HTTP1 code-path
- QUrl parseRedirectResponse(QAbstractSocket *socket, QHttpNetworkReply *reply);
+ QUrl parseRedirectResponse(QIODevice *socket, QHttpNetworkReply *reply);
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy networkProxy;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 6766989690..8688e4b8d7 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -12,6 +12,7 @@
#include <private/qhttp2protocolhandler_p.h>
#include <private/qhttpprotocolhandler_p.h>
#include <private/http2protocol_p.h>
+#include <private/qsocketabstraction_p.h>
#ifndef QT_NO_SSL
# include <private/qsslsocket_p.h>
@@ -78,6 +79,8 @@ void QHttpNetworkConnectionChannel::init()
#ifndef QT_NO_SSL
if (connection->d_func()->encrypt)
socket = new QSslSocket;
+ else if (connection->d_func()->isLocalSocket)
+ socket = new QLocalSocket;
else
socket = new QTcpSocket;
#else
@@ -85,58 +88,75 @@ void QHttpNetworkConnectionChannel::init()
#endif
#ifndef QT_NO_NETWORKPROXY
// Set by QNAM anyway, but let's be safe here
- socket->setProxy(QNetworkProxy::NoProxy);
+ if (auto s = qobject_cast<QAbstractSocket *>(socket))
+ s->setProxy(QNetworkProxy::NoProxy);
#endif
// After some back and forth in all the last years, this is now a DirectConnection because otherwise
// the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
// which behave slightly differently on Windows vs Linux
- QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
- this, SLOT(_q_bytesWritten(qint64)),
+ QObject::connect(socket, &QIODevice::bytesWritten,
+ this, &QHttpNetworkConnectionChannel::_q_bytesWritten,
Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(connected()),
- this, SLOT(_q_connected()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(readyRead()),
- this, SLOT(_q_readyRead()),
+ QObject::connect(socket, &QIODevice::readyRead,
+ this, &QHttpNetworkConnectionChannel::_q_readyRead,
Qt::DirectConnection);
- // The disconnected() and error() signals may already come
- // while calling connectToHost().
- // In case of a cached hostname or an IP this
- // will then emit a signal to the user of QNetworkReply
- // but cannot be caught because the user did not have a chance yet
- // to connect to QNetworkReply's signals.
- qRegisterMetaType<QAbstractSocket::SocketError>();
- QObject::connect(socket, SIGNAL(disconnected()),
- this, SLOT(_q_disconnected()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
- this, SLOT(_q_error(QAbstractSocket::SocketError)),
- Qt::DirectConnection);
+
+ QSocketAbstraction::visit([this](auto *socket){
+ using SocketType = std::remove_pointer_t<decltype(socket)>;
+ QObject::connect(socket, &SocketType::connected,
+ this, &QHttpNetworkConnectionChannel::_q_connected,
+ Qt::DirectConnection);
+
+ // The disconnected() and error() signals may already come
+ // while calling connectToHost().
+ // In case of a cached hostname or an IP this
+ // will then emit a signal to the user of QNetworkReply
+ // but cannot be caught because the user did not have a chance yet
+ // to connect to QNetworkReply's signals.
+ QObject::connect(socket, &SocketType::disconnected,
+ this, &QHttpNetworkConnectionChannel::_q_disconnected,
+ Qt::DirectConnection);
+ if constexpr (std::is_same_v<SocketType, QAbstractSocket>) {
+ QObject::connect(socket, &QAbstractSocket::errorOccurred,
+ this, &QHttpNetworkConnectionChannel::_q_error,
+ Qt::DirectConnection);
+ } else if constexpr (std::is_same_v<SocketType, QLocalSocket>) {
+ auto convertAndForward = [this](QLocalSocket::LocalSocketError error) {
+ _q_error(static_cast<QAbstractSocket::SocketError>(error));
+ };
+ QObject::connect(socket, &SocketType::errorOccurred,
+ this, std::move(convertAndForward),
+ Qt::DirectConnection);
+ }
+ }, socket);
+
#ifndef QT_NO_NETWORKPROXY
- QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
- this, SLOT(_q_proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
- Qt::DirectConnection);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket)) {
+ QObject::connect(s, &QAbstractSocket::proxyAuthenticationRequired,
+ this, &QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired,
+ Qt::DirectConnection);
+ }
#endif
#ifndef QT_NO_SSL
QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
if (sslSocket) {
// won't be a sslSocket if encrypt is false
- QObject::connect(sslSocket, SIGNAL(encrypted()),
- this, SLOT(_q_encrypted()),
+ QObject::connect(sslSocket, &QSslSocket::encrypted,
+ this, &QHttpNetworkConnectionChannel::_q_encrypted,
Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
- this, SLOT(_q_sslErrors(QList<QSslError>)),
+ QObject::connect(sslSocket, &QSslSocket::sslErrors,
+ this, &QHttpNetworkConnectionChannel::_q_sslErrors,
Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
- this, SLOT(_q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
+ QObject::connect(sslSocket, &QSslSocket::preSharedKeyAuthenticationRequired,
+ this, &QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired,
Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
- this, SLOT(_q_encryptedBytesWritten(qint64)),
+ QObject::connect(sslSocket, &QSslSocket::encryptedBytesWritten,
+ this, &QHttpNetworkConnectionChannel::_q_encryptedBytesWritten,
Qt::DirectConnection);
if (ignoreAllSslErrors)
@@ -156,8 +176,10 @@ void QHttpNetworkConnectionChannel::init()
#endif
#ifndef QT_NO_NETWORKPROXY
- if (proxy.type() != QNetworkProxy::NoProxy)
- socket->setProxy(proxy);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket);
+ s && proxy.type() != QNetworkProxy::NoProxy) {
+ s->setProxy(proxy);
+ }
#endif
isInitialized = true;
}
@@ -170,7 +192,7 @@ void QHttpNetworkConnectionChannel::close()
if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
- else if (socket->state() == QAbstractSocket::UnconnectedState)
+ else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState;
else
state = QHttpNetworkConnectionChannel::ClosingState;
@@ -190,7 +212,7 @@ void QHttpNetworkConnectionChannel::abort()
{
if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
- else if (socket->state() == QAbstractSocket::UnconnectedState)
+ else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState;
else
state = QHttpNetworkConnectionChannel::ClosingState;
@@ -201,7 +223,10 @@ void QHttpNetworkConnectionChannel::abort()
if (socket) {
// socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
// there is no socket yet.
- socket->abort();
+ auto callAbort = [](auto *s) {
+ s->abort();
+ };
+ QSocketAbstraction::visit(callAbort, socket);
}
}
@@ -268,7 +293,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
if (!isInitialized)
init();
- QAbstractSocket::SocketState socketState = socket->state();
+ QAbstractSocket::SocketState socketState = QSocketAbstraction::socketState(socket);
// resend this request after we receive the disconnected signal
// If !socket->isOpen() then we have already called close() on the socket, but there was still a
@@ -335,7 +360,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
connectHost = connection->d_func()->networkProxy.hostName();
connectPort = connection->d_func()->networkProxy.port();
}
- if (socket->proxy().type() == QNetworkProxy::HttpProxy) {
+ if (auto *abSocket = qobject_cast<QAbstractSocket *>(socket);
+ abSocket && abSocket->proxy().type() == QNetworkProxy::HttpProxy) {
// Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
QByteArray value;
// ensureConnection is called before any request has been assigned, but can also be
@@ -353,9 +379,11 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
value = request.headerField("user-agent");
}
if (!value.isEmpty()) {
- QNetworkProxy proxy(socket->proxy());
- proxy.setRawHeader("User-Agent", value); //detaches
- socket->setProxy(proxy);
+ QNetworkProxy proxy(abSocket->proxy());
+ auto h = proxy.headers();
+ h.replaceOrAppend(QHttpHeaders::WellKnownHeader::UserAgent, value);
+ proxy.setHeaders(std::move(h));
+ abSocket->setProxy(proxy);
}
}
#endif
@@ -378,7 +406,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
// limit the socket read buffer size. we will read everything into
// the QHttpNetworkReply anyway, so let's grow only that and not
// here and there.
- socket->setReadBufferSize(64*1024);
+ sslSocket->setReadBufferSize(64*1024);
#else
// Need to dequeue the request so that we can emit the error.
if (!reply)
@@ -392,17 +420,24 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
&& connection->cacheProxy().type() == QNetworkProxy::NoProxy
&& connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
#endif
- socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered, networkLayerPreference);
- // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
- socket->setReadBufferSize(1*1024);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket)) {
+ s->connectToHost(connectHost, connectPort,
+ QIODevice::ReadWrite | QIODevice::Unbuffered,
+ networkLayerPreference);
+ // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
+ s->setReadBufferSize(1 * 1024);
+ } else if (auto *s = qobject_cast<QLocalSocket *>(socket)) {
+ s->connectToServer(connectHost);
+ }
#ifndef QT_NO_NETWORKPROXY
} else {
- socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
-
+ auto *s = qobject_cast<QAbstractSocket *>(socket);
+ Q_ASSERT(s);
// limit the socket read buffer size. we will read everything into
// the QHttpNetworkReply anyway, so let's grow only that and not
// here and there.
- socket->setReadBufferSize(64*1024);
+ s->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
+ s->setReadBufferSize(64 * 1024);
}
#endif
}
@@ -505,7 +540,7 @@ void QHttpNetworkConnectionChannel::allDone()
// move next from pipeline to current request
if (!alreadyPipelinedRequests.isEmpty()) {
- if (resendCurrent || connectionCloseEnabled || socket->state() != QAbstractSocket::ConnectedState) {
+ if (resendCurrent || connectionCloseEnabled || QSocketAbstraction::socketState(socket) != QAbstractSocket::ConnectedState) {
// move the pipelined ones back to the main queue
requeueCurrentlyPipelinedRequests();
close();
@@ -536,7 +571,7 @@ void QHttpNetworkConnectionChannel::allDone()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
} else if (alreadyPipelinedRequests.isEmpty()) {
if (connectionCloseEnabled)
- if (socket->state() != QAbstractSocket::UnconnectedState)
+ if (QSocketAbstraction::socketState(socket) != QAbstractSocket::UnconnectedState)
close();
if (qobject_cast<QHttpNetworkConnection*>(connection))
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@@ -554,7 +589,7 @@ void QHttpNetworkConnectionChannel::detectPipeliningSupport()
// check for not having connection close
&& (!reply->d_func()->isConnectionCloseEnabled())
// check if it is still connected
- && (socket->state() == QAbstractSocket::ConnectedState)
+ && (QSocketAbstraction::socketState(socket) == QAbstractSocket::ConnectedState)
// check for broken servers in server reply header
// this is adapted from http://mxr.mozilla.org/firefox/ident?i=SupportsPipelining
&& (serverHeaderField = reply->headerField("Server"), !serverHeaderField.contains("Microsoft-IIS/4."))
@@ -677,8 +712,8 @@ bool QHttpNetworkConnectionChannel::resetUploadData()
void QHttpNetworkConnectionChannel::setProxy(const QNetworkProxy &networkProxy)
{
- if (socket)
- socket->setProxy(networkProxy);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket))
+ s->setProxy(networkProxy);
proxy = networkProxy;
}
@@ -839,7 +874,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
}
-void QHttpNetworkConnectionChannel::_q_connected()
+void QHttpNetworkConnectionChannel::_q_connected_abstract_socket(QAbstractSocket *absSocket)
{
// For the Happy Eyeballs we need to check if this is the first channel to connect.
if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::HostLookupPending || connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4or6) {
@@ -850,7 +885,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
else if (networkLayerPreference == QAbstractSocket::IPv6Protocol)
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
else {
- if (socket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
+ if (absSocket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
else
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
@@ -873,7 +908,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
}
// improve performance since we get the request sent by the kernel ASAP
- //socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
+ //absSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
// We have this commented out now. It did not have the effect we wanted. If we want to
// do this properly, Qt has to combine multiple HTTP requests into one buffer
// and send this to the kernel in one syscall and then the kernel immediately sends
@@ -882,7 +917,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
// the requests into one TCP packet.
// not sure yet if it helps, but it makes sense
- socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
+ absSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
@@ -891,7 +926,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
if (!connectionPrivate->connectionMonitor.isMonitoring()) {
// Now that we have a pair of addresses, we can start monitoring the
// connection status to handle its loss properly.
- if (connectionPrivate->connectionMonitor.setTargets(socket->localAddress(), socket->peerAddress()))
+ if (connectionPrivate->connectionMonitor.setTargets(absSocket->localAddress(), absSocket->peerAddress()))
connectionPrivate->connectionMonitor.startMonitoring();
}
}
@@ -903,7 +938,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
if (!connection->sslContext()) {
// this socket is making the 1st handshake for this connection,
// we need to set the SSL context so new sockets can reuse it
- if (auto socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(socket)))
+ if (auto socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(absSocket)))
connection->setSslContext(std::move(socketSslContext));
}
#endif
@@ -925,7 +960,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
switchedToHttp2 = false;
if (!reply)
- connection->d_func()->dequeueRequest(socket);
+ connection->d_func()->dequeueRequest(absSocket);
if (reply) {
if (tryProtocolUpgrade) {
@@ -938,6 +973,22 @@ void QHttpNetworkConnectionChannel::_q_connected()
}
}
+void QHttpNetworkConnectionChannel::_q_connected_local_socket(QLocalSocket *localSocket)
+{
+ state = QHttpNetworkConnectionChannel::IdleState;
+ if (!reply) // No reply object, try to dequeue a request (which is paired with a reply):
+ connection->d_func()->dequeueRequest(localSocket);
+ if (reply)
+ sendRequest();
+}
+
+void QHttpNetworkConnectionChannel::_q_connected()
+{
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket))
+ _q_connected_abstract_socket(s);
+ else if (auto *s = qobject_cast<QLocalSocket *>(socket))
+ _q_connected_local_socket(s);
+}
void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
{
@@ -1114,7 +1165,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
//signal emission triggered event loop
if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
- else if (socket->state() == QAbstractSocket::UnconnectedState)
+ else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState;
else
state = QHttpNetworkConnectionChannel::ClosingState;
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index c42290feca..853b647ecc 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -19,6 +19,7 @@
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkreply.h>
#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qlocalsocket.h>
#include <private/qobject_p.h>
#include <qauthenticator.h>
@@ -71,7 +72,7 @@ public:
ClosingState = 16,
BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|ClosingState)
};
- QAbstractSocket *socket;
+ QIODevice *socket;
bool ssl;
bool isInitialized;
ChannelState state;
@@ -156,6 +157,8 @@ public:
void _q_bytesWritten(qint64 bytes); // proceed sending
void _q_readyRead(); // pending data to read
void _q_disconnected(); // disconnected from host
+ void _q_connected_abstract_socket(QAbstractSocket *socket);
+ void _q_connected_local_socket(QLocalSocket *socket);
void _q_connected(); // start sending request
void _q_error(QAbstractSocket::SocketError); // error from socket
#ifndef QT_NO_NETWORKPROXY
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 6d82e81322..5711c96b18 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -378,7 +378,7 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
}
}
-qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
+qint64 QHttpNetworkReplyPrivate::readStatus(QIODevice *socket)
{
if (fragment.isEmpty()) {
// reserve bytes for the status line. This is better than always append() which reallocs the byte array
@@ -432,7 +432,7 @@ bool QHttpNetworkReplyPrivate::parseStatus(QByteArrayView status)
return parser.parseStatus(status);
}
-qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
+qint64 QHttpNetworkReplyPrivate::readHeader(QIODevice *socket)
{
if (fragment.isEmpty()) {
// according to http://dev.opera.com/articles/view/mama-http-headers/ the average size of the header
@@ -516,7 +516,7 @@ bool QHttpNetworkReplyPrivate::isConnectionCloseEnabled()
// note this function can only be used for non-chunked, non-compressed with
// known content length
-qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char *b)
+qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QIODevice *socket, char *b)
{
// This first read is to flush the buffer inside the socket
qint64 haveRead = 0;
@@ -535,7 +535,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char
// note this function can only be used for non-chunked, non-compressed with
// known content length
-qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb)
+qint64 QHttpNetworkReplyPrivate::readBodyFast(QIODevice *socket, QByteDataBuffer *rb)
{
qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
@@ -565,7 +565,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteData
}
-qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuffer *out)
+qint64 QHttpNetworkReplyPrivate::readBody(QIODevice *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
@@ -585,7 +585,7 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuff
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByteDataBuffer *out, qint64 size)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *socket, QByteDataBuffer *out, qint64 size)
{
// FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
qint64 bytes = 0;
@@ -618,7 +618,7 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByte
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, QByteDataBuffer *out)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
while (socket->bytesAvailable()) {
@@ -680,7 +680,7 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, Q
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *chunkSize)
+qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *socket, qint64 *chunkSize)
{
qint64 bytes = 0;
char crlf[2];
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index c1b155caa7..caec82bd7e 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -172,20 +172,20 @@ class Q_AUTOTEST_EXPORT QHttpNetworkReplyPrivate : public QObjectPrivate, public
public:
QHttpNetworkReplyPrivate(const QUrl &newUrl = QUrl());
~QHttpNetworkReplyPrivate();
- qint64 readStatus(QAbstractSocket *socket);
+ qint64 readStatus(QIODevice *socket);
bool parseStatus(QByteArrayView status);
- qint64 readHeader(QAbstractSocket *socket);
+ qint64 readHeader(QIODevice *socket);
void parseHeader(QByteArrayView header);
void appendHeaderField(const QByteArray &name, const QByteArray &data);
- qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out);
- qint64 readBodyVeryFast(QAbstractSocket *socket, char *b);
- qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb);
+ qint64 readBody(QIODevice *socket, QByteDataBuffer *out);
+ qint64 readBodyVeryFast(QIODevice *socket, char *b);
+ qint64 readBodyFast(QIODevice *socket, QByteDataBuffer *rb);
void clear();
void clearHttpLayerInformation();
- qint64 readReplyBodyRaw(QAbstractSocket *in, QByteDataBuffer *out, qint64 size);
- qint64 readReplyBodyChunked(QAbstractSocket *in, QByteDataBuffer *out);
- qint64 getChunkSize(QAbstractSocket *in, qint64 *chunkSize);
+ qint64 readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size);
+ qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out);
+ qint64 getChunkSize(QIODevice *in, qint64 *chunkSize);
bool isRedirecting() const;
bool shouldEmitSignals();
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index 28eab03890..fb584eb9cc 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -5,6 +5,7 @@
#include <private/qhttpprotocolhandler_p.h>
#include <private/qnoncontiguousbytedevice_p.h>
#include <private/qhttpnetworkconnectionchannel_p.h>
+#include <private/qsocketabstraction_p.h>
QT_BEGIN_NAMESPACE
@@ -34,10 +35,8 @@ void QHttpProtocolHandler::_q_receiveReply()
return;
}
- QAbstractSocket::SocketState socketState = m_socket->state();
-
// connection might be closed to signal the end of data
- if (socketState == QAbstractSocket::UnconnectedState) {
+ if (QSocketAbstraction::socketState(m_socket) == QAbstractSocket::UnconnectedState) {
if (m_socket->bytesAvailable() <= 0) {
if (m_reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
// finish this reply. this case happens when the server did not send a content length
@@ -115,7 +114,7 @@ void QHttpProtocolHandler::_q_receiveReply()
}
case QHttpNetworkReplyPrivate::ReadingDataState: {
QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
- if (m_socket->state() == QAbstractSocket::ConnectedState &&
+ if (QSocketAbstraction::socketState(m_socket) == QAbstractSocket::ConnectedState &&
replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
// (only do the following when still connected, not when we have already been disconnected and there is still data)
// We already have some HTTP body data. We don't read more from the socket until
@@ -193,7 +192,8 @@ void QHttpProtocolHandler::_q_receiveReply()
void QHttpProtocolHandler::_q_readyRead()
{
- if (m_socket->state() == QAbstractSocket::ConnectedState && m_socket->bytesAvailable() == 0) {
+ if (QSocketAbstraction::socketState(m_socket) == QAbstractSocket::ConnectedState
+ && m_socket->bytesAvailable() == 0) {
// We got a readyRead but no bytes are available..
// This happens for the Unbuffered QTcpSocket
// Also check if socket is in ConnectedState since
@@ -201,7 +201,7 @@ void QHttpProtocolHandler::_q_readyRead()
char c;
qint64 ret = m_socket->peek(&c, 1);
if (ret < 0) {
- m_channel->_q_error(m_socket->error());
+ m_channel->_q_error(QSocketAbstraction::socketError(m_socket));
// We still need to handle the reply so it emits its signals etc.
if (m_reply)
_q_receiveReply();
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index b0ae0dcf44..7dddd1369e 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -95,7 +95,9 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy, const QString &p
QUrl copy = url;
QString scheme = copy.scheme();
bool isEncrypted = scheme == "https"_L1 || scheme == "preconnect-https"_L1;
- copy.setPort(copy.port(isEncrypted ? 443 : 80));
+ const bool isLocalSocket = scheme.startsWith("unix"_L1);
+ if (!isLocalSocket)
+ copy.setPort(copy.port(isEncrypted ? 443 : 80));
if (scheme == "preconnect-http"_L1)
copy.setScheme("http"_L1);
else if (scheme == "preconnect-https"_L1)
@@ -145,9 +147,9 @@ class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection,
{
// Q_OBJECT
public:
- QNetworkAccessCachedHttpConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt,
+ QNetworkAccessCachedHttpConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt, bool isLocalSocket,
QHttpNetworkConnection::ConnectionType connectionType)
- : QHttpNetworkConnection(connectionCount, hostName, port, encrypt, /*parent=*/nullptr, connectionType)
+ : QHttpNetworkConnection(connectionCount, hostName, port, encrypt, isLocalSocket, /*parent=*/nullptr, connectionType)
{
setExpires(true);
setShareable(true);
@@ -244,7 +246,9 @@ void QHttpThreadDelegate::startRequest()
// check if we have an open connection to this host
QUrl urlCopy = httpRequest.url();
- urlCopy.setPort(urlCopy.port(ssl ? 443 : 80));
+ const bool isLocalSocket = urlCopy.scheme().startsWith("unix"_L1);
+ if (!isLocalSocket)
+ urlCopy.setPort(urlCopy.port(ssl ? 443 : 80));
QHttpNetworkConnection::ConnectionType connectionType
= httpRequest.isHTTP2Allowed() ? QHttpNetworkConnection::ConnectionTypeHTTP2
@@ -279,7 +283,10 @@ void QHttpThreadDelegate::startRequest()
} else
#endif // QT_CONFIG(ssl)
{
- urlCopy.setScheme(QStringLiteral("h2"));
+ if (isLocalSocket)
+ urlCopy.setScheme(QStringLiteral("unix+h2"));
+ else
+ urlCopy.setScheme(QStringLiteral("h2"));
}
}
@@ -297,8 +304,9 @@ void QHttpThreadDelegate::startRequest()
if (!httpConnection) {
// no entry in cache; create an object
// the http object is actually a QHttpNetworkConnection
- httpConnection = new QNetworkAccessCachedHttpConnection(http1Parameters.numberOfConnectionsPerHost(), urlCopy.host(), urlCopy.port(), ssl,
- connectionType);
+ httpConnection = new QNetworkAccessCachedHttpConnection(
+ http1Parameters.numberOfConnectionsPerHost(), urlCopy.host(), urlCopy.port(), ssl,
+ isLocalSocket, connectionType);
if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
httpConnection->setHttp2Parameters(http2Parameters);
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index 5dbcef4bbe..3c7fee567d 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -568,6 +568,43 @@ void QNetworkAccessBackend::setRawHeader(const QByteArray &header, const QByteAr
}
/*!
+ \since 6.8
+
+ Returns headers that are set in this QNetworkAccessBackend instance.
+
+ \sa setHeaders()
+*/
+QHttpHeaders QNetworkAccessBackend::headers() const
+{
+ return d_func()->m_reply->headers();
+}
+
+/*!
+ \since 6.8
+
+ Sets \a newHeaders as headers, overriding any previously set headers.
+
+ These headers are accessible on the QNetworkReply instance which was
+ returned when calling one of the appropriate functions on
+ QNetworkAccessManager.
+
+ \sa headers()
+*/
+void QNetworkAccessBackend::setHeaders(QHttpHeaders &&newHeaders)
+{
+ d_func()->m_reply->setHeaders(std::move(newHeaders));
+}
+
+/*!
+ \overload
+ \since 6.8
+*/
+void QNetworkAccessBackend::setHeaders(const QHttpHeaders &newHeaders)
+{
+ d_func()->m_reply->setHeaders(newHeaders);
+}
+
+/*!
Returns the operation which was requested when calling
QNetworkAccessManager.
*/
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index 799ae3faad..4f8d7e4372 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -104,6 +104,9 @@ public:
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
QByteArray rawHeader(const QByteArray &header) const;
void setRawHeader(const QByteArray &header, const QByteArray &value);
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
QNetworkAccessManager::Operation operation() const;
bool isCachingEnabled() const;
diff --git a/src/network/access/qnetworkaccesscachebackend.cpp b/src/network/access/qnetworkaccesscachebackend.cpp
index fd8174c143..ead5fe2ef5 100644
--- a/src/network/access/qnetworkaccesscachebackend.cpp
+++ b/src/network/access/qnetworkaccesscachebackend.cpp
@@ -47,21 +47,21 @@ bool QNetworkAccessCacheBackend::sendCacheContents()
return false;
QNetworkCacheMetaData::AttributesMap attributes = item.attributes();
- setAttribute(QNetworkRequest::HttpStatusCodeAttribute, attributes.value(QNetworkRequest::HttpStatusCodeAttribute));
- setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute));
-
- // set the raw headers
- const QNetworkCacheMetaData::RawHeaderList rawHeaders = item.rawHeaders();
- for (const auto &header : rawHeaders) {
- if (header.first.compare("cache-control", Qt::CaseInsensitive) == 0) {
- const QLatin1StringView cacheControlValue(header.second);
- if (cacheControlValue.contains("must-revalidate"_L1, Qt::CaseInsensitive)
- || cacheControlValue.contains("no-cache"_L1, Qt::CaseInsensitive)) {
- return false;
- }
- }
- setRawHeader(header.first, header.second);
+ setAttribute(QNetworkRequest::HttpStatusCodeAttribute,
+ attributes.value(QNetworkRequest::HttpStatusCodeAttribute));
+ setAttribute(QNetworkRequest::HttpReasonPhraseAttribute,
+ attributes.value(QNetworkRequest::HttpReasonPhraseAttribute));
+
+ // set the headers
+ auto headers = item.headers();
+ const auto cacheControlValue = QLatin1StringView(
+ headers.value(QHttpHeaders::WellKnownHeader::CacheControl));
+ // RFC 9111 Section 5.2 Cache Control
+ if (cacheControlValue.contains("must-revalidate"_L1, Qt::CaseInsensitive)
+ || cacheControlValue.contains("no-cache"_L1, Qt::CaseInsensitive)) {
+ return false;
}
+ setHeaders(std::move(headers));
// handle a possible redirect
QVariant redirectionTarget = attributes.value(QNetworkRequest::RedirectionTargetAttribute);
diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp
index 4b12f9fe31..e0a89e3646 100644
--- a/src/network/access/qnetworkaccessdebugpipebackend.cpp
+++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp
@@ -97,7 +97,9 @@ qint64 QNetworkAccessDebugPipeBackend::read(char *data, qint64 maxlen)
if (haveRead == -1) {
hasDownloadFinished = true;
// this ensures a good last downloadProgress is emitted
- setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
+ auto h = headers();
+ h.removeAll(QHttpHeaders::WellKnownHeader::ContentLength);
+ setHeaders(std::move(h));
possiblyFinish();
return haveRead;
}
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 4e13c9924b..ae99721758 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -1220,6 +1220,13 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
bool isLocalFile = req.url().isLocalFile();
QString scheme = req.url().scheme();
+ // Remap local+http to unix+http to make further processing easier
+ if (scheme == "local+http"_L1) {
+ scheme = u"unix+http"_s;
+ QUrl url = req.url();
+ url.setScheme(scheme);
+ req.setUrl(url);
+ }
// fast path for GET on file:// URLs
// The QNetworkAccessFileBackend will right now only be used for PUT
@@ -1255,12 +1262,14 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
}
}
QNetworkRequest request = req;
+ auto h = request.headers();
#ifndef Q_OS_WASM // Content-length header is not allowed to be set by user in wasm
- if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
+ if (!h.contains(QHttpHeaders::WellKnownHeader::ContentLength) &&
outgoingData && !outgoingData->isSequential()) {
// request has no Content-Length
// but the data that is outgoing is random-access
- request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
+ h.append(QHttpHeaders::WellKnownHeader::ContentLength,
+ QByteArray::number(outgoingData->size()));
}
#endif
if (static_cast<QNetworkRequest::LoadControl>
@@ -1269,9 +1278,11 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
if (d->cookieJar) {
QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
if (!cookies.isEmpty())
- request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies));
+ h.replaceOrAppend(QHttpHeaders::WellKnownHeader::Cookie,
+ QNetworkHeadersPrivate::fromCookieList(cookies));
}
}
+ request.setHeaders(std::move(h));
#ifdef Q_OS_WASM
Q_UNUSED(isLocalFile);
// Support http, https, and relative urls
@@ -1292,11 +1303,15 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
u"https",
u"preconnect-https",
#endif
+ u"unix+http",
};
// Since Qt 5 we use the new QNetworkReplyHttpImpl
if (std::find(std::begin(httpSchemes), std::end(httpSchemes), scheme) != std::end(httpSchemes)) {
+
#ifndef QT_NO_SSL
- if (isStrictTransportSecurityEnabled() && d->stsCache.isKnownHost(request.url())) {
+ const bool isLocalSocket = scheme.startsWith("unix"_L1);
+ if (!isLocalSocket && isStrictTransportSecurityEnabled()
+ && d->stsCache.isKnownHost(request.url())) {
QUrl stsUrl(request.url());
// RFC6797, 8.3:
// The UA MUST replace the URI scheme with "https" [RFC2818],
@@ -1387,6 +1402,8 @@ QStringList QNetworkAccessManager::supportedSchemesImplementation() const
// Those ones don't exist in backends
#if QT_CONFIG(http)
schemes << QStringLiteral("http");
+ schemes << QStringLiteral("unix+http");
+ schemes << QStringLiteral("local+http");
#ifndef QT_NO_SSL
if (QSslSocket::supportsSsl())
schemes << QStringLiteral("https");
@@ -1746,9 +1763,10 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
{
// copy the request, we probably need to add some headers
QNetworkRequest newRequest(request);
+ auto h = newRequest.headers();
// add Content-Type header if not there already
- if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
+ if (!h.contains(QHttpHeaders::WellKnownHeader::ContentType)) {
QByteArray contentType;
contentType.reserve(34 + multiPart->d_func()->boundary.size());
contentType += "multipart/";
@@ -1768,14 +1786,15 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
}
// putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
- newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
+ h.append(QHttpHeaders::WellKnownHeader::ContentType, contentType);
}
// add MIME-Version header if not there already (we must include the header
// if the message conforms to RFC 2045, see section 4 of that RFC)
- auto mimeHeader = "MIME-Version"_ba;
- if (!request.hasRawHeader(mimeHeader))
- newRequest.setRawHeader(mimeHeader, "1.0"_ba);
+ if (!h.contains(QHttpHeaders::WellKnownHeader::MIMEVersion))
+ h.append(QHttpHeaders::WellKnownHeader::MIMEVersion, "1.0"_ba);
+
+ newRequest.setHeaders(std::move(h));
QIODevice *device = multiPart->d_func()->device;
if (!device->isReadable()) {
diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp
index c883a61886..b39924025e 100644
--- a/src/network/access/qnetworkdiskcache.cpp
+++ b/src/network/access/qnetworkdiskcache.cpp
@@ -154,15 +154,11 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData)
return nullptr;
}
- const auto headers = metaData.rawHeaders();
- for (const auto &header : headers) {
- if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) {
- const qint64 size = header.second.toLongLong();
- if (size > (maximumCacheSize() * 3)/4)
- return nullptr;
- break;
- }
- }
+ const auto sizeValue = metaData.headers().value(QHttpHeaders::WellKnownHeader::ContentLength);
+ const qint64 size = sizeValue.toLongLong();
+ if (size > (maximumCacheSize() * 3)/4)
+ return nullptr;
+
std::unique_ptr<QCacheItem> cacheItem = std::make_unique<QCacheItem>();
cacheItem->metaData = metaData;
@@ -578,31 +574,27 @@ QString QNetworkDiskCachePrivate::cacheFileName(const QUrl &url) const
*/
bool QCacheItem::canCompress() const
{
- bool sizeOk = false;
- bool typeOk = false;
- const auto headers = metaData.rawHeaders();
- for (const auto &header : headers) {
- if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) {
- qint64 size = header.second.toLongLong();
- if (size > MAX_COMPRESSION_SIZE)
- return false;
- else
- sizeOk = true;
- }
+ const auto h = metaData.headers();
- if (header.first.compare("content-type", Qt::CaseInsensitive) == 0) {
- QByteArray type = header.second;
- if (type.startsWith("text/")
- || (type.startsWith("application/")
- && (type.endsWith("javascript") || type.endsWith("ecmascript"))))
- typeOk = true;
- else
- return false;
- }
- if (sizeOk && typeOk)
- return true;
+ const auto sizeValue = h.value(QHttpHeaders::WellKnownHeader::ContentLength);
+ if (sizeValue.empty())
+ return false;
+
+ qint64 size = sizeValue.toLongLong();
+ if (size > MAX_COMPRESSION_SIZE)
+ return false;
+
+ const auto type = h.value(QHttpHeaders::WellKnownHeader::ContentType);
+ if (!type.empty())
+ return false;
+
+ if (!type.startsWith("text/")
+ && !(type.startsWith("application/")
+ && (type.endsWith("javascript") || type.endsWith("ecmascript")))) {
+ return false;
}
- return false;
+
+ return true;
}
enum
@@ -673,7 +665,7 @@ bool QCacheItem::read(QFileDevice *device, bool readData)
if (!device->fileName().endsWith(expectedFilename))
return false;
- return metaData.isValid() && !metaData.rawHeaders().isEmpty();
+ return metaData.isValid() && !metaData.headers().isEmpty();
}
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkfile.cpp b/src/network/access/qnetworkfile.cpp
index bfedf044de..fb9ce8232d 100644
--- a/src/network/access/qnetworkfile.cpp
+++ b/src/network/access/qnetworkfile.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkfile_p.h"
+#include "qnetworkrequest_p.h"
#include <QtCore/QDebug>
#include <QNetworkReply>
@@ -31,8 +32,10 @@ void QNetworkFile::open()
"Cannot open %1: Path is a directory").arg(fileName());
emit error(QNetworkReply::ContentOperationNotPermittedError, msg);
} else {
- emit headerRead(QNetworkRequest::LastModifiedHeader, QVariant::fromValue(fi.lastModified()));
- emit headerRead(QNetworkRequest::ContentLengthHeader, QVariant::fromValue(fi.size()));
+ emit headerRead(QHttpHeaders::WellKnownHeader::LastModified,
+ QNetworkHeadersPrivate::toHttpDate(fi.lastModified()));
+ emit headerRead(QHttpHeaders::WellKnownHeader::ContentLength,
+ QByteArray::number(fi.size()));
opened = QFile::open(QIODevice::ReadOnly | QIODevice::Unbuffered);
if (!opened) {
QString msg = QCoreApplication::translate("QNetworkAccessFileBackend",
diff --git a/src/network/access/qnetworkfile_p.h b/src/network/access/qnetworkfile_p.h
index df772251b4..9dcb63711e 100644
--- a/src/network/access/qnetworkfile_p.h
+++ b/src/network/access/qnetworkfile_p.h
@@ -35,7 +35,7 @@ public Q_SLOTS:
Q_SIGNALS:
void finished(bool ok);
- void headerRead(QNetworkRequest::KnownHeaders header, const QVariant &value);
+ void headerRead(QHttpHeaders::WellKnownHeader, const QByteArray &value);
void error(QNetworkReply::NetworkError error, const QString &message);
};
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 9334b01de6..3301ae85d2 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -617,7 +617,7 @@ QVariant QNetworkReply::header(QNetworkRequest::KnownHeaders header) const
bool QNetworkReply::hasRawHeader(QAnyStringView headerName) const
{
Q_D(const QNetworkReply);
- return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
+ return d->headers().contains(headerName);
}
/*!
@@ -633,9 +633,7 @@ bool QNetworkReply::hasRawHeader(QAnyStringView headerName) const
QByteArray QNetworkReply::rawHeader(QAnyStringView headerName) const
{
Q_D(const QNetworkReply);
- if (const auto it = d->findRawHeader(headerName); it != d->rawHeaders.constEnd())
- return it->second;
- return QByteArray();
+ return d->rawHeader(headerName);
}
/*! \typedef QNetworkReply::RawHeaderPair
@@ -650,7 +648,20 @@ QByteArray QNetworkReply::rawHeader(QAnyStringView headerName) const
const QList<QNetworkReply::RawHeaderPair>& QNetworkReply::rawHeaderPairs() const
{
Q_D(const QNetworkReply);
- return d->rawHeaders;
+ return d->allRawHeaders();
+}
+
+/*!
+ \since 6.8
+
+ Returns headers that were sent by the remote server.
+
+ \sa setHeaders(), QNetworkRequest::setAttribute(), QNetworkRequest::Attribute
+*/
+QHttpHeaders QNetworkReply::headers() const
+{
+ Q_D(const QNetworkReply);
+ return d->headers();
}
/*!
@@ -888,6 +899,45 @@ void QNetworkReply::setUrl(const QUrl &url)
}
/*!
+ \since 6.8
+
+ Sets \a newHeaders as headers in this network reply, overriding
+ any previously set headers.
+
+ If some headers correspond to the known headers, they will be
+ parsed and the corresponding parsed form will also be set.
+
+ \sa headers(), QNetworkRequest::KnownHeaders
+*/
+void QNetworkReply::setHeaders(const QHttpHeaders &newHeaders)
+{
+ Q_D(QNetworkReply);
+ d->setHeaders(newHeaders);
+}
+
+/*!
+ \overload
+ \since 6.8
+*/
+void QNetworkReply::setHeaders(QHttpHeaders &&newHeaders)
+{
+ Q_D(QNetworkReply);
+ d->setHeaders(std::move(newHeaders));
+}
+
+/*!
+ \since 6.8
+
+ Sets the header \a name to be of value \a value. If \a
+ name was previously set, it is overridden.
+*/
+void QNetworkReply::setWellKnownHeader(QHttpHeaders::WellKnownHeader name, const QByteArray &value)
+{
+ Q_D(QNetworkReply);
+ d->setHeader(name, value);
+}
+
+/*!
Sets the known header \a header to be of value \a value. The
corresponding raw form of the header will be set as well.
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index 390a6f2f51..48ec0397c6 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -109,6 +109,7 @@ public:
typedef QPair<QByteArray, QByteArray> RawHeaderPair;
const QList<RawHeaderPair>& rawHeaderPairs() const;
+ QHttpHeaders headers() const;
// attributes
QVariant attribute(QNetworkRequest::Attribute code) const;
@@ -152,6 +153,9 @@ protected:
void setUrl(const QUrl &url);
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
void setRawHeader(const QByteArray &headerName, const QByteArray &value);
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+ void setWellKnownHeader(QHttpHeaders::WellKnownHeader name, const QByteArray &value);
void setAttribute(QNetworkRequest::Attribute code, const QVariant &value);
#if QT_CONFIG(ssl)
diff --git a/src/network/access/qnetworkreplydataimpl.cpp b/src/network/access/qnetworkreplydataimpl.cpp
index 7cb7621bca..006cfd57cb 100644
--- a/src/network/access/qnetworkreplydataimpl.cpp
+++ b/src/network/access/qnetworkreplydataimpl.cpp
@@ -36,8 +36,11 @@ QNetworkReplyDataImpl::QNetworkReplyDataImpl(QObject *parent, const QNetworkRequ
QByteArray payload;
if (qDecodeDataUrl(url, mimeType, payload)) {
qint64 size = payload.size();
- setHeader(QNetworkRequest::ContentTypeHeader, mimeType);
- setHeader(QNetworkRequest::ContentLengthHeader, size);
+ auto h = headers();
+ h.replaceOrAppend(QHttpHeaders::WellKnownHeader::ContentType, mimeType);
+ h.replaceOrAppend(QHttpHeaders::WellKnownHeader::ContentLength, QByteArray::number(size));
+ setHeaders(std::move(h));
+
QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection);
d->decodedData.setData(payload);
diff --git a/src/network/access/qnetworkreplyfileimpl.cpp b/src/network/access/qnetworkreplyfileimpl.cpp
index e6208a5c85..bad0bb7b0a 100644
--- a/src/network/access/qnetworkreplyfileimpl.cpp
+++ b/src/network/access/qnetworkreplyfileimpl.cpp
@@ -85,7 +85,7 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con
if (req.attribute(QNetworkRequest::BackgroundRequestAttribute).toBool()) { // Asynchronous open
auto realFile = new QNetworkFile(fileName);
- connect(realFile, &QNetworkFile::headerRead, this, &QNetworkReplyFileImpl::setHeader,
+ connect(realFile, &QNetworkFile::headerRead, this, &QNetworkReplyFileImpl::setWellKnownHeader,
Qt::QueuedConnection);
connect(realFile, &QNetworkFile::error, this, &QNetworkReplyFileImpl::setError,
Qt::QueuedConnection);
@@ -128,8 +128,12 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con
QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
return;
}
- setHeader(QNetworkRequest::LastModifiedHeader, fi.lastModified());
- setHeader(QNetworkRequest::ContentLengthHeader, fi.size());
+ auto h = headers();
+ h.replaceOrAppend(QHttpHeaders::WellKnownHeader::LastModified,
+ QNetworkHeadersPrivate::toHttpDate(fi.lastModified()));
+ h.replaceOrAppend(QHttpHeaders::WellKnownHeader::ContentLength,
+ QByteArray::number(fi.size()));
+ setHeaders(std::move(h));
QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection);
QMetaObject::invokeMethod(this, "downloadProgress", Qt::QueuedConnection,
@@ -171,9 +175,9 @@ bool QNetworkReplyFileImpl::isSequential () const
qint64 QNetworkReplyFileImpl::size() const
{
- bool ok;
- int size = header(QNetworkRequest::ContentLengthHeader).toInt(&ok);
- return ok ? size : 0;
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
+ return totalSizeOpt.value_or(0);
}
/*!
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 1eee98f834..b4aca940a7 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -202,7 +202,10 @@ QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manage
if (bufferingDisallowed) {
// if a valid content-length header for the request was supplied, we can disable buffering
// if not, we will buffer anyway
- if (request.header(QNetworkRequest::ContentLengthHeader).isValid()) {
+
+ const auto sizeOpt = QNetworkHeadersPrivate::toInt(
+ request.headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
+ if (sizeOpt) {
QMetaObject::invokeMethod(this, "_q_startOperation", Qt::QueuedConnection);
// FIXME make direct call?
} else {
@@ -478,10 +481,12 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
{
QNetworkRequest::CacheLoadControl CacheLoadControlAttribute =
(QNetworkRequest::CacheLoadControl)request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt();
+
+ auto requestHeaders = request.headers();
if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork) {
// If the request does not already specify preferred cache-control
// force reload from the network and tell any caching proxy servers to reload too
- if (!request.rawHeaderList().contains(cacheControlName())) {
+ if (!requestHeaders.contains(QHttpHeaders::WellKnownHeader::CacheControl)) {
const auto noCache = "no-cache"_ba;
httpRequest.setHeaderField(cacheControlName(), noCache);
httpRequest.setHeaderField("Pragma"_ba, noCache);
@@ -491,7 +496,7 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
// The disk cache API does not currently support partial content retrieval.
// That is why we don't use the disk cache for any such requests.
- if (request.hasRawHeader(rangeName()))
+ if (requestHeaders.contains(QHttpHeaders::WellKnownHeader::Range))
return false;
QAbstractNetworkCache *nc = managerPrivate->networkCache;
@@ -505,28 +510,27 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
if (!metaData.saveToDisk())
return false;
- QNetworkHeadersPrivate cacheHeaders;
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
- cacheHeaders.setAllRawHeaders(metaData.rawHeaders());
+ QHttpHeaders cacheHeaders = metaData.headers();
- it = cacheHeaders.findRawHeader("content-length");
- if (it != cacheHeaders.rawHeaders.constEnd()) {
+ const auto sizeOpt = QNetworkHeadersPrivate::toInt(
+ cacheHeaders.value(QHttpHeaders::WellKnownHeader::ContentLength));
+ if (sizeOpt) {
std::unique_ptr<QIODevice> data(nc->data(httpRequest.url()));
- if (!data || data->size() < it->second.toLongLong())
+ if (!data || data->size() < sizeOpt.value())
return false; // The data is smaller than the content-length specified
}
- it = cacheHeaders.findRawHeader("etag");
- if (it != cacheHeaders.rawHeaders.constEnd())
- httpRequest.setHeaderField("If-None-Match"_ba, it->second);
+ auto value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::ETag);
+ if (!value.empty())
+ httpRequest.setHeaderField("If-None-Match"_ba, value.toByteArray());
QDateTime lastModified = metaData.lastModified();
if (lastModified.isValid())
httpRequest.setHeaderField("If-Modified-Since"_ba, QNetworkHeadersPrivate::toHttpDate(lastModified));
- it = cacheHeaders.findRawHeader(cacheControlName());
- if (it != cacheHeaders.rawHeaders.constEnd()) {
- QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second);
+ value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::CacheControl);
+ if (!value.empty()) {
+ QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(value);
if (cacheControl.contains("must-revalidate"_ba))
return false;
if (cacheControl.contains("no-cache"_ba))
@@ -553,16 +557,15 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
* now
* is the current (local) time
*/
- qint64 age_value = 0;
- it = cacheHeaders.findRawHeader("age");
- if (it != cacheHeaders.rawHeaders.constEnd())
- age_value = it->second.toLongLong();
+ const auto ageOpt = QNetworkHeadersPrivate::toInt(
+ cacheHeaders.value(QHttpHeaders::WellKnownHeader::Age));
+ const qint64 age_value = ageOpt.value_or(0);
QDateTime dateHeader;
qint64 date_value = 0;
- it = cacheHeaders.findRawHeader("date");
- if (it != cacheHeaders.rawHeaders.constEnd()) {
- dateHeader = QNetworkHeadersPrivate::fromHttpDate(it->second);
+ value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::Date);
+ if (!value.empty()) {
+ dateHeader = QNetworkHeadersPrivate::fromHttpDate(value);
date_value = dateHeader.toSecsSinceEpoch();
}
@@ -744,18 +747,17 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
break; // can't happen
}
- QList<QByteArray> headers = newHttpRequest.rawHeaderList();
+ QHttpHeaders newRequestHeaders = newHttpRequest.headers();
if (resumeOffset != 0) {
- const int rangeIndex = headers.indexOf(rangeName());
- if (rangeIndex != -1) {
+ if (newRequestHeaders.contains(QHttpHeaders::WellKnownHeader::Range)) {
// Need to adjust resume offset for user specified range
- headers.removeAt(rangeIndex);
-
// We've already verified that requestRange starts with "bytes=", see canResume.
- const auto rangeHeader = newHttpRequest.rawHeader(rangeName());
+ const auto rangeHeader = newRequestHeaders.value(QHttpHeaders::WellKnownHeader::Range);
const auto requestRange = QByteArrayView(rangeHeader).mid(bytesEqualPrefix().size());
+ newRequestHeaders.removeAll(QHttpHeaders::WellKnownHeader::Range);
+
int index = requestRange.indexOf('-');
quint64 requestStartOffset = requestRange.left(index).toULongLong();
@@ -771,8 +773,11 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
}
}
- for (const QByteArray &header : std::as_const(headers))
- httpRequest.setHeaderField(header, newHttpRequest.rawHeader(header));
+ for (int i = 0; i < newRequestHeaders.size(); i++) {
+ const auto name = newRequestHeaders.nameAt(i);
+ const auto value = newRequestHeaders.valueAt(i);
+ httpRequest.setHeaderField(QByteArray(name.data(), name.size()), value.toByteArray());
+ }
if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool())
httpRequest.setPipeliningAllowed(true);
@@ -1151,7 +1156,8 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d)
}
lastReadyReadEmittedSize = bytesDownloaded;
- QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
emit q->readyRead();
// emit readyRead before downloadProgress in case this will cause events to be
@@ -1159,8 +1165,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d)
if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval
&& (!decompressHelper.isValid() || decompressHelper.isCountingBytes())) {
downloadProgressSignalChoke.restart();
- emit q->downloadProgress(bytesDownloaded,
- totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ emit q->downloadProgress(bytesDownloaded, totalSizeOpt.value_or(-1));
}
}
@@ -1223,7 +1228,8 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
if (httpRequest.isFollowRedirects()) // update the reply's url as it could've changed
url = redirectUrl;
- if (managerPrivate->stsEnabled && managerPrivate->stsCache.isKnownHost(url)) {
+ const bool wasLocalSocket = schemeBefore.startsWith("unix"_L1);
+ if (!wasLocalSocket && managerPrivate->stsEnabled && managerPrivate->stsCache.isKnownHost(url)) {
// RFC6797, 8.3:
// The UA MUST replace the URI scheme with "https" [RFC2818],
// and if the URI contains an explicit port component of "80",
@@ -1237,9 +1243,12 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
url.setPort(443);
}
- const bool isLessSafe = schemeBefore == "https"_L1 && url.scheme() == "http"_L1;
- if (httpRequest.redirectPolicy() == QNetworkRequest::NoLessSafeRedirectPolicy
- && isLessSafe) {
+ // Just to be on the safe side for local sockets, any changes to the scheme
+ // are considered less safe
+ const bool changingLocalScheme = wasLocalSocket && url.scheme() != schemeBefore;
+ const bool isLessSafe = changingLocalScheme
+ || (schemeBefore == "https"_L1 && url.scheme() == "http"_L1);
+ if (httpRequest.redirectPolicy() == QNetworkRequest::NoLessSafeRedirectPolicy && isLessSafe) {
error(QNetworkReply::InsecureRedirectError,
QCoreApplication::translate("QHttp", "Insecure redirect"));
return;
@@ -1255,6 +1264,7 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
// Clear stale headers, the relevant ones get set again later
httpRequest.clearHeaders();
+ auto newHeaders = redirectRequest.headers();
if ((operation == QNetworkAccessManager::GetOperation
|| operation == QNetworkAccessManager::HeadOperation) && !getOperationKeepsBody) {
// possibly changed from not-GET/HEAD to GET/HEAD, make sure to get rid of upload device
@@ -1269,18 +1279,20 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
outgoingData = nullptr;
outgoingDataBuffer.reset();
// We need to explicitly unset these headers so they're not reapplied to the httpRequest
- redirectRequest.setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
- redirectRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
+ newHeaders.removeAll(QHttpHeaders::WellKnownHeader::ContentLength);
+ newHeaders.removeAll(QHttpHeaders::WellKnownHeader::ContentType);
}
if (const QNetworkCookieJar *const cookieJar = manager->cookieJar()) {
auto cookies = cookieJar->cookiesForUrl(url);
if (!cookies.empty()) {
- redirectRequest.setHeader(QNetworkRequest::KnownHeaders::CookieHeader,
- QVariant::fromValue(cookies));
+ auto cookieHeader = QNetworkHeadersPrivate::fromCookieList(cookies);
+ newHeaders.replaceOrAppend(QHttpHeaders::WellKnownHeader::Cookie, cookieHeader);
}
}
+ redirectRequest.setHeaders(std::move(newHeaders));
+
if (httpRequest.redirectPolicy() != QNetworkRequest::UserVerifiedRedirectPolicy)
followRedirect();
@@ -1293,8 +1305,7 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
Q_ASSERT(managerPrivate);
decompressHelper.clear();
- rawHeaders.clear();
- cookedHeaders.clear();
+ clearHeaders();
if (managerPrivate->thread)
managerPrivate->thread->disconnect();
@@ -1317,7 +1328,7 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
// What do we do about the caching of the HTML note?
// The response to a 303 MUST NOT be cached, while the response to
// all of the others is cacheable if the headers indicate it to be
- QByteArray header = q->rawHeader(locationHeader());
+ QByteArrayView header = q->headers().value(locationHeader());
QUrl url = QUrl(QString::fromUtf8(header));
if (!url.isValid())
url = QUrl(QLatin1StringView(header));
@@ -1361,20 +1372,19 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QHttpHeaders &hm,
// A user having manually defined which encodings they accept is, for
// somwehat unknown (presumed legacy compatibility) reasons treated as
// disabling our decompression:
- const bool autoDecompress = request.rawHeader("accept-encoding").isEmpty();
+ const bool autoDecompress = !request.headers().contains(QHttpHeaders::WellKnownHeader::AcceptEncoding);
const bool shouldDecompress = isCompressed && autoDecompress;
// reconstruct the HTTP header
+ auto h = q->headers();
for (qsizetype i = 0; i < hm.size(); ++i) {
const auto key = hm.nameAt(i);
const auto originValue = hm.valueAt(i);
- QByteArray value = q->rawHeader(key);
-
// Reset any previous "location" header set in the reply. In case of
// redirects, we don't want to 'append' multiple location header values,
// rather we keep only the latest one
- if (key == locationHeader())
- value.clear();
+ if (key.compare(locationHeader(), Qt::CaseInsensitive) == 0)
+ h.removeAll(key);
if (shouldDecompress && !decompressHelper.isValid() && key == "content-encoding"_L1) {
if (!synchronous) // with synchronous all the data is expected to be handled at once
@@ -1390,17 +1400,9 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QHttpHeaders &hm,
request.decompressedSafetyCheckThreshold());
}
- if (!value.isEmpty()) {
- // Why are we appending values for headers which are already
- // present?
- if (key == "set-cookie"_L1)
- value += '\n';
- else
- value += ", ";
- }
- value += originValue;
- q->setRawHeader({key.data(), key.size()}, value);
+ h.append(key, originValue);
}
+ q->setHeaders(std::move(h));
q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase);
@@ -1415,13 +1417,10 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QHttpHeaders &hm,
QAbstractNetworkCache *nc = managerPrivate->networkCache;
if (nc) {
QNetworkCacheMetaData metaData = nc->metaData(httpRequest.url());
- QNetworkHeadersPrivate cacheHeaders;
- cacheHeaders.setAllRawHeaders(metaData.rawHeaders());
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
- it = cacheHeaders.findRawHeader(cacheControlName());
+ auto value = metaData.headers().value(QHttpHeaders::WellKnownHeader::CacheControl);
bool mustReValidate = false;
- if (it != cacheHeaders.rawHeaders.constEnd()) {
- QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second);
+ if (!value.empty()) {
+ QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(value);
if (cacheControl.contains("must-revalidate"_ba))
mustReValidate = true;
}
@@ -1660,16 +1659,21 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute));
q->setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true);
- QNetworkCacheMetaData::RawHeaderList rawHeaders = metaData.rawHeaders();
- QNetworkCacheMetaData::RawHeaderList::ConstIterator it = rawHeaders.constBegin(),
- end = rawHeaders.constEnd();
+ QHttpHeaders cachedHeaders = metaData.headers();
+ QHttpHeaders h = headers();
QUrl redirectUrl;
- for ( ; it != end; ++it) {
- if (httpRequest.isFollowRedirects() &&
- !it->first.compare(locationHeader(), Qt::CaseInsensitive))
- redirectUrl = QUrl::fromEncoded(it->second);
- setRawHeader(it->first, it->second);
+ for (qsizetype i = 0; i < cachedHeaders.size(); ++i) {
+ const auto name = cachedHeaders.nameAt(i);
+ const auto value = cachedHeaders.valueAt(i);
+
+ if (httpRequest.isFollowRedirects()
+ && !name.compare(locationHeader(), Qt::CaseInsensitive)) {
+ redirectUrl = QUrl::fromEncoded(value);
+ }
+
+ h.replaceOrAppend(name, value);
}
+ setHeaders(std::move(h));
if (!isHttpRedirectResponse())
checkForRedirect(status);
@@ -1729,17 +1733,17 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
Q_Q(const QNetworkReplyHttpImpl);
QNetworkCacheMetaData metaData = oldMetaData;
+ QHttpHeaders cacheHeaders = metaData.headers();
- QNetworkHeadersPrivate cacheHeaders;
- cacheHeaders.setAllRawHeaders(metaData.rawHeaders());
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
+ const auto newHeaders = q->headers();
+ for (qsizetype i = 0; i < newHeaders.size(); ++i) {
+ const auto name = newHeaders.nameAt(i);
+ const auto value = newHeaders.valueAt(i);
- const QList<QByteArray> newHeaders = q->rawHeaderList();
- for (const QByteArray& header : newHeaders) {
- if (isHopByHop(header))
+ if (isHopByHop(name))
continue;
- if (header.compare("set-cookie", Qt::CaseInsensitive) == 0)
+ if (name.compare("set-cookie", Qt::CaseInsensitive) == 0)
continue;
// for 4.6.0, we were planning to not store the date header in the
@@ -1752,50 +1756,46 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
//continue;
// Don't store Warning 1xx headers
- if (header.compare("warning", Qt::CaseInsensitive) == 0) {
- const QByteArray v = q->rawHeader(header);
- if (v.size() == 3
- && v[0] == '1'
- && isAsciiDigit(v[1])
- && isAsciiDigit(v[2]))
+ if (name.compare("warning", Qt::CaseInsensitive) == 0) {
+ if (value.size() == 3
+ && value[0] == '1'
+ && isAsciiDigit(value[1])
+ && isAsciiDigit(value[2]))
continue;
}
- it = cacheHeaders.findRawHeader(header);
- if (it != cacheHeaders.rawHeaders.constEnd()) {
+ if (cacheHeaders.contains(name)) {
// Match the behavior of Firefox and assume Cache-Control: "no-transform"
constexpr QByteArrayView headers[]=
{"content-encoding", "content-range", "content-type"};
- if (std::any_of(std::begin(headers), std::end(headers), caseInsensitiveCompare(header)))
+ if (std::any_of(std::begin(headers), std::end(headers), caseInsensitiveCompare(name)))
continue;
}
// IIS has been known to send "Content-Length: 0" on 304 responses, so
// ignore this too
- if (statusCode == 304 && header.compare("content-length", Qt::CaseInsensitive) == 0)
+ if (statusCode == 304 && name.compare("content-length", Qt::CaseInsensitive) == 0)
continue;
#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
- QByteArray n = q->rawHeader(header);
- QByteArray o;
- if (it != cacheHeaders.rawHeaders.constEnd())
- o = (*it).second;
- if (n != o && headerheader.compare("date", Qt::CaseInsensitive) != 0) {
- qDebug() << "replacing" << header;
+ QByteArrayView n = newHeaders.value(name);
+ QByteArrayView o = cacheHeaders.value(name);
+ if (n != o && name.compare("date", Qt::CaseInsensitive) != 0) {
+ qDebug() << "replacing" << name;
qDebug() << "new" << n;
qDebug() << "old" << o;
}
#endif
- cacheHeaders.setRawHeader(header, q->rawHeader(header));
+ cacheHeaders.replaceOrAppend(name, value);
}
- metaData.setRawHeaders(cacheHeaders.rawHeaders);
+ metaData.setHeaders(cacheHeaders);
bool checkExpired = true;
QHash<QByteArray, QByteArray> cacheControl;
- it = cacheHeaders.findRawHeader(cacheControlName());
- if (it != cacheHeaders.rawHeaders.constEnd()) {
- cacheControl = parseHttpOptionHeader(it->second);
+ auto value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::CacheControl);
+ if (!value.empty()) {
+ cacheControl = parseHttpOptionHeader(value);
QByteArray maxAge = cacheControl.value("max-age"_ba);
if (!maxAge.isEmpty()) {
checkExpired = false;
@@ -1805,16 +1805,18 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
}
}
if (checkExpired) {
- it = cacheHeaders.findRawHeader("expires");
- if (it != cacheHeaders.rawHeaders.constEnd()) {
- QDateTime expiredDateTime = QNetworkHeadersPrivate::fromHttpDate(it->second);
+ if (const auto value = cacheHeaders.value(
+ QHttpHeaders::WellKnownHeader::Expires); !value.isEmpty()) {
+ QDateTime expiredDateTime = QNetworkHeadersPrivate::fromHttpDate(value);
metaData.setExpirationDate(expiredDateTime);
}
}
- it = cacheHeaders.findRawHeader("last-modified");
- if (it != cacheHeaders.rawHeaders.constEnd())
- metaData.setLastModified(QNetworkHeadersPrivate::fromHttpDate(it->second));
+ if (const auto value = cacheHeaders.value(
+ QHttpHeaders::WellKnownHeader::LastModified); !value.isEmpty()) {
+ metaData.setLastModified(QNetworkHeadersPrivate::fromHttpDate(value));
+ }
+
bool canDiskCache;
// only cache GET replies by default, all other replies (POST, PUT, DELETE)
@@ -1862,14 +1864,16 @@ bool QNetworkReplyHttpImplPrivate::canResume() const
if (operation != QNetworkAccessManager::GetOperation)
return false;
+ const auto h = q->headers();
+
// Can only resume if server/resource supports Range header.
- constexpr auto acceptRangesheaderName = QByteArrayView("Accept-Ranges");
- if (!q->hasRawHeader(acceptRangesheaderName) || q->rawHeader(acceptRangesheaderName) == "none")
+ const auto acceptRanges = h.value(QHttpHeaders::WellKnownHeader::AcceptRanges);
+ if (acceptRanges.empty() || acceptRanges == "none")
return false;
// We only support resuming for byte ranges.
- if (request.hasRawHeader(rangeName())) {
- QByteArray range = request.rawHeader(rangeName());
+ const auto range = h.value(QHttpHeaders::WellKnownHeader::Range);
+ if (!range.empty()) {
if (!range.startsWith(bytesEqualPrefix()))
return false;
}
@@ -1918,8 +1922,8 @@ void QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead()
// Needs to be done where sendCacheContents() (?) of HTTP is emitting
// metaDataChanged ?
-
- QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
// emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
@@ -1930,8 +1934,7 @@ void QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead()
if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
downloadProgressSignalChoke.restart();
- emit q->downloadProgress(bytesDownloaded,
- totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ emit q->downloadProgress(bytesDownloaded, totalSizeOpt.value_or(-1));
}
}
@@ -2118,11 +2121,13 @@ void QNetworkReplyHttpImplPrivate::finished()
if (state == Finished || state == Aborted)
return;
- QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
+ const qint64 totalSize = totalSizeOpt.value_or(-1);
// if we don't know the total size of or we received everything save the cache.
// If the data is compressed then this is done in readData()
- if ((totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
+ if ((totalSize == -1 || bytesDownloaded == totalSize)
&& !decompressHelper.isValid()) {
completeCacheSave();
}
@@ -2135,10 +2140,10 @@ void QNetworkReplyHttpImplPrivate::finished()
state = Finished;
q->setFinished(true);
- if (totalSize.isNull() || totalSize == -1) {
+ if (totalSize == -1) {
emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
} else {
- emit q->downloadProgress(bytesDownloaded, totalSize.toLongLong());
+ emit q->downloadProgress(bytesDownloaded, totalSize);
}
if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
@@ -2182,14 +2187,15 @@ void QNetworkReplyHttpImplPrivate::_q_metaDataChanged()
// 1. do we have cookies?
// 2. are we allowed to set them?
Q_ASSERT(manager);
- const auto it = cookedHeaders.constFind(QNetworkRequest::SetCookieHeader);
- if (it != cookedHeaders.cend()
+
+ const auto cookiesOpt = QNetworkHeadersPrivate::toSetCookieList(
+ headers().values(QHttpHeaders::WellKnownHeader::SetCookie));
+ const auto cookies = cookiesOpt.value_or(QList<QNetworkCookie>());
+ if (!cookies.empty()
&& request.attribute(QNetworkRequest::CookieSaveControlAttribute,
QNetworkRequest::Automatic).toInt() == QNetworkRequest::Automatic) {
QNetworkCookieJar *jar = manager->cookieJar();
if (jar) {
- QList<QNetworkCookie> cookies =
- qvariant_cast<QList<QNetworkCookie> >(it.value());
jar->setCookiesFromUrl(cookies, url);
}
}
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 8b2acfdb4e..b90ec1cc4c 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -118,15 +118,16 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
return;
}
- QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
+
pauseNotificationHandling();
// emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
emit q->readyRead();
if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
downloadProgressSignalChoke.restart();
- emit q->downloadProgress(bytesDownloaded,
- totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ emit q->downloadProgress(bytesDownloaded, totalSizeOpt.value_or(-1));
}
resumeNotificationHandling();
}
@@ -243,7 +244,10 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
if (bufferingDisallowed) {
// if a valid content-length header for the request was supplied, we can disable buffering
// if not, we will buffer anyway
- if (req.header(QNetworkRequest::ContentLengthHeader).isValid()) {
+ const auto sizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
+
+ if (sizeOpt) {
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
} else {
state = Buffering;
@@ -478,7 +482,8 @@ void QNetworkReplyImplPrivate::appendDownstreamDataSignalEmissions()
{
Q_Q(QNetworkReplyImpl);
- QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
pauseNotificationHandling();
// important: At the point of this readyRead(), the data parameter list must be empty,
// else implicit sharing will trigger memcpy when the user is reading data!
@@ -487,8 +492,7 @@ void QNetworkReplyImplPrivate::appendDownstreamDataSignalEmissions()
// processed and we get into a recursive call (as in QProgressDialog).
if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
downloadProgressSignalChoke.restart();
- emit q->downloadProgress(bytesDownloaded,
- totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ emit q->downloadProgress(bytesDownloaded, totalSizeOpt.value_or(-1));
}
resumeNotificationHandling();
@@ -589,7 +593,9 @@ void QNetworkReplyImplPrivate::finished()
return;
pauseNotificationHandling();
- QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
+ const auto totalSize = totalSizeOpt.value_or(-1);
resumeNotificationHandling();
@@ -599,10 +605,10 @@ void QNetworkReplyImplPrivate::finished()
pendingNotifications.clear();
pauseNotificationHandling();
- if (totalSize.isNull() || totalSize == -1) {
+ if (totalSize == -1) {
emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
} else {
- emit q->downloadProgress(bytesDownloaded, totalSize.toLongLong());
+ emit q->downloadProgress(bytesDownloaded, totalSize);
}
if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
@@ -610,7 +616,7 @@ void QNetworkReplyImplPrivate::finished()
resumeNotificationHandling();
// if we don't know the total size of or we received everything save the cache
- if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
+ if (totalSize == -1 || bytesDownloaded == totalSize)
completeCacheSave();
// note: might not be a good idea, since users could decide to delete us
@@ -646,14 +652,14 @@ void QNetworkReplyImplPrivate::metaDataChanged()
// 1. do we have cookies?
// 2. are we allowed to set them?
if (!manager.isNull()) {
- const auto it = cookedHeaders.constFind(QNetworkRequest::SetCookieHeader);
- if (it != cookedHeaders.cend()
+ const auto cookiesOpt = QNetworkHeadersPrivate::toSetCookieList(
+ headers().values(QHttpHeaders::WellKnownHeader::SetCookie));
+ const auto cookies = cookiesOpt.value_or(QList<QNetworkCookie>());
+ if (!cookies.empty()
&& request.attribute(QNetworkRequest::CookieSaveControlAttribute,
QNetworkRequest::Automatic).toInt() == QNetworkRequest::Automatic) {
QNetworkCookieJar *jar = manager->cookieJar();
if (jar) {
- QList<QNetworkCookie> cookies =
- qvariant_cast<QList<QNetworkCookie> >(it.value());
jar->setCookiesFromUrl(cookies, url);
}
}
@@ -857,9 +863,10 @@ qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen)
break;
}
}
- QVariant totalSize = d->cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
- emit downloadProgress(bytesRead,
- totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+
+ const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
+ headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
+ emit downloadProgress(bytesRead, totalSizeOpt.value_or(-1));
return bytesRead;
} else if (d->backend && d->backend->bytesAvailable()) {
return d->backend->read(data, maxlen);
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp
index c02f0b4e61..7d2b6a701e 100644
--- a/src/network/access/qnetworkreplywasmimpl.cpp
+++ b/src/network/access/qnetworkreplywasmimpl.cpp
@@ -9,6 +9,7 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qthread.h>
+#include <QtCore/private/qeventdispatcher_wasm_p.h>
#include <QtCore/private/qoffsetstringarray_p.h>
#include <QtCore/private/qtools_p.h>
@@ -63,11 +64,27 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate()
, totalDownloadSize(0)
, percentFinished(0)
, m_fetch(nullptr)
+ , m_fetchContext(nullptr)
{
}
QNetworkReplyWasmImplPrivate::~QNetworkReplyWasmImplPrivate()
{
+
+ if (m_fetchContext) { // fetch has been initiated
+ std::unique_lock lock{ m_fetchContext->mutex };
+
+ if (m_fetchContext->state == FetchContext::State::SCHEDULED
+ || m_fetchContext->state == FetchContext::State::SENT
+ || m_fetchContext->state == FetchContext::State::CANCELED) {
+ m_fetchContext->reply = nullptr;
+ m_fetchContext->state = FetchContext::State::TO_BE_DESTROYED;
+ } else if (m_fetchContext->state == FetchContext::State::FINISHED) {
+ lock.unlock();
+ delete m_fetchContext;
+ }
+ }
+
}
QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent)
@@ -116,7 +133,7 @@ void QNetworkReplyWasmImpl::close()
d->state = QNetworkReplyPrivate::Finished;
d->setCanceled();
}
-
+ emscripten_fetch_close(d->m_fetch);
QNetworkReply::close();
}
@@ -134,8 +151,14 @@ void QNetworkReplyWasmImpl::abort()
void QNetworkReplyWasmImplPrivate::setCanceled()
{
Q_Q(QNetworkReplyWasmImpl);
- if (m_fetch)
- m_fetch->userData = nullptr;
+ {
+ if (m_fetchContext) {
+ std::scoped_lock lock{ m_fetchContext->mutex };
+ if (m_fetchContext->state == FetchContext::State::SCHEDULED
+ || m_fetchContext->state == FetchContext::State::SENT)
+ m_fetchContext->state = FetchContext::State::CANCELED;
+ }
+ }
emitReplyError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled"));
q->setFinished(true);
@@ -227,48 +250,7 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
emscripten_fetch_attr_t attr;
emscripten_fetch_attr_init(&attr);
- strcpy(attr.requestMethod, q->methodName().constData());
-
- QList<QByteArray> headersData = request.rawHeaderList();
- int arrayLength = getArraySize(headersData.count());
- const char *customHeaders[arrayLength];
- QStringList trimmedHeaders;
-
- if (headersData.count() > 0) {
- int i = 0;
- for (const auto &headerName : headersData) {
- if (isUnsafeHeader(QLatin1StringView(headerName.constData()))) {
- trimmedHeaders.push_back(QString::fromLatin1(headerName));
- } else {
- customHeaders[i++] = headerName.constData();
- customHeaders[i++] = request.rawHeader(headerName).constData();
- }
- }
- if (!trimmedHeaders.isEmpty()) {
- qWarning() << "Qt has trimmed the following forbidden headers from the request:"
- << trimmedHeaders.join(QLatin1StringView(", "));
- }
- customHeaders[i] = nullptr;
- attr.requestHeaders = customHeaders;
- }
-
- if (outgoingData) { // data from post request
- // handle extra data
- requestData = outgoingData->readAll(); // is there a size restriction here?
- if (!requestData.isEmpty()) {
- attr.requestData = requestData.data();
- attr.requestDataSize = requestData.size();
- }
- }
-
- QByteArray userName, password;
- // username & password
- if (!request.url().userInfo().isEmpty()) {
- userName = request.url().userName().toUtf8();
- password = request.url().password().toUtf8();
- attr.userName = userName.constData();
- attr.password = password.constData();
- }
+ qstrncpy(attr.requestMethod, q->methodName().constData(), 32); // requestMethod is char[32] in emscripten
attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
@@ -293,13 +275,67 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
attr.onprogress = QNetworkReplyWasmImplPrivate::downloadProgress;
attr.onreadystatechange = QNetworkReplyWasmImplPrivate::stateChange;
attr.timeoutMSecs = request.transferTimeout();
- attr.userData = reinterpret_cast<void *>(this);
- QString dPath = "/home/web_user/"_L1 + request.url().fileName();
- QByteArray destinationPath = dPath.toUtf8();
- attr.destinationPath = destinationPath.constData();
+ m_fetchContext = new FetchContext(this);;
+ attr.userData = static_cast<void *>(m_fetchContext);
+ if (outgoingData) { // data from post request
+ m_fetchContext->requestData = outgoingData->readAll(); // is there a size restriction here?
+ if (!m_fetchContext->requestData.isEmpty()) {
+ attr.requestData = m_fetchContext->requestData.data();
+ attr.requestDataSize = m_fetchContext->requestData.size();
+ }
+ }
- m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8().constData());
+ QEventDispatcherWasm::runOnMainThread([attr, fetchContext = m_fetchContext]() mutable {
+ std::unique_lock lock{ fetchContext->mutex };
+ if (fetchContext->state == FetchContext::State::CANCELED) {
+ fetchContext->state = FetchContext::State::FINISHED;
+ return;
+ } else if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) {
+ lock.unlock();
+ delete fetchContext;
+ return;
+ }
+ const auto reply = fetchContext->reply;
+ const auto &request = reply->request;
+
+ QByteArray userName, password;
+ if (!request.url().userInfo().isEmpty()) {
+ userName = request.url().userName().toUtf8();
+ password = request.url().password().toUtf8();
+ attr.userName = userName.constData();
+ attr.password = password.constData();
+ }
+
+ QList<QByteArray> headersData = request.rawHeaderList();
+ int arrayLength = getArraySize(headersData.count());
+ const char *customHeaders[arrayLength];
+ QStringList trimmedHeaders;
+ if (headersData.count() > 0) {
+ int i = 0;
+ for (const auto &headerName : headersData) {
+ if (isUnsafeHeader(QLatin1StringView(headerName.constData()))) {
+ trimmedHeaders.push_back(QString::fromLatin1(headerName));
+ } else {
+ customHeaders[i++] = headerName.constData();
+ customHeaders[i++] = request.rawHeader(headerName).constData();
+ }
+ }
+ if (!trimmedHeaders.isEmpty()) {
+ qWarning() << "Qt has trimmed the following forbidden headers from the request:"
+ << trimmedHeaders.join(QLatin1StringView(", "));
+ }
+ customHeaders[i] = nullptr;
+ attr.requestHeaders = customHeaders;
+ }
+
+ auto url = request.url().toString().toUtf8();
+ QString dPath = "/home/web_user/"_L1 + request.url().fileName();
+ QByteArray destinationPath = dPath.toUtf8();
+ attr.destinationPath = destinationPath.constData();
+ reply->m_fetch = emscripten_fetch(&attr, url.constData());
+ fetchContext->state = FetchContext::State::SENT;
+ });
state = Working;
}
@@ -477,8 +513,18 @@ void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData()
void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch)
{
- auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
- if (reply) {
+ auto fetchContext = static_cast<FetchContext *>(fetch->userData);
+ std::unique_lock lock{ fetchContext->mutex };
+
+ if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) {
+ lock.unlock();
+ delete fetchContext;
+ return;
+ } else if (fetchContext->state == FetchContext::State::CANCELED) {
+ fetchContext->state = FetchContext::State::FINISHED;
+ return;
+ } else if (fetchContext->state == FetchContext::State::SENT) {
+ const auto reply = fetchContext->reply;
if (reply->state != QNetworkReplyPrivate::Aborted) {
QByteArray buffer(fetch->data, fetch->numBytes);
reply->dataReceived(buffer);
@@ -487,8 +533,8 @@ void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch)
reply->setReplyFinished();
}
reply->m_fetch = nullptr;
+ fetchContext->state = FetchContext::State::FINISHED;
}
- emscripten_fetch_close(fetch);
}
void QNetworkReplyWasmImplPrivate::setReplyFinished()
@@ -509,7 +555,8 @@ void QNetworkReplyWasmImplPrivate::setStatusCode(int status, const QByteArray &s
void QNetworkReplyWasmImplPrivate::stateChange(emscripten_fetch_t *fetch)
{
- auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
+ const auto fetchContext = static_cast<FetchContext*>(fetch->userData);
+ const auto reply = fetchContext->reply;
if (reply && reply->state != QNetworkReplyPrivate::Aborted) {
if (fetch->readyState == /*HEADERS_RECEIVED*/ 2) {
size_t headerLength = emscripten_fetch_get_response_headers_length(fetch);
@@ -522,7 +569,8 @@ void QNetworkReplyWasmImplPrivate::stateChange(emscripten_fetch_t *fetch)
void QNetworkReplyWasmImplPrivate::downloadProgress(emscripten_fetch_t *fetch)
{
- auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
+ const auto fetchContext = static_cast<FetchContext*>(fetch->userData);
+ const auto reply = fetchContext->reply;
if (reply && reply->state != QNetworkReplyPrivate::Aborted) {
if (fetch->status < 400) {
uint64_t bytes = fetch->dataOffset + fetch->numBytes;
@@ -536,8 +584,18 @@ void QNetworkReplyWasmImplPrivate::downloadProgress(emscripten_fetch_t *fetch)
void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch)
{
- auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
- if (reply) {
+ const auto fetchContext = static_cast<FetchContext*>(fetch->userData);
+ std::unique_lock lock{ fetchContext->mutex };
+
+ if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) {
+ lock.unlock();
+ delete fetchContext;
+ return;
+ } else if (fetchContext->state == FetchContext::State::CANCELED) {
+ fetchContext->state = FetchContext::State::FINISHED;
+ return;
+ } else if (fetchContext->state == FetchContext::State::SENT) {
+ const auto reply = fetchContext->reply;
if (reply->state != QNetworkReplyPrivate::Aborted) {
QString reasonStr;
if (fetch->status > 600)
@@ -548,12 +606,13 @@ void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch)
reply->dataReceived(buffer);
QByteArray statusText(fetch->statusText);
reply->setStatusCode(fetch->status, statusText);
- reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), reasonStr);
+ reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()),
+ reasonStr);
reply->setReplyFinished();
}
reply->m_fetch = nullptr;
+ fetchContext->state = FetchContext::State::FINISHED;
}
- emscripten_fetch_close(fetch);
}
//taken from qhttpthreaddelegate.cpp
diff --git a/src/network/access/qnetworkreplywasmimpl_p.h b/src/network/access/qnetworkreplywasmimpl_p.h
index ae167799d7..4b00bb09ea 100644
--- a/src/network/access/qnetworkreplywasmimpl_p.h
+++ b/src/network/access/qnetworkreplywasmimpl_p.h
@@ -28,6 +28,7 @@
#include <emscripten/fetch.h>
#include <memory>
+#include <mutex>
QT_BEGIN_NAMESPACE
@@ -63,6 +64,29 @@ private:
QByteArray methodName() const;
};
+class QNetworkReplyWasmImplPrivate;
+
+/*!
+ The FetchContext class ensures the requestData object remains valid
+ while a fetch operation is pending. Since Emscripten fetch is asynchronous,
+ requestData must persist until one of the final callbacks is invoked.
+ Additionally, there's a potential race condition between the thread
+ scheduling the fetch operation and the one executing it. Since fetch must
+ occur on the main thread due to browser limitations,
+ a mutex safeguards the FetchContext to ensure atomic state transitions.
+*/
+struct FetchContext
+{
+ enum class State { SCHEDULED, SENT, FINISHED, CANCELED, TO_BE_DESTROYED };
+
+ FetchContext(QNetworkReplyWasmImplPrivate *networkReply) : reply(networkReply) { }
+
+ QNetworkReplyWasmImplPrivate *reply{ nullptr };
+ std::mutex mutex;
+ QByteArray requestData;
+ State state{ State::SCHEDULED };
+};
+
class QNetworkReplyWasmImplPrivate: public QNetworkReplyPrivate
{
public:
@@ -101,7 +125,6 @@ public:
QIODevice *outgoingData;
std::shared_ptr<QRingBuffer> outgoingDataBuffer;
- QByteArray requestData;
static void downloadProgress(emscripten_fetch_t *fetch);
static void downloadFailed(emscripten_fetch_t *fetch);
@@ -111,6 +134,7 @@ public:
static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url);
emscripten_fetch_t *m_fetch;
+ FetchContext *m_fetchContext;
void setReplyFinished();
void setCanceled();
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index 6f5a7ff19a..7a1b5426d2 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -6,6 +6,7 @@
#include "qplatformdefs.h"
#include "qnetworkcookie.h"
#include "qsslconfiguration.h"
+#include "qhttpheadershelper_p.h"
#if QT_CONFIG(http)
#include "qhttp1configuration.h"
#include "qhttp2configuration.h"
@@ -16,6 +17,7 @@
#include "QtCore/qlocale.h"
#include "QtCore/qshareddata.h"
#include "QtCore/qtimezone.h"
+#include "QtCore/private/qduplicatetracker_p.h"
#include "QtCore/private/qtools_p.h"
#include <ctype.h>
@@ -24,6 +26,7 @@
#endif
#include <algorithm>
+#include <q20algorithm.h>
QT_BEGIN_NAMESPACE
@@ -109,6 +112,8 @@ QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy, QNetworkRequest_
\value ServerHeader The Server header received by HTTP clients.
+ \omitvalue NumKnownHeaders
+
\sa header(), setHeader(), rawHeader(), setRawHeader()
*/
@@ -465,7 +470,6 @@ public:
{
return url == other.url &&
priority == other.priority &&
- rawHeaders == other.rawHeaders &&
attributes == other.attributes &&
maxRedirectsAllowed == other.maxRedirectsAllowed &&
peerVerifyName == other.peerVerifyName
@@ -475,6 +479,7 @@ public:
&& decompressedSafetyCheckThreshold == other.decompressedSafetyCheckThreshold
#endif
&& transferTimeout == other.transferTimeout
+ && QHttpHeadersHelper::compareStrict(httpHeaders, other.httpHeaders)
;
// don't compare cookedHeaders
}
@@ -601,6 +606,43 @@ void QNetworkRequest::setUrl(const QUrl &url)
}
/*!
+ \since 6.8
+
+ Returns headers that are set in this network request.
+
+ \sa setHeaders()
+*/
+QHttpHeaders QNetworkRequest::headers() const
+{
+ return d->headers();
+}
+
+/*!
+ \since 6.8
+
+ Sets \a newHeaders as headers in this network request, overriding
+ any previously set headers.
+
+ If some headers correspond to the known headers, the values will
+ be parsed and the corresponding parsed form will also be set.
+
+ \sa headers(), KnownHeaders
+*/
+void QNetworkRequest::setHeaders(QHttpHeaders &&newHeaders)
+{
+ d->setHeaders(std::move(newHeaders));
+}
+
+/*!
+ \overload
+ \since 6.8
+*/
+void QNetworkRequest::setHeaders(const QHttpHeaders &newHeaders)
+{
+ d->setHeaders(newHeaders);
+}
+
+/*!
Returns the value of the known network header \a header if it is
present in this request. If it is not present, returns QVariant()
(i.e., an invalid variant).
@@ -633,7 +675,7 @@ void QNetworkRequest::setHeader(KnownHeaders header, const QVariant &value)
*/
bool QNetworkRequest::hasRawHeader(QAnyStringView headerName) const
{
- return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
+ return d->headers().contains(headerName);
}
/*!
@@ -649,9 +691,7 @@ bool QNetworkRequest::hasRawHeader(QAnyStringView headerName) const
*/
QByteArray QNetworkRequest::rawHeader(QAnyStringView headerName) const
{
- if (const auto it = d->findRawHeader(headerName); it != d->rawHeaders.constEnd())
- return it->second;
- return QByteArray();
+ return d->rawHeader(headerName);
}
/*!
@@ -1038,63 +1078,72 @@ void QNetworkRequest::setTransferTimeout(std::chrono::milliseconds duration)
}
#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
-static QByteArray headerName(QNetworkRequest::KnownHeaders header)
-{
- switch (header) {
- case QNetworkRequest::ContentTypeHeader:
- return "Content-Type"_ba;
-
- case QNetworkRequest::ContentLengthHeader:
- return "Content-Length"_ba;
-
- case QNetworkRequest::LocationHeader:
- return "Location"_ba;
-
- case QNetworkRequest::LastModifiedHeader:
- return "Last-Modified"_ba;
-
- case QNetworkRequest::IfModifiedSinceHeader:
- return "If-Modified-Since"_ba;
+namespace {
- case QNetworkRequest::ETagHeader:
- return "ETag"_ba;
-
- case QNetworkRequest::IfMatchHeader:
- return "If-Match"_ba;
-
- case QNetworkRequest::IfNoneMatchHeader:
- return "If-None-Match"_ba;
-
- case QNetworkRequest::CookieHeader:
- return "Cookie"_ba;
+struct HeaderPair {
+ QHttpHeaders::WellKnownHeader wellKnownHeader;
+ QNetworkRequest::KnownHeaders knownHeader;
+};
- case QNetworkRequest::SetCookieHeader:
- return "Set-Cookie"_ba;
+constexpr bool operator<(const HeaderPair &lhs, const HeaderPair &rhs)
+{
+ return lhs.wellKnownHeader < rhs.wellKnownHeader;
+}
- case QNetworkRequest::ContentDispositionHeader:
- return "Content-Disposition"_ba;
+constexpr bool operator<(const HeaderPair &lhs, QHttpHeaders::WellKnownHeader rhs)
+{
+ return lhs.wellKnownHeader < rhs;
+}
- case QNetworkRequest::UserAgentHeader:
- return "User-Agent"_ba;
+constexpr bool operator<(QHttpHeaders::WellKnownHeader lhs, const HeaderPair &rhs)
+{
+ return lhs < rhs.wellKnownHeader;
+}
- case QNetworkRequest::ServerHeader:
- return "Server"_ba;
+} // anonymous namespace
+
+static constexpr HeaderPair knownHeadersArr[] = {
+ { QHttpHeaders::WellKnownHeader::ContentDisposition, QNetworkRequest::KnownHeaders::ContentDispositionHeader },
+ { QHttpHeaders::WellKnownHeader::ContentLength, QNetworkRequest::KnownHeaders::ContentLengthHeader },
+ { QHttpHeaders::WellKnownHeader::ContentType, QNetworkRequest::KnownHeaders::ContentTypeHeader },
+ { QHttpHeaders::WellKnownHeader::Cookie, QNetworkRequest::KnownHeaders::CookieHeader },
+ { QHttpHeaders::WellKnownHeader::ETag, QNetworkRequest::KnownHeaders::ETagHeader },
+ { QHttpHeaders::WellKnownHeader::IfMatch , QNetworkRequest::KnownHeaders::IfMatchHeader },
+ { QHttpHeaders::WellKnownHeader::IfModifiedSince, QNetworkRequest::KnownHeaders::IfModifiedSinceHeader },
+ { QHttpHeaders::WellKnownHeader::IfNoneMatch, QNetworkRequest::KnownHeaders::IfNoneMatchHeader },
+ { QHttpHeaders::WellKnownHeader::LastModified, QNetworkRequest::KnownHeaders::LastModifiedHeader},
+ { QHttpHeaders::WellKnownHeader::Location, QNetworkRequest::KnownHeaders::LocationHeader},
+ { QHttpHeaders::WellKnownHeader::Server, QNetworkRequest::KnownHeaders::ServerHeader },
+ { QHttpHeaders::WellKnownHeader::SetCookie, QNetworkRequest::KnownHeaders::SetCookieHeader },
+ { QHttpHeaders::WellKnownHeader::UserAgent, QNetworkRequest::KnownHeaders::UserAgentHeader }
+};
- // no default:
- // if new values are added, this will generate a compiler warning
- }
+static_assert(std::size(knownHeadersArr) == size_t(QNetworkRequest::KnownHeaders::NumKnownHeaders));
+static_assert(q20::is_sorted(std::begin(knownHeadersArr), std::end(knownHeadersArr)));
- return QByteArray();
+static std::optional<QNetworkRequest::KnownHeaders> toKnownHeader(QHttpHeaders::WellKnownHeader key)
+{
+ const auto it = std::lower_bound(std::begin(knownHeadersArr), std::end(knownHeadersArr), key);
+ if (it == std::end(knownHeadersArr) || key < *it)
+ return std::nullopt;
+ return it->knownHeader;
}
-static QByteArray makeCookieHeader(const QVariant &value, QNetworkCookie::RawForm type, QByteArrayView separator)
+static std::optional<QHttpHeaders::WellKnownHeader> toWellKnownHeader(QNetworkRequest::KnownHeaders key)
{
- QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
- if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
- cookies << qvariant_cast<QNetworkCookie>(value);
+ auto pred = [key](const HeaderPair &pair) { return pair.knownHeader == key; };
+ const auto it = std::find_if(std::begin(knownHeadersArr), std::end(knownHeadersArr), pred);
+ if (it == std::end(knownHeadersArr))
+ return std::nullopt;
+ return it->wellKnownHeader;
+}
+static QByteArray makeCookieHeader(const QList<QNetworkCookie> &cookies,
+ QNetworkCookie::RawForm type,
+ QByteArrayView separator)
+{
QByteArray result;
- for (const QNetworkCookie &cookie : std::as_const(cookies)) {
+ for (const QNetworkCookie &cookie : cookies) {
result += cookie.toRawForm(type);
result += separator;
}
@@ -1103,6 +1152,15 @@ static QByteArray makeCookieHeader(const QVariant &value, QNetworkCookie::RawFor
return result;
}
+static QByteArray makeCookieHeader(const QVariant &value, QNetworkCookie::RawForm type,
+ QByteArrayView separator)
+{
+ const QList<QNetworkCookie> *cookies = get_if<QList<QNetworkCookie>>(&value);
+ if (!cookies)
+ return {};
+ return makeCookieHeader(*cookies, type, separator);
+}
+
static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
{
switch (header) {
@@ -1143,9 +1201,10 @@ static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVaria
case QNetworkRequest::SetCookieHeader:
return makeCookieHeader(value, QNetworkCookie::Full, ", ");
- }
- return QByteArray();
+ default:
+ Q_UNREACHABLE_RETURN({});
+ }
}
static int parseHeaderName(QByteArrayView headerName)
@@ -1206,7 +1265,7 @@ static int parseHeaderName(QByteArrayView headerName)
return -1; // nothing found
}
-static QVariant parseHttpDate(const QByteArray &raw)
+static QVariant parseHttpDate(QByteArrayView raw)
{
QDateTime dt = QNetworkHeadersPrivate::fromHttpDate(raw);
if (dt.isValid())
@@ -1214,18 +1273,18 @@ static QVariant parseHttpDate(const QByteArray &raw)
return QVariant(); // transform an invalid QDateTime into a null QVariant
}
-static QVariant parseCookieHeader(QByteArrayView raw)
+static QList<QNetworkCookie> parseCookieHeader(QByteArrayView raw)
{
QList<QNetworkCookie> result;
for (auto cookie : QLatin1StringView(raw).tokenize(';'_L1)) {
QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie.trimmed());
if (parsed.size() != 1)
- return QVariant(); // invalid Cookie: header
+ return {}; // invalid Cookie: header
result += parsed;
}
- return QVariant::fromValue(result);
+ return result;
}
static QVariant parseETag(QByteArrayView raw)
@@ -1241,7 +1300,7 @@ static QVariant parseETag(QByteArrayView raw)
}
template<typename T>
-static QVariant parseMatchImpl(QByteArrayView raw, T op)
+static QStringList parseMatchImpl(QByteArrayView raw, T op)
{
const QByteArrayView trimmedRaw = raw.trimmed();
if (trimmedRaw == "*")
@@ -1256,14 +1315,14 @@ static QVariant parseMatchImpl(QByteArrayView raw, T op)
}
-static QVariant parseIfMatch(QByteArrayView raw)
+static QStringList parseIfMatch(QByteArrayView raw)
{
return parseMatchImpl(raw, [](QByteArrayView element) {
return element.startsWith('"') && element.endsWith('"');
});
}
-static QVariant parseIfNoneMatch(QByteArrayView raw)
+static QStringList parseIfNoneMatch(QByteArrayView raw)
{
return parseMatchImpl(raw, [](QByteArrayView element) {
return (element.startsWith('"') || element.startsWith(R"(W/")")) && element.endsWith('"');
@@ -1271,7 +1330,7 @@ static QVariant parseIfNoneMatch(QByteArrayView raw)
}
-static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QByteArray &value)
+static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, QByteArrayView value)
{
// header is always a valid value
switch (header) {
@@ -1311,40 +1370,127 @@ static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QBy
return parseIfNoneMatch(value);
case QNetworkRequest::CookieHeader:
- return parseCookieHeader(value);
+ return QVariant::fromValue(parseCookieHeader(value));
case QNetworkRequest::SetCookieHeader:
return QVariant::fromValue(QNetworkCookie::parseCookies(value));
default:
- Q_ASSERT(0);
+ Q_UNREACHABLE_RETURN({});
+ }
+}
+
+static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, QList<QByteArray> values)
+{
+ if (values.empty())
+ return QVariant();
+
+ // header is always a valid value
+ switch (header) {
+ case QNetworkRequest::IfMatchHeader: {
+ QStringList res;
+ for (const auto &val : values)
+ res << parseIfMatch(val);
+ return res;
+ }
+ case QNetworkRequest::IfNoneMatchHeader: {
+ QStringList res;
+ for (const auto &val : values)
+ res << parseIfNoneMatch(val);
+ return res;
+ }
+ case QNetworkRequest::CookieHeader: {
+ auto listOpt = QNetworkHeadersPrivate::toCookieList(values);
+ return listOpt.has_value() ? QVariant::fromValue(listOpt.value()) : QVariant();
+ }
+ case QNetworkRequest::SetCookieHeader: {
+ QList<QNetworkCookie> res;
+ for (const auto &val : values)
+ res << QNetworkCookie::parseCookies(val);
+ return QVariant::fromValue(res);
+ }
+ default:
+ return parseHeaderValue(header, values.first());
}
return QVariant();
}
-QNetworkHeadersPrivate::RawHeadersList::ConstIterator
-QNetworkHeadersPrivate::findRawHeader(QAnyStringView key) const
+static bool isSetCookie(QByteArrayView name)
{
- auto isKeyEqual = [key](const auto &headerPair)
- {
- QLatin1StringView name{headerPair.first};
- return QAnyStringView::compare(name, key, Qt::CaseInsensitive) == 0;
- };
- return std::find_if(rawHeaders.begin(), rawHeaders.end(), isKeyEqual);
+ return name.compare(QHttpHeaders::wellKnownHeaderName(QHttpHeaders::WellKnownHeader::SetCookie),
+ Qt::CaseInsensitive) == 0;
+}
+
+static bool isSetCookie(QHttpHeaders::WellKnownHeader name)
+{
+ return name == QHttpHeaders::WellKnownHeader::SetCookie;
}
-QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::allRawHeaders() const
+template<class HeaderName>
+static void setFromRawHeader(QHttpHeaders &headers, HeaderName header,
+ QByteArrayView value)
{
- return rawHeaders;
+ headers.removeAll(header);
+
+ if (value.isNull())
+ // only wanted to erase key
+ return;
+
+ if (isSetCookie(header)) {
+ for (auto cookie : QLatin1StringView(value).tokenize('\n'_L1))
+ headers.append(QHttpHeaders::WellKnownHeader::SetCookie, cookie);
+ } else {
+ headers.append(header, value);
+ }
+}
+
+const QNetworkHeadersPrivate::RawHeadersList &QNetworkHeadersPrivate::allRawHeaders() const
+{
+ if (rawHeaderCache.isCached)
+ return rawHeaderCache.headersList;
+
+ rawHeaderCache.headersList = fromHttpToRaw(httpHeaders);
+ rawHeaderCache.isCached = true;
+ return rawHeaderCache.headersList;
}
QList<QByteArray> QNetworkHeadersPrivate::rawHeadersKeys() const
{
+ if (httpHeaders.isEmpty())
+ return {};
+
QList<QByteArray> result;
- result.reserve(rawHeaders.size());
- for (const auto &pair : rawHeaders)
- result << pair.first;
+ result.reserve(httpHeaders.size());
+ QDuplicateTracker<QByteArray> seen(httpHeaders.size());
+ for (qsizetype i = 0; i < httpHeaders.size(); i++) {
+ const auto nameL1 = httpHeaders.nameAt(i);
+ const auto name = QByteArray(nameL1.data(), nameL1.size());
+ if (seen.hasSeen(name))
+ continue;
+
+ result << name;
+ }
+
+ return result;
+}
+
+QByteArray QNetworkHeadersPrivate::rawHeader(QAnyStringView headerName) const
+{
+ QByteArrayView setCookieStr = QHttpHeaders::wellKnownHeaderName(
+ QHttpHeaders::WellKnownHeader::SetCookie);
+ if (QAnyStringView::compare(headerName, setCookieStr, Qt::CaseInsensitive) != 0)
+ return httpHeaders.combinedValue(headerName);
+
+ QByteArray result;
+ const char* separator = "";
+ for (qsizetype i = 0; i < httpHeaders.size(); ++i) {
+ if (QAnyStringView::compare(httpHeaders.nameAt(i), headerName, Qt::CaseInsensitive) == 0) {
+ result.append(separator);
+ result.append(httpHeaders.valueAt(i));
+ separator = "\n";
+ }
+ }
return result;
}
@@ -1354,86 +1500,101 @@ void QNetworkHeadersPrivate::setRawHeader(const QByteArray &key, const QByteArra
// refuse to accept an empty raw header
return;
- setRawHeaderInternal(key, value);
+ setFromRawHeader(httpHeaders, key, value);
parseAndSetHeader(key, value);
-}
-/*!
- \internal
- Sets the internal raw headers list to match \a list. The cooked headers
- will also be updated.
-
- If \a list contains duplicates, they will be stored, but only the first one
- is usually accessed.
-*/
-void QNetworkHeadersPrivate::setAllRawHeaders(const RawHeadersList &list)
-{
- cookedHeaders.clear();
- rawHeaders = list;
-
- for (const auto &[key, value] : std::as_const(rawHeaders))
- parseAndSetHeader(key, value);
+ invalidateHeaderCache();
}
void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders header,
const QVariant &value)
{
- QByteArray name = headerName(header);
- if (name.isEmpty()) {
- // headerName verifies that \a header is a known value
+ const auto wellKnownOpt = toWellKnownHeader(header);
+ if (!wellKnownOpt) {
+ // verifies that \a header is a known value
qWarning("QNetworkRequest::setHeader: invalid header value KnownHeader(%d) received", header);
return;
}
if (value.isNull()) {
- setRawHeaderInternal(name, QByteArray());
+ httpHeaders.removeAll(wellKnownOpt.value());
cookedHeaders.remove(header);
} else {
QByteArray rawValue = headerValue(header, value);
if (rawValue.isEmpty()) {
qWarning("QNetworkRequest::setHeader: QVariant of type %s cannot be used with header %s",
- value.typeName(), name.constData());
+ value.typeName(),
+ QHttpHeaders::wellKnownHeaderName(wellKnownOpt.value()).constData());
return;
}
- setRawHeaderInternal(name, rawValue);
+ setFromRawHeader(httpHeaders, wellKnownOpt.value(), rawValue);
cookedHeaders.insert(header, value);
}
+
+ invalidateHeaderCache();
}
-void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value)
+QHttpHeaders QNetworkHeadersPrivate::headers() const
{
- auto firstEqualsKey = [&key](const RawHeaderPair &header) {
- return header.first.compare(key, Qt::CaseInsensitive) == 0;
- };
- rawHeaders.removeIf(firstEqualsKey);
+ return httpHeaders;
+}
- if (value.isNull())
- return; // only wanted to erase key
+void QNetworkHeadersPrivate::setHeaders(const QHttpHeaders &newHeaders)
+{
+ httpHeaders = newHeaders;
+ setCookedFromHttp(httpHeaders);
+ invalidateHeaderCache();
+}
+
+void QNetworkHeadersPrivate::setHeaders(QHttpHeaders &&newHeaders)
+{
+ httpHeaders = std::move(newHeaders);
+ setCookedFromHttp(httpHeaders);
+ invalidateHeaderCache();
+}
+
+void QNetworkHeadersPrivate::setHeader(QHttpHeaders::WellKnownHeader name, QByteArrayView value)
+{
+ httpHeaders.replaceOrAppend(name, value);
- RawHeaderPair pair;
- pair.first = key;
- pair.second = value;
- rawHeaders.append(pair);
+ // set cooked header
+ const auto knownHeaderOpt = toKnownHeader(name);
+ if (knownHeaderOpt)
+ parseAndSetHeader(knownHeaderOpt.value(), value);
+
+ invalidateHeaderCache();
+}
+
+void QNetworkHeadersPrivate::clearHeaders()
+{
+ httpHeaders.clear();
+ cookedHeaders.clear();
+ invalidateHeaderCache();
}
-void QNetworkHeadersPrivate::parseAndSetHeader(const QByteArray &key, const QByteArray &value)
+void QNetworkHeadersPrivate::parseAndSetHeader(QByteArrayView key, QByteArrayView value)
{
// is it a known header?
const int parsedKeyAsInt = parseHeaderName(key);
if (parsedKeyAsInt != -1) {
const QNetworkRequest::KnownHeaders parsedKey
= static_cast<QNetworkRequest::KnownHeaders>(parsedKeyAsInt);
- if (value.isNull()) {
- cookedHeaders.remove(parsedKey);
- } else if (parsedKey == QNetworkRequest::ContentLengthHeader
- && cookedHeaders.contains(QNetworkRequest::ContentLengthHeader)) {
- // Only set the cooked header "Content-Length" once.
- // See bug QTBUG-15311
- } else {
- cookedHeaders.insert(parsedKey, parseHeaderValue(parsedKey, value));
- }
+ parseAndSetHeader(parsedKey, value);
+ }
+}
+void QNetworkHeadersPrivate::parseAndSetHeader(QNetworkRequest::KnownHeaders key,
+ QByteArrayView value)
+{
+ if (value.isNull()) {
+ cookedHeaders.remove(key);
+ } else if (key == QNetworkRequest::ContentLengthHeader
+ && cookedHeaders.contains(QNetworkRequest::ContentLengthHeader)) {
+ // Only set the cooked header "Content-Length" once.
+ // See bug QTBUG-15311
+ } else {
+ cookedHeaders.insert(key, parseHeaderValue(key, value));
}
}
@@ -1487,7 +1648,7 @@ static int name_to_month(const char* month_str)
return 0;
}
-QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value)
+QDateTime QNetworkHeadersPrivate::fromHttpDate(QByteArrayView value)
{
// HTTP dates have three possible formats:
// RFC 1123/822 - ddd, dd MMM yyyy hh:mm:ss "GMT"
@@ -1536,6 +1697,137 @@ QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
return QLocale::c().toString(dt.toUTC(), u"ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1();
}
+QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::fromHttpToRaw(
+ const QHttpHeaders &headers)
+{
+ if (headers.isEmpty())
+ return {};
+
+ QNetworkHeadersPrivate::RawHeadersList list;
+ QHash<QByteArray, qsizetype> nameToIndex;
+ list.reserve(headers.size());
+ nameToIndex.reserve(headers.size());
+
+ for (qsizetype i = 0; i < headers.size(); ++i) {
+ const auto nameL1 = headers.nameAt(i);
+ const auto value = headers.valueAt(i);
+
+ const bool isSetCookie = nameL1 == QHttpHeaders::wellKnownHeaderName(
+ QHttpHeaders::WellKnownHeader::SetCookie);
+
+ const auto name = QByteArray(nameL1.data(), nameL1.size());
+ if (auto it = nameToIndex.find(name); it != nameToIndex.end()) {
+ list[it.value()].second += isSetCookie ? "\n" : ", ";
+ list[it.value()].second += value;
+ } else {
+ nameToIndex[name] = list.size();
+ list.emplaceBack(name, value.toByteArray());
+ }
+ }
+
+ return list;
+}
+
+QHttpHeaders QNetworkHeadersPrivate::fromRawToHttp(const RawHeadersList &raw)
+{
+ if (raw.empty())
+ return {};
+
+ QHttpHeaders headers;
+ headers.reserve(raw.size());
+
+ for (const auto &[key, value] : raw) {
+ const bool isSetCookie = key.compare(QHttpHeaders::wellKnownHeaderName(
+ QHttpHeaders::WellKnownHeader::SetCookie),
+ Qt::CaseInsensitive) == 0;
+ if (isSetCookie) {
+ for (auto header : QLatin1StringView(value).tokenize('\n'_L1))
+ headers.append(key, header);
+ } else {
+ headers.append(key, value);
+ }
+ }
+
+ return headers;
+}
+
+std::optional<qint64> QNetworkHeadersPrivate::toInt(QByteArrayView value)
+{
+ if (value.empty())
+ return std::nullopt;
+
+ bool ok;
+ qint64 res = value.toLongLong(&ok);
+ if (ok)
+ return res;
+ return std::nullopt;
+}
+
+std::optional<QNetworkHeadersPrivate::NetworkCookieList> QNetworkHeadersPrivate::toSetCookieList(
+ const QList<QByteArray> &values)
+{
+ if (values.empty())
+ return std::nullopt;
+
+ QList<QNetworkCookie> cookies;
+ for (const auto &s : values)
+ cookies += QNetworkCookie::parseCookies(s);
+
+ if (cookies.empty())
+ return std::nullopt;
+ return cookies;
+}
+
+QByteArray QNetworkHeadersPrivate::fromCookieList(const QList<QNetworkCookie> &cookies)
+{
+ return makeCookieHeader(cookies, QNetworkCookie::NameAndValueOnly, "; ");
+}
+
+std::optional<QNetworkHeadersPrivate::NetworkCookieList> QNetworkHeadersPrivate::toCookieList(
+ const QList<QByteArray> &values)
+{
+ if (values.empty())
+ return std::nullopt;
+
+ QList<QNetworkCookie> cookies;
+ for (const auto &s : values)
+ cookies += parseCookieHeader(s);
+
+ if (cookies.empty())
+ return std::nullopt;
+ return cookies;
+}
+
+void QNetworkHeadersPrivate::invalidateHeaderCache()
+{
+ rawHeaderCache.headersList.clear();
+ rawHeaderCache.isCached = false;
+}
+
+void QNetworkHeadersPrivate::setCookedFromHttp(const QHttpHeaders &newHeaders)
+{
+ cookedHeaders.clear();
+
+ QMap<QNetworkRequest::KnownHeaders, QList<QByteArray>> multipleHeadersMap;
+ for (int i = 0; i < newHeaders.size(); ++i) {
+ const auto name = newHeaders.nameAt(i);
+ const auto value = newHeaders.valueAt(i);
+
+ const int parsedKeyAsInt = parseHeaderName(name);
+ if (parsedKeyAsInt == -1)
+ continue;
+
+ const QNetworkRequest::KnownHeaders parsedKey
+ = static_cast<QNetworkRequest::KnownHeaders>(parsedKeyAsInt);
+
+ auto &list = multipleHeadersMap[parsedKey];
+ list.append(value.toByteArray());
+ }
+
+ for (auto i = multipleHeadersMap.cbegin(), end = multipleHeadersMap.cend(); i != end; ++i)
+ cookedHeaders.insert(i.key(), parseHeaderValue(i.key(), i.value()));
+}
+
QT_END_NAMESPACE
#include "moc_qnetworkrequest.cpp"
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index 3ca61a2ee3..e281c74834 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -5,6 +5,7 @@
#define QNETWORKREQUEST_H
#include <QtNetwork/qtnetworkglobal.h>
+#include <QtNetwork/qhttpheaders.h>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QString>
#include <QtCore/QUrl>
@@ -34,7 +35,8 @@ public:
IfModifiedSinceHeader,
ETagHeader,
IfMatchHeader,
- IfNoneMatchHeader
+ IfNoneMatchHeader,
+ NumKnownHeaders
};
Q_ENUM(KnownHeaders)
@@ -119,6 +121,10 @@ public:
QUrl url() const;
void setUrl(const QUrl &url);
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+
// "cooked" headers
QVariant header(KnownHeaders header) const;
void setHeader(KnownHeaders header, const QVariant &value);
diff --git a/src/network/access/qnetworkrequest_p.h b/src/network/access/qnetworkrequest_p.h
index 48fcdcf1ed..7268e1a4aa 100644
--- a/src/network/access/qnetworkrequest_p.h
+++ b/src/network/access/qnetworkrequest_p.h
@@ -16,6 +16,7 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtNetwork/qhttpheaders.h>
#include "qnetworkrequest.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qlist.h"
@@ -26,6 +27,8 @@
QT_BEGIN_NAMESPACE
+class QNetworkCookie;
+
// this is the common part between QNetworkRequestPrivate, QNetworkReplyPrivate and QHttpPartPrivate
class QNetworkHeadersPrivate
{
@@ -35,24 +38,49 @@ public:
typedef QHash<QNetworkRequest::KnownHeaders, QVariant> CookedHeadersMap;
typedef QHash<QNetworkRequest::Attribute, QVariant> AttributesMap;
- RawHeadersList rawHeaders;
+ mutable struct {
+ RawHeadersList headersList;
+ bool isCached = false;
+ } rawHeaderCache;
+
+ QHttpHeaders httpHeaders;
CookedHeadersMap cookedHeaders;
AttributesMap attributes;
QPointer<QObject> originatingObject;
- RawHeadersList::ConstIterator findRawHeader(QAnyStringView key) const;
- RawHeadersList allRawHeaders() const;
+ const RawHeadersList &allRawHeaders() const;
QList<QByteArray> rawHeadersKeys() const;
+ QByteArray rawHeader(QAnyStringView headerName) const;
void setRawHeader(const QByteArray &key, const QByteArray &value);
- void setAllRawHeaders(const RawHeadersList &list);
void setCookedHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
- static QDateTime fromHttpDate(const QByteArray &value);
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+ void setHeader(QHttpHeaders::WellKnownHeader name, QByteArrayView value);
+
+ void clearHeaders();
+
+ static QDateTime fromHttpDate(QByteArrayView value);
static QByteArray toHttpDate(const QDateTime &dt);
+ static std::optional<qint64> toInt(QByteArrayView value);
+
+ typedef QList<QNetworkCookie> NetworkCookieList;
+ static QByteArray fromCookieList(const NetworkCookieList &cookies);
+ static std::optional<NetworkCookieList> toSetCookieList(const QList<QByteArray> &values);
+ static std::optional<NetworkCookieList> toCookieList(const QList<QByteArray> &values);
+
+ static RawHeadersList fromHttpToRaw(const QHttpHeaders &headers);
+ static QHttpHeaders fromRawToHttp(const RawHeadersList &raw);
+
private:
- void setRawHeaderInternal(const QByteArray &key, const QByteArray &value);
- void parseAndSetHeader(const QByteArray &key, const QByteArray &value);
+ void invalidateHeaderCache();
+
+ void setCookedFromHttp(const QHttpHeaders &newHeaders);
+ void parseAndSetHeader(QByteArrayView key, QByteArrayView value);
+ void parseAndSetHeader(QNetworkRequest::KnownHeaders key, QByteArrayView value);
+
};
Q_DECLARE_TYPEINFO(QNetworkHeadersPrivate::RawHeaderPair, Q_RELOCATABLE_TYPE);
diff --git a/src/network/access/qnetworkrequestfactory.cpp b/src/network/access/qnetworkrequestfactory.cpp
index 87738d9086..d9c536cef2 100644
--- a/src/network/access/qnetworkrequestfactory.cpp
+++ b/src/network/access/qnetworkrequestfactory.cpp
@@ -615,17 +615,11 @@ QNetworkRequest QNetworkRequestFactoryPrivate::newRequest(const QUrl &url) const
if (!sslConfig.isNull())
request.setSslConfiguration(sslConfig);
#endif
- // Set the header entries to the request. Combine values as there
- // may be multiple values per name. Note: this would not necessarily
- // produce right result for 'Set-Cookie' header if it has multiple values,
- // but since it is a purely server-side (response) header, not relevant here.
- const auto headerNames = headers.toMultiMap().uniqueKeys(); // ### fixme: port QNR to QHH
- for (const auto &name : headerNames)
- request.setRawHeader(name, headers.combinedValue(name));
-
+ auto h = headers;
constexpr char Bearer[] = "Bearer ";
if (!bearerToken.isEmpty())
- request.setRawHeader("Authorization"_ba, Bearer + bearerToken);
+ h.replaceOrAppend(QHttpHeaders::WellKnownHeader::Authorization, Bearer + bearerToken);
+ request.setHeaders(std::move(h));
request.setTransferTimeout(transferTimeout);
request.setPriority(priority);
diff --git a/src/network/access/qrestaccessmanager_p.h b/src/network/access/qrestaccessmanager_p.h
index 51af299f5c..2e6c1afb90 100644
--- a/src/network/access/qrestaccessmanager_p.h
+++ b/src/network/access/qrestaccessmanager_p.h
@@ -61,10 +61,12 @@ public:
return warnNoAccessManager();
verifyThreadAffinity(context);
QNetworkRequest req(request);
- if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
- req.setHeader(QNetworkRequest::ContentTypeHeader,
- QLatin1StringView{"application/json"});
+ auto h = req.headers();
+ if (!h.contains(QHttpHeaders::WellKnownHeader::ContentType)) {
+ h.append(QHttpHeaders::WellKnownHeader::ContentType,
+ QLatin1StringView{"application/json"});
}
+ req.setHeaders(std::move(h));
QNetworkReply *reply = requestOperation(qnam, req, jsonDoc.toJson(QJsonDocument::Compact));
return createActiveRequest(reply, context, slot);
}
diff --git a/src/network/access/qrestreply.cpp b/src/network/access/qrestreply.cpp
index 3cc62c7efa..2d8d101084 100644
--- a/src/network/access/qrestreply.cpp
+++ b/src/network/access/qrestreply.cpp
@@ -4,11 +4,17 @@
#include "qrestreply.h"
#include "qrestreply_p.h"
+#include <QtNetwork/private/qnetworkreply_p.h>
+
+#include <QtCore/qbytearrayview.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qlatin1stringmatcher.h>
+#include <QtCore/qlatin1stringview.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qstringconverter.h>
+#include <QtCore/qxpfunctional.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -329,12 +335,255 @@ QDebug operator<<(QDebug debug, const QRestReply &reply)
<< ", bytesAvailable = " << reply.networkReply()->bytesAvailable()
<< ", url " << reply.networkReply()->url()
<< ", operation = " << operationName(reply.networkReply()->operation())
- << ", reply headers = " << reply.networkReply()->rawHeaderPairs()
+ << ", reply headers = " << reply.networkReply()->headers()
<< ")";
return debug;
}
#endif // QT_NO_DEBUG_STREAM
+static constexpr auto parse_OWS(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView ows, tail;
+ };
+
+ constexpr auto is_OWS_char = [](auto ch) { return ch == ' ' || ch == '\t'; };
+
+ qsizetype i = 0;
+ while (i < data.size() && is_OWS_char(data[i]))
+ ++i;
+
+ return R{data.first(i), data.sliced(i)};
+}
+
+static constexpr void eat_OWS(QByteArrayView &data) noexcept
+{
+ data = parse_OWS(data).tail;
+}
+
+static constexpr auto parse_quoted_string(QByteArrayView data, qxp::function_ref<void(char) const> yield)
+{
+ struct R {
+ QByteArrayView quotedString, tail;
+ constexpr explicit operator bool() const noexcept { return !quotedString.isEmpty(); }
+ };
+
+ if (!data.startsWith('"'))
+ return R{{}, data};
+
+ qsizetype i = 1; // one past initial DQUOTE
+ while (i < data.size()) {
+ switch (auto ch = data[i++]) {
+ case '"': // final DQUOTE -> end of string
+ return R{data.first(i), data.sliced(i)};
+ case '\\': // quoted-pair
+ // https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.4-3:
+ // Recipients that process the value of a quoted-string MUST handle a
+ // quoted-pair as if it were replaced by the octet following the backslash.
+ if (i == data.size())
+ break; // premature end
+ ch = data[i++]; // eat '\\'
+ [[fallthrough]];
+ default:
+ // we don't validate quoted-string octets to be only qdtext (Postel's Law)
+ yield(ch);
+ }
+ }
+
+ return R{{}, data}; // premature end
+}
+
+static constexpr bool is_tchar(char ch) noexcept
+{
+ // ### optimize
+ switch (ch) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ return true;
+ default:
+ return (ch >= 'a' && ch <= 'z')
+ || (ch >= '0' && ch <= '9')
+ || (ch >= 'A' && ch <= 'Z');
+ }
+}
+
+static constexpr auto parse_comment(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView comment, tail;
+ constexpr explicit operator bool() const noexcept { return !comment.isEmpty(); }
+ };
+
+ const auto invalid = R{{}, data}; // preserves original `data`
+
+ // comment = "(" *( ctext / quoted-pair / comment ) ")"
+ // ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text
+
+ if (!data.startsWith('('))
+ return invalid;
+
+ qsizetype i = 1;
+ qsizetype level = 1;
+ while (i < data.size()) {
+ switch (data[i++]) {
+ case '(': // nested comment
+ ++level;
+ break;
+ case ')': // end of comment
+ if (--level == 0)
+ return R{data.first(i), data.sliced(i)};
+ break;
+ case '\\': // quoted-pair
+ if (i == data.size())
+ return invalid; // premature end
+ ++i; // eat escaped character
+ break;
+ default:
+ ; // don't validate ctext - accept everything (Postel's Law)
+ }
+ }
+
+ return invalid; // premature end / unbalanced nesting levels
+}
+
+static constexpr void eat_CWS(QByteArrayView &data) noexcept
+{
+ eat_OWS(data);
+ while (const auto comment = parse_comment(data)) {
+ data = comment.tail;
+ eat_OWS(data);
+ }
+}
+
+static constexpr auto parse_token(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView token, tail;
+ constexpr explicit operator bool() const noexcept { return !token.isEmpty(); }
+ };
+
+ qsizetype i = 0;
+ while (i < data.size() && is_tchar(data[i]))
+ ++i;
+
+ return R{data.first(i), data.sliced(i)};
+}
+
+static constexpr auto parse_parameter(QByteArrayView data, qxp::function_ref<void(char) const> yield)
+{
+ struct R {
+ QLatin1StringView name; QByteArrayView value; QByteArrayView tail;
+ constexpr explicit operator bool() const noexcept { return !name.isEmpty(); }
+ };
+
+ const auto invalid = R{{}, {}, data}; // preserves original `data`
+
+ // parameter = parameter-name "=" parameter-value
+ // parameter-name = token
+ // parameter-value = ( token / quoted-string )
+
+ const auto name = parse_token(data);
+ if (!name)
+ return invalid;
+ data = name.tail;
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (!data.startsWith('='))
+ return invalid;
+ data = data.sliced(1);
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (Q_UNLIKELY(data.startsWith('"'))) { // value is a quoted-string
+
+ const auto value = parse_quoted_string(data, yield);
+ if (!value)
+ return invalid;
+ data = value.tail;
+
+ return R{QLatin1StringView{name.token}, value.quotedString, data};
+
+ } else { // value is a token
+
+ const auto value = parse_token(data);
+ if (!value)
+ return invalid;
+ data = value.tail;
+
+ return R{QLatin1StringView{name.token}, value.token, data};
+ }
+}
+
+static auto parse_content_type(QByteArrayView data)
+{
+ struct R {
+ QLatin1StringView type, subtype;
+ std::string charset;
+ constexpr explicit operator bool() const noexcept { return !type.isEmpty(); }
+ };
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ const auto type = parse_token(data);
+ if (!type)
+ return R{};
+ data = type.tail;
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (!data.startsWith('/'))
+ return R{};
+ data = data.sliced(1);
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ const auto subtype = parse_token(data);
+ if (!subtype)
+ return R{};
+ data = subtype.tail;
+
+ eat_CWS(data);
+
+ auto r = R{QLatin1StringView{type.token}, QLatin1StringView{subtype.token}, {}};
+
+ while (data.startsWith(';')) {
+
+ data = data.sliced(1); // eat ';'
+
+ eat_CWS(data);
+
+ const auto param = parse_parameter(data, [&](char ch) { r.charset.append(1, ch); });
+ if (param.name.compare("charset"_L1, Qt::CaseInsensitive) == 0) {
+ if (r.charset.empty() && !param.value.startsWith('"')) // wasn't a quoted-string
+ r.charset.assign(param.value.begin(), param.value.end());
+ return r; // charset found
+ }
+ r.charset.clear(); // wasn't an actual charset
+ if (param.tail.size() == data.size()) // no progress was made
+ break; // returns {type, subtype}
+ // otherwise, continue (accepting e.g. `;;`)
+ data = param.tail;
+
+ eat_CWS(data);
+ }
+
+ return r; // no charset found
+}
+
QByteArray QRestReplyPrivate::contentCharset(const QNetworkReply* reply)
{
// Content-type consists of mimetype and optional parameters, of which one may be 'charset'
@@ -345,28 +594,15 @@ QByteArray QRestReplyPrivate::contentCharset(const QNetworkReply* reply)
// text/plain; charset=utf-8;version=1.7
// text/plain; charset = utf-8
// text/plain; charset ="utf-8"
- // Default to the most commonly used UTF-8.
- QByteArray charset{"UTF-8"};
+
const QByteArray contentTypeValue =
- reply->header(QNetworkRequest::KnownHeaders::ContentTypeHeader).toByteArray();
-
- QList<QByteArray> parameters = contentTypeValue.split(';');
- if (parameters.size() >= 2) { // Need at least one parameter in addition to the mimetype itself
- parameters.removeFirst(); // Exclude the mimetype itself, only interested in parameters
- QLatin1StringMatcher matcher("charset="_L1, Qt::CaseSensitivity::CaseInsensitive);
- qsizetype matchIndex = -1;
- for (auto &parameter : parameters) {
- // Remove whitespaces and parantheses
- const QByteArray curated = parameter.replace(" ", "").replace("\"","");
- // Check for match
- matchIndex = matcher.indexIn(QLatin1String(curated.constData()));
- if (matchIndex >= 0) {
- charset = curated.sliced(matchIndex + 8); // 8 is size of "charset="
- break;
- }
- }
- }
- return charset;
+ reply->headers().value(QHttpHeaders::WellKnownHeader::ContentType).toByteArray();
+
+ const auto r = parse_content_type(contentTypeValue);
+ if (r && !r.charset.empty())
+ return QByteArrayView(r.charset).toByteArray();
+ else
+ return "UTF-8"_ba; // Default to the most commonly used UTF-8.
}
QT_END_NAMESPACE
diff --git a/src/network/access/qsocketabstraction_p.h b/src/network/access/qsocketabstraction_p.h
new file mode 100644
index 0000000000..2b40b80244
--- /dev/null
+++ b/src/network/access/qsocketabstraction_p.h
@@ -0,0 +1,91 @@
+// 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 QSOCKETABSTRACTION_P_H
+#define QSOCKETABSTRACTION_P_H
+
+#include <private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qlocalsocket.h>
+
+#include <QtCore/qxpfunctional.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+// Helper functions to deal with a QIODevice that is either a socket or a local
+// socket.
+namespace QSocketAbstraction {
+template <typename Fn, typename... Args>
+auto visit(Fn &&fn, QIODevice *socket, Args &&...args)
+{
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket))
+ return std::forward<Fn>(fn)(s, std::forward<Args>(args)...);
+ if (auto *s = qobject_cast<QLocalSocket *>(socket))
+ return std::forward<Fn>(fn)(s, std::forward<Args>(args)...);
+ Q_UNREACHABLE();
+}
+
+// Since QLocalSocket's LocalSocketState's values are defined as being equal
+// to some of QAbstractSocket's SocketState's values, we can use the superset
+// of the two as the return type.
+inline QAbstractSocket::SocketState socketState(QIODevice *device)
+{
+ auto getState = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->state();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ QLocalSocket::LocalSocketState st = s->state();
+ return static_cast<QAbstractSocket::SocketState>(st);
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getState, device);
+}
+
+// Same as for socketState(), but for the errors
+inline QAbstractSocket::SocketError socketError(QIODevice *device)
+{
+ auto getError = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->error();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ QLocalSocket::LocalSocketError st = s->error();
+ return static_cast<QAbstractSocket::SocketError>(st);
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getError, device);
+}
+
+inline QString socketPeerName(QIODevice *device)
+{
+ auto getPeerName = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->peerName();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ return s->serverName();
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getPeerName, device);
+}
+} // namespace QSocketAbstraction
+
+QT_END_NAMESPACE
+
+#endif // QSOCKETABSTRACTION_P_H
diff --git a/src/network/compat/removed_api.cpp b/src/network/compat/removed_api.cpp
index 86951d9222..ceda117538 100644
--- a/src/network/compat/removed_api.cpp
+++ b/src/network/compat/removed_api.cpp
@@ -58,6 +58,9 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin
#if QT_NETWORK_REMOVED_SINCE(6, 8)
+#if QT_CONFIG(dnslookup)
+# include "qdnslookup.h" // inlined API
+#endif
#include "qnetworkrequest.h" // inlined API
// #include "qotherheader.h"
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index c310c7e28e..1b4db7130b 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -8,14 +8,22 @@
#include <qapplicationstatic.h>
#include <qcoreapplication.h>
#include <qdatetime.h>
+#include <qendian.h>
#include <qloggingcategory.h>
#include <qrandom.h>
+#include <qspan.h>
#include <qurl.h>
+#if QT_CONFIG(ssl)
+# include <qsslsocket.h>
+#endif
+
#include <algorithm>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static Q_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg)
namespace {
@@ -159,6 +167,42 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
\note If you simply want to find the IP address(es) associated with a host
name, or the host name associated with an IP address you should use
QHostInfo instead.
+
+ \section1 DNS-over-TLS and Authentic Data
+
+ QDnsLookup supports DNS-over-TLS (DoT, as specified by \l{RFC 7858}) on
+ some platforms. That currently includes all Unix platforms where regular
+ queries are supported, if \l QSslSocket support is present in Qt. To query
+ if support is present at runtime, use isProtocolSupported().
+
+ When using DNS-over-TLS, QDnsLookup only implements the "Opportunistic
+ Privacy Profile" method of authentication, as described in \l{RFC 7858}
+ section 4.1. In this mode, QDnsLookup (through \l QSslSocket) only
+ validates that the server presents a certificate that is valid for the
+ server being connected to. Clients may use setSslConfiguration() to impose
+ additional restrictions and sslConfiguration() to obtain information after
+ the query is complete.
+
+ QDnsLookup will request DNS servers queried over TLS to perform
+ authentication on the data they return. If they confirm the data is valid,
+ the \l authenticData property will be set to true. QDnsLookup does not
+ verify the integrity of the data by itself, so applications should only
+ trust this property on servers they have confirmed through other means to
+ be trustworthy.
+
+ \section2 Authentic Data without TLS
+
+ QDnsLookup request Authentic Data for any server set with setNameserver(),
+ even if TLS encryption is not required. This is useful when querying a
+ caching nameserver on the same host as the application or on a trusted
+ network. Though similar to the TLS case, the application is responsible for
+ determining if the server it chose to use is trustworthy, and if the
+ unencrypted connection cannot be tampered with.
+
+ QDnsLookup obeys the system configuration to request Authentic Data on the
+ default nameserver (that is, if setNameserver() is not called). This is
+ currently only supported on Linux systems using glibc 2.31 or later. On any
+ other systems, QDnsLookup will ignore the AD bit in the query header.
*/
/*!
@@ -213,10 +257,72 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
\value SRV service records.
+ \value[since 6.8] TLSA TLS association records.
+
\value TXT text records.
*/
/*!
+ \enum QDnsLookup::Protocol
+
+ Indicates the type of DNS server that is being queried.
+
+ \value Standard
+ Regular, unencrypted DNS, using UDP and falling back to TCP as necessary
+ (default port: 53)
+
+ \value DnsOverTls
+ Encrypted DNS over TLS (DoT, as specified by \l{RFC 7858}), over TCP
+ (default port: 853)
+
+ \sa isProtocolSupported(), nameserverProtocol, setNameserver()
+*/
+
+/*!
+ \since 6.8
+
+ Returns true if DNS queries using \a protocol are supported with QDnsLookup.
+
+ \sa nameserverProtocol
+*/
+bool QDnsLookup::isProtocolSupported(Protocol protocol)
+{
+#if QT_CONFIG(libresolv) || defined(Q_OS_WIN)
+ switch (protocol) {
+ case QDnsLookup::Standard:
+ return true;
+ case QDnsLookup::DnsOverTls:
+# if QT_CONFIG(ssl)
+ if (QSslSocket::supportsSsl())
+ return true;
+# endif
+ return false;
+ }
+#else
+ Q_UNUSED(protocol)
+#endif
+ return false;
+}
+
+/*!
+ \since 6.8
+
+ Returns the standard (default) port number for the protocol \a protocol.
+
+ \sa isProtocolSupported()
+*/
+quint16 QDnsLookup::defaultPortForProtocol(Protocol protocol) noexcept
+{
+ switch (protocol) {
+ case QDnsLookup::Standard:
+ return DnsPort;
+ case QDnsLookup::DnsOverTls:
+ return DnsOverTlsPort;
+ }
+ return 0; // will probably fail somewhere
+}
+
+/*!
\fn void QDnsLookup::finished()
This signal is emitted when the reply has finished processing.
@@ -270,7 +376,7 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
*/
QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
- : QDnsLookup(type, name, nameserver, DnsPort, parent)
+ : QDnsLookup(type, name, nameserver, 0, parent)
{
}
@@ -285,8 +391,9 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &names
//! [nameserver-port]
\note Setting the port number to any value other than the default (53) can
cause the name resolution to fail, depending on the operating system
- limitations and firewalls. Notably, the Windows API used by QDnsLookup is
- unable to handle alternate port numbers.
+ limitations and firewalls, if the nameserverProtocol() to be used
+ QDnsLookup::Standard. Notably, the Windows API used by QDnsLookup is unable
+ to handle alternate port numbers.
//! [nameserver-port]
*/
QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
@@ -300,6 +407,30 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &names
}
/*!
+ \since 6.8
+
+ Constructs a QDnsLookup object to issue a query for \a name of record type
+ \a type, using the DNS server \a nameserver running on port \a port, and
+ sets \a parent as the parent object.
+
+ The query will be sent using \a protocol, if supported. Use
+ isProtocolSupported() to check if it is supported.
+
+ \include qdnslookup.cpp nameserver-port
+*/
+QDnsLookup::QDnsLookup(Type type, const QString &name, Protocol protocol,
+ const QHostAddress &nameserver, quint16 port, QObject *parent)
+ : QObject(*new QDnsLookupPrivate, parent)
+{
+ Q_D(QDnsLookup);
+ d->name = name;
+ d->type = type;
+ d->nameserver = nameserver;
+ d->port = port;
+ d->protocol = protocol;
+}
+
+/*!
Destroys the QDnsLookup object.
It is safe to delete a QDnsLookup object even if it is not finished, you
@@ -311,6 +442,28 @@ QDnsLookup::~QDnsLookup()
}
/*!
+ \since 6.8
+ \property QDnsLookup::authenticData
+ \brief whether the reply was authenticated by the resolver.
+
+ QDnsLookup does not perform the authentication itself. Instead, it trusts
+ the name server that was queried to perform the authentication and report
+ it. The application is responsible for determining if any servers it
+ configured with setNameserver() are trustworthy; if no server was set,
+ QDnsLookup obeys system configuration on whether responses should be
+ trusted.
+
+ This property may be set even if error() indicates a resolver error
+ occurred.
+
+ \sa setNameserver(), nameserverProtocol()
+*/
+bool QDnsLookup::isAuthenticData() const
+{
+ return d_func()->reply.authenticData;
+}
+
+/*!
\property QDnsLookup::error
\brief the type of error that occurred if the DNS lookup failed, or NoError.
*/
@@ -416,6 +569,10 @@ QBindable<QHostAddress> QDnsLookup::bindableNameserver()
\property QDnsLookup::nameserverPort
\since 6.6
\brief the port number of nameserver to use for DNS lookup.
+
+ The value of 0 indicates that QDnsLookup should use the default port for
+ the nameserverProtocol().
+
\include qdnslookup.cpp nameserver-port
*/
@@ -437,18 +594,44 @@ QBindable<quint16> QDnsLookup::bindableNameserverPort()
}
/*!
+ \property QDnsLookup::nameserverProtocol
+ \since 6.8
+ \brief the protocol to use when sending the DNS query
+
+ \sa isProtocolSupported()
+*/
+QDnsLookup::Protocol QDnsLookup::nameserverProtocol() const
+{
+ return d_func()->protocol;
+}
+
+void QDnsLookup::setNameserverProtocol(Protocol protocol)
+{
+ d_func()->protocol = protocol;
+}
+
+QBindable<QDnsLookup::Protocol> QDnsLookup::bindableNameserverProtocol()
+{
+ return &d_func()->protocol;
+}
+
+/*!
+ \fn void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
\since 6.6
+
Sets the nameserver to \a nameserver and the port to \a port.
\include qdnslookup.cpp nameserver-port
\sa QDnsLookup::nameserver, QDnsLookup::nameserverPort
*/
-void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
+
+void QDnsLookup::setNameserver(Protocol protocol, const QHostAddress &nameserver, quint16 port)
{
Qt::beginPropertyUpdateGroup();
setNameserver(nameserver);
setNameserverPort(port);
+ setNameserverProtocol(protocol);
Qt::endPropertyUpdateGroup();
}
@@ -524,6 +707,46 @@ QList<QDnsTextRecord> QDnsLookup::textRecords() const
}
/*!
+ \since 6.8
+ Returns the list of TLS association records associated with this lookup.
+
+ According to the standards relating to DNS-based Authentication of Named
+ Entities (DANE), this field should be ignored and must not be used for
+ verifying the authentity of a given server if the authenticity of the DNS
+ reply cannot itself be confirmed. See isAuthenticData() for more
+ information.
+ */
+QList<QDnsTlsAssociationRecord> QDnsLookup::tlsAssociationRecords() const
+{
+ return d_func()->reply.tlsAssociationRecords;
+}
+
+#if QT_CONFIG(ssl)
+/*!
+ \since 6.8
+ Sets the \a sslConfiguration to use for outgoing DNS-over-TLS connections.
+
+ \sa sslConfiguration(), QSslSocket::setSslConfiguration()
+*/
+void QDnsLookup::setSslConfiguration(const QSslConfiguration &sslConfiguration)
+{
+ Q_D(QDnsLookup);
+ d->sslConfiguration.emplace(sslConfiguration);
+}
+
+/*!
+ Returns the current SSL configuration.
+
+ \sa setSslConfiguration()
+*/
+QSslConfiguration QDnsLookup::sslConfiguration() const
+{
+ const Q_D(QDnsLookup);
+ return d->sslConfiguration.value_or(QSslConfiguration::defaultConfiguration());
+}
+#endif
+
+/*!
Aborts the DNS lookup operation.
If the lookup is already finished, does nothing.
@@ -565,6 +788,9 @@ void QDnsLookup::lookup()
#ifdef QDNSLOOKUP_DEBUG
qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
#endif
+#if QT_CONFIG(ssl)
+ d->sslConfiguration = std::move(reply.sslConfiguration);
+#endif
d->reply = reply;
d->runnable = nullptr;
d->isFinished = true;
@@ -1052,6 +1278,223 @@ QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
very fast and never fails.
*/
+/*!
+ \class QDnsTlsAssociationRecord
+ \since 6.8
+ \brief The QDnsTlsAssociationRecord class stores information about a DNS TLSA record.
+
+ \inmodule QtNetwork
+ \ingroup network
+ \ingroup shared
+
+ When performing a text lookup, zero or more records will be returned. Each
+ record is represented by a QDnsTlsAssociationRecord instance.
+
+ The meaning of the fields is defined in \l{RFC 6698}.
+
+ \sa QDnsLookup
+*/
+
+QT_DEFINE_QSDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
+
+/*!
+ \enum QDnsTlsAssociationRecord::CertificateUsage
+
+ This enumeration contains valid values for the certificate usage field of
+ TLS Association queries. The following list is up-to-date with \l{RFC 6698}
+ section 2.1.1 and RFC 7218 section 2.1. Please refer to those documents for
+ authoritative instructions on interpreting this enumeration.
+
+ \value CertificateAuthorityConstrait
+ Indicates the record includes an association to a specific Certificate
+ Authority that must be found in the TLS server's certificate chain and
+ must pass PKIX validation.
+
+ \value ServiceCertificateConstraint
+ Indicates the record includes an association to a certificate that must
+ match the end entity certificate provided by the TLS server and must
+ pass PKIX validation.
+
+ \value TrustAnchorAssertion
+ Indicates the record includes an association to a certificate that MUST
+ be used as the ultimate trust anchor to validate the TLS server's
+ certificate and must pass PKIX validation.
+
+ \value DomainIssuedCertificate
+ Indicates the record includes an association to a certificate that must
+ match the end entity certificate provided by the TLS server. PKIX
+ validation is not tested.
+
+ \value PrivateUse
+ No standard meaning applied.
+
+ \value PKIX_TA
+ Alias; mnemonic for Public Key Infrastructure Trust Anchor
+
+ \value PKIX_EE
+ Alias; mnemonic for Public Key Infrastructure End Entity
+
+ \value DANE_TA
+ Alias; mnemonic for DNS-based Authentication of Named Entities Trust Anchor
+
+ \value DANE_EE
+ Alias; mnemonic for DNS-based Authentication of Named Entities End Entity
+
+ \value PrivCert
+ Alias
+
+ Other values are currently reserved, but may be unreserved by future
+ standards. This enumeration can be used for those values even if no
+ enumerator is provided.
+
+ \sa certificateUsage()
+*/
+
+/*!
+ \enum QDnsTlsAssociationRecord::Selector
+
+ This enumeration contains valid values for the selector field of TLS
+ Association queries. The following list is up-to-date with \l{RFC 6698}
+ section 2.1.2 and RFC 7218 section 2.2. Please refer to those documents for
+ authoritative instructions on interpreting this enumeration.
+
+ \value FullCertificate
+ Indicates this record refers to the full certificate in its binary
+ structure form.
+
+ \value SubjectPublicKeyInfo
+ Indicates the record refers to the certificate's subject and public
+ key information, in DER-encoded binary structure form.
+
+ \value PrivateUse
+ No standard meaning applied.
+
+ \value Cert
+ Alias
+
+ \value SPKI
+ Alias
+
+ \value PrivSel
+ Alias
+
+ Other values are currently reserved, but may be unreserved by future
+ standards. This enumeration can be used for those values even if no
+ enumerator is provided.
+
+ \sa selector()
+*/
+
+/*!
+ \enum QDnsTlsAssociationRecord::MatchingType
+
+ This enumeration contains valid values for the matching type field of TLS
+ Association queries. The following list is up-to-date with \l{RFC 6698}
+ section 2.1.3 and RFC 7218 section 2.3. Please refer to those documents for
+ authoritative instructions on interpreting this enumeration.
+
+ \value Exact
+ Indicates this the certificate or SPKI data is stored verbatim in this
+ record.
+
+ \value Sha256
+ Indicates this a SHA-256 checksum of the the certificate or SPKI data
+ present in this record.
+
+ \value Sha512
+ Indicates this a SHA-512 checksum of the the certificate or SPKI data
+ present in this record.
+
+ \value PrivateUse
+ No standard meaning applied.
+
+ \value PrivMatch
+ Alias
+
+ Other values are currently reserved, but may be unreserved by future
+ standards. This enumeration can be used for those values even if no
+ enumerator is provided.
+
+ \sa matchingType()
+*/
+
+/*!
+ Constructs an empty TLS Association record.
+ */
+QDnsTlsAssociationRecord::QDnsTlsAssociationRecord()
+ : d(new QDnsTlsAssociationRecordPrivate)
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+ */
+QDnsTlsAssociationRecord::QDnsTlsAssociationRecord(const QDnsTlsAssociationRecord &other) = default;
+
+/*!
+ Moves the content of \a other into this object.
+ */
+QDnsTlsAssociationRecord &
+QDnsTlsAssociationRecord::operator=(const QDnsTlsAssociationRecord &other) = default;
+
+/*!
+ Destroys this TLS Association record object.
+ */
+QDnsTlsAssociationRecord::~QDnsTlsAssociationRecord() = default;
+
+/*!
+ Returns the name of this record.
+*/
+QString QDnsTlsAssociationRecord::name() const
+{
+ return d->name;
+}
+
+/*!
+ Returns the duration in seconds for which this record is valid.
+*/
+quint32 QDnsTlsAssociationRecord::timeToLive() const
+{
+ return d->timeToLive;
+}
+
+/*!
+ Returns the certificate usage field for this record.
+ */
+QDnsTlsAssociationRecord::CertificateUsage QDnsTlsAssociationRecord::usage() const
+{
+ return d->usage;
+}
+
+/*!
+ Returns the selector field for this record.
+ */
+QDnsTlsAssociationRecord::Selector QDnsTlsAssociationRecord::selector() const
+{
+ return d->selector;
+}
+
+/*!
+ Returns the match type field for this record.
+ */
+QDnsTlsAssociationRecord::MatchingType QDnsTlsAssociationRecord::matchType() const
+{
+ return d->matchType;
+}
+
+/*!
+ Returns the binary data field for this record. The interpretation of this
+ binary data depends on the three numeric fields provided by
+ certificateUsage(), selector(), and matchType().
+
+ Do note this is a binary field, even for the checksums, similar to what
+ QCyrptographicHash::result() returns.
+ */
+QByteArray QDnsTlsAssociationRecord::value() const
+{
+ return d->value;
+}
+
static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
{
QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
@@ -1070,8 +1513,14 @@ inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d)
: requestName(encodeLabel(d->name)),
nameserver(d->nameserver),
requestType(d->type),
- port(d->port)
+ port(d->port),
+ protocol(d->protocol)
{
+ if (port == 0)
+ port = QDnsLookup::defaultPortForProtocol(protocol);
+#if QT_CONFIG(ssl)
+ sslConfiguration = d->sslConfiguration;
+#endif
}
void QDnsLookupRunnable::run()
@@ -1120,12 +1569,103 @@ inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
if (r->requestName.size() > MaxDomainNameLength)
d << "... (truncated)";
d << " type " << r->requestType;
- if (!r->nameserver.isNull())
+ if (!r->nameserver.isNull()) {
d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
- << " port " << (r->port ? r->port : DnsPort);
+ << " port " << (r->port ? r->port : QDnsLookup::defaultPortForProtocol(r->protocol));
+ switch (r->protocol) {
+ case QDnsLookup::Standard:
+ break;
+ case QDnsLookup::DnsOverTls:
+ d << " (TLS)";
+ }
+ }
return d;
}
+#if QT_CONFIG(ssl)
+static constexpr std::chrono::milliseconds DnsOverTlsConnectTimeout(15'000);
+static constexpr std::chrono::milliseconds DnsOverTlsTimeout(120'000);
+static constexpr quint8 DnsAuthenticDataBit = 0x20;
+
+static int makeReplyErrorFromSocket(QDnsLookupReply *reply, const QAbstractSocket *socket)
+{
+ QDnsLookup::Error error = [&] {
+ switch (socket->error()) {
+ case QAbstractSocket::SocketTimeoutError:
+ case QAbstractSocket::ProxyConnectionTimeoutError:
+ return QDnsLookup::TimeoutError;
+ default:
+ return QDnsLookup::ResolverError;
+ }
+ }();
+ reply->setError(error, socket->errorString());
+ return false;
+}
+
+bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
+ ReplyBuffer &response)
+{
+ QSslSocket socket;
+ socket.setSslConfiguration(sslConfiguration.value_or(QSslConfiguration::defaultConfiguration()));
+
+# if QT_CONFIG(networkproxy)
+ socket.setProtocolTag("domain-s"_L1);
+# endif
+
+ // Request the name server attempt to authenticate the reply.
+ query[3] |= DnsAuthenticDataBit;
+
+ do {
+ quint16 size = qToBigEndian<quint16>(query.size());
+ QDeadlineTimer timeout(DnsOverTlsTimeout);
+
+ socket.connectToHostEncrypted(nameserver.toString(), port);
+ socket.write(reinterpret_cast<const char *>(&size), sizeof(size));
+ socket.write(reinterpret_cast<const char *>(query.data()), query.size());
+ if (!socket.waitForEncrypted(DnsOverTlsConnectTimeout.count()))
+ break;
+
+ reply->sslConfiguration = socket.sslConfiguration();
+
+ // accumulate reply
+ auto waitForBytes = [&](void *buffer, int count) {
+ int remaining = timeout.remainingTime();
+ while (remaining >= 0 && socket.bytesAvailable() < count) {
+ if (!socket.waitForReadyRead(remaining))
+ return false;
+ }
+ return socket.read(static_cast<char *>(buffer), count) == count;
+ };
+ if (!waitForBytes(&size, sizeof(size)))
+ break;
+
+ // note: strictly speaking, we're allocating memory based on untrusted data
+ // but in practice, due to limited range of the data type (16 bits),
+ // the maximum allocation is small.
+ size = qFromBigEndian(size);
+ response.resize(size);
+ if (waitForBytes(response.data(), size)) {
+ // check if the AD bit is set; we'll trust it over TLS requests
+ if (size >= 4)
+ reply->authenticData = response[3] & DnsAuthenticDataBit;
+ return true;
+ }
+ } while (false);
+
+ // handle errors
+ return makeReplyErrorFromSocket(reply, &socket);
+}
+#else
+bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
+ ReplyBuffer &response)
+{
+ Q_UNUSED(query)
+ Q_UNUSED(response)
+ reply->setError(QDnsLookup::ResolverError, QDnsLookup::tr("SSL/TLS support not present"));
+ return false;
+}
+#endif
+
QT_END_NAMESPACE
#include "moc_qdnslookup.cpp"
diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h
index ae89a0a11f..8d21e99c84 100644
--- a/src/network/kernel/qdnslookup.h
+++ b/src/network/kernel/qdnslookup.h
@@ -22,6 +22,10 @@ class QDnsHostAddressRecordPrivate;
class QDnsMailExchangeRecordPrivate;
class QDnsServiceRecordPrivate;
class QDnsTextRecordPrivate;
+class QDnsTlsAssociationRecordPrivate;
+class QSslConfiguration;
+
+QT_DECLARE_QSDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
class Q_NETWORK_EXPORT QDnsDomainNameRecord
{
@@ -137,10 +141,83 @@ private:
Q_DECLARE_SHARED(QDnsTextRecord)
+class Q_NETWORK_EXPORT QDnsTlsAssociationRecord
+{
+ Q_GADGET
+public:
+ enum class CertificateUsage : quint8 {
+ // https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml#certificate-usages
+ // RFC 6698
+ CertificateAuthorityConstrait = 0,
+ ServiceCertificateConstraint = 1,
+ TrustAnchorAssertion = 2,
+ DomainIssuedCertificate = 3,
+ PrivateUse = 255,
+
+ // Aliases by RFC 7218
+ PKIX_TA = 0,
+ PKIX_EE = 1,
+ DANE_TA = 2,
+ DANE_EE = 3,
+ PrivCert = 255,
+ };
+ Q_ENUM(CertificateUsage)
+
+ enum class Selector : quint8 {
+ // https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml#selectors
+ // RFC 6698
+ FullCertificate = 0,
+ SubjectPublicKeyInfo = 1,
+ PrivateUse = 255,
+
+ // Aliases by RFC 7218
+ Cert = FullCertificate,
+ SPKI = SubjectPublicKeyInfo,
+ PrivSel = PrivateUse,
+ };
+ Q_ENUM(Selector)
+
+ enum class MatchingType : quint8 {
+ // https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml#matching-types
+ // RFC 6698
+ Exact = 0,
+ Sha256 = 1,
+ Sha512 = 2,
+ PrivateUse = 255,
+ PrivMatch = PrivateUse,
+ };
+ Q_ENUM(MatchingType)
+
+ QDnsTlsAssociationRecord();
+ QDnsTlsAssociationRecord(const QDnsTlsAssociationRecord &other);
+ QDnsTlsAssociationRecord(QDnsTlsAssociationRecord &&other)
+ : d(std::move(other.d))
+ {}
+ QDnsTlsAssociationRecord &operator=(QDnsTlsAssociationRecord &&other) noexcept { swap(other); return *this; }
+ QDnsTlsAssociationRecord &operator=(const QDnsTlsAssociationRecord &other);
+ ~QDnsTlsAssociationRecord();
+
+ void swap(QDnsTlsAssociationRecord &other) noexcept { d.swap(other.d); }
+
+ QString name() const;
+ quint32 timeToLive() const;
+ CertificateUsage usage() const;
+ Selector selector() const;
+ MatchingType matchType() const;
+ QByteArray value() const;
+
+private:
+ QSharedDataPointer<QDnsTlsAssociationRecordPrivate> d;
+ friend class QDnsLookupRunnable;
+};
+
+Q_DECLARE_SHARED(QDnsTlsAssociationRecord)
+
class Q_NETWORK_EXPORT QDnsLookup : public QObject
{
Q_OBJECT
Q_PROPERTY(Error error READ error NOTIFY finished)
+ Q_PROPERTY(bool authenticData READ isAuthenticData NOTIFY finished)
Q_PROPERTY(QString errorString READ errorString NOTIFY finished)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged BINDABLE bindableName)
Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged BINDABLE bindableType)
@@ -148,6 +225,8 @@ class Q_NETWORK_EXPORT QDnsLookup : public QObject
BINDABLE bindableNameserver)
Q_PROPERTY(quint16 nameserverPort READ nameserverPort WRITE setNameserverPort
NOTIFY nameserverPortChanged BINDABLE bindableNameserverPort)
+ Q_PROPERTY(Protocol nameserverProtocol READ nameserverProtocol WRITE setNameserverProtocol
+ NOTIFY nameserverProtocolChanged BINDABLE bindableNameserverProtocol)
public:
enum Error
@@ -174,17 +253,27 @@ public:
NS = 2,
PTR = 12,
SRV = 33,
+ TLSA = 52,
TXT = 16
};
Q_ENUM(Type)
+ enum Protocol : quint8 {
+ Standard = 0,
+ DnsOverTls,
+ };
+ Q_ENUM(Protocol)
+
explicit QDnsLookup(QObject *parent = nullptr);
QDnsLookup(Type type, const QString &name, QObject *parent = nullptr);
QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent = nullptr);
QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port,
QObject *parent = nullptr);
+ QDnsLookup(Type type, const QString &name, Protocol protocol, const QHostAddress &nameserver,
+ quint16 port = 0, QObject *parent = nullptr);
~QDnsLookup();
+ bool isAuthenticData() const;
Error error() const;
QString errorString() const;
bool isFinished() const;
@@ -203,6 +292,11 @@ public:
quint16 nameserverPort() const;
void setNameserverPort(quint16 port);
QBindable<quint16> bindableNameserverPort();
+ Protocol nameserverProtocol() const;
+ void setNameserverProtocol(Protocol protocol);
+ QBindable<Protocol> bindableNameserverProtocol();
+ void setNameserver(Protocol protocol, const QHostAddress &nameserver, quint16 port = 0);
+ QT_NETWORK_INLINE_SINCE(6, 8)
void setNameserver(const QHostAddress &nameserver, quint16 port);
QList<QDnsDomainNameRecord> canonicalNameRecords() const;
@@ -212,7 +306,15 @@ public:
QList<QDnsDomainNameRecord> pointerRecords() const;
QList<QDnsServiceRecord> serviceRecords() const;
QList<QDnsTextRecord> textRecords() const;
+ QList<QDnsTlsAssociationRecord> tlsAssociationRecords() const;
+
+#if QT_CONFIG(ssl)
+ void setSslConfiguration(const QSslConfiguration &sslConfiguration);
+ QSslConfiguration sslConfiguration() const;
+#endif
+ static bool isProtocolSupported(Protocol protocol);
+ static quint16 defaultPortForProtocol(Protocol protocol) noexcept Q_DECL_CONST_FUNCTION;
public Q_SLOTS:
void abort();
@@ -224,11 +326,19 @@ Q_SIGNALS:
void typeChanged(Type type);
void nameserverChanged(const QHostAddress &nameserver);
void nameserverPortChanged(quint16 port);
+ void nameserverProtocolChanged(Protocol protocol);
private:
Q_DECLARE_PRIVATE(QDnsLookup)
};
+#if QT_NETWORK_INLINE_IMPL_SINCE(6, 8)
+void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
+{
+ setNameserver(Standard, nameserver, port);
+}
+#endif
+
QT_END_NAMESPACE
#endif // QDNSLOOKUP_H
diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h
index da4721411b..1f32b4ee4f 100644
--- a/src/network/kernel/qdnslookup_p.h
+++ b/src/network/kernel/qdnslookup_p.h
@@ -27,6 +27,10 @@
#include "private/qobject_p.h"
#include "private/qurl_p.h"
+#if QT_CONFIG(ssl)
+# include "qsslconfiguration.h"
+#endif
+
QT_REQUIRE_CONFIG(dnslookup);
QT_BEGIN_NAMESPACE
@@ -35,6 +39,7 @@ QT_BEGIN_NAMESPACE
constexpr qsizetype MaxDomainNameLength = 255;
constexpr quint16 DnsPort = 53;
+constexpr quint16 DnsOverTlsPort = 853;
class QDnsLookupRunnable;
QDebug operator<<(QDebug &, QDnsLookupRunnable *);
@@ -43,6 +48,7 @@ class QDnsLookupReply
{
public:
QDnsLookup::Error error = QDnsLookup::NoError;
+ bool authenticData = false;
QString errorString;
QList<QDnsDomainNameRecord> canonicalNameRecords;
@@ -51,8 +57,13 @@ public:
QList<QDnsDomainNameRecord> nameServerRecords;
QList<QDnsDomainNameRecord> pointerRecords;
QList<QDnsServiceRecord> serviceRecords;
+ QList<QDnsTlsAssociationRecord> tlsAssociationRecords;
QList<QDnsTextRecord> textRecords;
+#if QT_CONFIG(ssl)
+ std::optional<QSslConfiguration> sslConfiguration;
+#endif
+
// helper methods
void setError(QDnsLookup::Error err, QString &&msg)
{
@@ -120,6 +131,7 @@ private:
&& nameServerRecords.isEmpty()
&& pointerRecords.isEmpty()
&& serviceRecords.isEmpty()
+ && tlsAssociationRecords.isEmpty()
&& textRecords.isEmpty();
}
};
@@ -129,7 +141,8 @@ class QDnsLookupPrivate : public QObjectPrivate
public:
QDnsLookupPrivate()
: type(QDnsLookup::A)
- , port(DnsPort)
+ , port(0)
+ , protocol(QDnsLookup::Standard)
{ }
void nameChanged()
@@ -162,11 +175,22 @@ public:
Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, quint16,
port, &QDnsLookupPrivate::nameserverPortChanged);
+ void nameserverProtocolChanged()
+ {
+ emit q_func()->nameserverProtocolChanged(protocol);
+ }
+
+ Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QDnsLookup::Protocol,
+ protocol, &QDnsLookupPrivate::nameserverProtocolChanged);
QDnsLookupReply reply;
QDnsLookupRunnable *runnable = nullptr;
bool isFinished = false;
+#if QT_CONFIG(ssl)
+ std::optional<QSslConfiguration> sslConfiguration;
+#endif
+
Q_DECLARE_PUBLIC(QDnsLookup)
};
@@ -180,9 +204,13 @@ public:
#else
using EncodedLabel = QByteArray;
#endif
+ // minimum IPv6 MTU (1280) minus the IPv6 (40) and UDP headers (8)
+ static constexpr qsizetype ReplyBufferSize = 1280 - 40 - 8;
+ using ReplyBuffer = QVarLengthArray<unsigned char, ReplyBufferSize>;
QDnsLookupRunnable(const QDnsLookupPrivate *d);
void run() override;
+ bool sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query, ReplyBuffer &response);
signals:
void finished(const QDnsLookupReply &reply);
@@ -198,6 +226,11 @@ private:
QHostAddress nameserver;
QDnsLookup::Type requestType;
quint16 port;
+ QDnsLookup::Protocol protocol;
+
+#if QT_CONFIG(ssl)
+ std::optional<QSslConfiguration> sslConfiguration;
+#endif
friend QDebug operator<<(QDebug &, QDnsLookupRunnable *);
};
@@ -265,6 +298,15 @@ public:
QList<QByteArray> values;
};
+class QDnsTlsAssociationRecordPrivate : public QDnsRecordPrivate
+{
+public:
+ QDnsTlsAssociationRecord::CertificateUsage usage;
+ QDnsTlsAssociationRecord::Selector selector;
+ QDnsTlsAssociationRecord::MatchingType matchType;
+ QByteArray value;
+};
+
QT_END_NAMESPACE
#endif // QDNSLOOKUP_P_H
diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp
index 0217293348..9de073b781 100644
--- a/src/network/kernel/qdnslookup_unix.cpp
+++ b/src/network/kernel/qdnslookup_unix.cpp
@@ -6,6 +6,7 @@
#include <qendian.h>
#include <qscopedpointer.h>
+#include <qspan.h>
#include <qurl.h>
#include <qvarlengtharray.h>
#include <private/qnativesocketengine_p.h> // for setSockAddr
@@ -32,15 +33,13 @@ QT_REQUIRE_CONFIG(libresolv);
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-
-// minimum IPv6 MTU (1280) minus the IPv6 (40) and UDP headers (8)
-static constexpr qsizetype ReplyBufferSize = 1280 - 40 - 8;
+using ReplyBuffer = QDnsLookupRunnable::ReplyBuffer;
// https://www.rfc-editor.org/rfc/rfc6891
static constexpr unsigned char Edns0Record[] = {
0x00, // root label
T_OPT >> 8, T_OPT & 0xff, // type OPT
- ReplyBufferSize >> 8, ReplyBufferSize & 0xff, // payload size
+ ReplyBuffer::PreallocatedSize >> 8, ReplyBuffer::PreallocatedSize & 0xff, // payload size
NOERROR, // extended rcode
0, // version
0x00, 0x00, // flags
@@ -68,11 +67,9 @@ using Cache = QList<QDnsCachedName>; // QHash or QMap are overkill
// https://docs.oracle.com/cd/E86824_01/html/E54774/res-setservers-3resolv.html
static bool applyNameServer(res_state state, const QHostAddress &nameserver, quint16 port)
{
- if (!nameserver.isNull()) {
- union res_sockaddr_union u;
- setSockaddr(reinterpret_cast<sockaddr *>(&u.sin), nameserver, port);
- res_setservers(state, &u, 1);
- }
+ union res_sockaddr_union u;
+ setSockaddr(reinterpret_cast<sockaddr *>(&u.sin), nameserver, port);
+ res_setservers(state, &u, 1);
return true;
}
#else
@@ -123,9 +120,6 @@ template <typename State> bool setIpv6NameServer(State *, const void *, quint16)
static bool applyNameServer(res_state state, const QHostAddress &nameserver, quint16 port)
{
- if (nameserver.isNull())
- return true;
-
state->nscount = 1;
state->nsaddr_list[0].sin_family = AF_UNSPEC;
if (nameserver.protocol() == QAbstractSocket::IPv6Protocol)
@@ -153,51 +147,53 @@ prepareQueryBuffer(res_state state, QueryBuffer &buffer, const char *label, ns_r
return queryLength + sizeof(Edns0Record);
}
-void QDnsLookupRunnable::query(QDnsLookupReply *reply)
+static int sendStandardDns(QDnsLookupReply *reply, res_state state, QSpan<unsigned char> qbuffer,
+ ReplyBuffer &buffer, const QHostAddress &nameserver, quint16 port)
{
- // Initialize state.
- std::remove_pointer_t<res_state> state = {};
- if (res_ninit(&state) < 0) {
- int error = errno;
- qErrnoWarning(error, "QDnsLookup: Resolver initialization failed");
- return reply->makeResolverSystemError(error);
- }
- auto guard = qScopeGuard([&] { res_nclose(&state); });
+ // Check if a nameserver was set. If so, use it.
+ if (!nameserver.isNull()) {
+ if (!applyNameServer(state, nameserver, port)) {
+ reply->setError(QDnsLookup::ResolverError,
+ QDnsLookup::tr("IPv6 nameservers are currently not supported on this OS"));
+ return -1;
+ }
- //Check if a nameserver was set. If so, use it
- if (!applyNameServer(&state, nameserver, port))
- return reply->setError(QDnsLookup::ResolverError,
- QDnsLookup::tr("IPv6 nameservers are currently not supported on this OS"));
-#ifdef QDNSLOOKUP_DEBUG
- state.options |= RES_DEBUG;
-#endif
+ // Request the name server attempt to authenticate the reply.
+ reinterpret_cast<HEADER *>(buffer.data())->ad = true;
- // Prepare the DNS query.
- QueryBuffer qbuffer;
- int queryLength = prepareQueryBuffer(&state, qbuffer, requestName.constData(), ns_rcode(requestType));
- if (Q_UNLIKELY(queryLength < 0))
- return reply->makeResolverSystemError();
+#ifdef RES_TRUSTAD
+ // Need to set this option even though we set the AD bit, otherwise
+ // glibc turns it off.
+ state->options |= RES_TRUSTAD;
+#endif
+ }
- // Perform DNS query.
- QVarLengthArray<unsigned char, ReplyBufferSize> buffer(ReplyBufferSize);
auto attemptToSend = [&]() {
std::memset(buffer.data(), 0, HFIXEDSZ); // the header is enough
- int responseLength = res_nsend(&state, qbuffer.data(), queryLength, buffer.data(), buffer.size());
- if (responseLength < 0) {
- // network error of some sort
- if (errno == ETIMEDOUT)
- reply->makeTimeoutError();
- else
- reply->makeResolverSystemError();
- }
- return responseLength;
+ int responseLength = res_nsend(state, qbuffer.data(), qbuffer.size(), buffer.data(), buffer.size());
+ if (responseLength >= 0)
+ return responseLength; // success
+
+ // libresolv uses ETIMEDOUT for resolver errors ("no answer")
+ if (errno == ECONNREFUSED)
+ reply->setError(QDnsLookup::ServerRefusedError, qt_error_string());
+ else if (errno != ETIMEDOUT)
+ reply->makeResolverSystemError(); // some other error
+
+ auto query = reinterpret_cast<HEADER *>(qbuffer.data());
+ auto header = reinterpret_cast<HEADER *>(buffer.data());
+ if (query->id == header->id && header->qr)
+ reply->makeDnsRcodeError(header->rcode);
+ else
+ reply->makeTimeoutError(); // must really be a timeout
+ return -1;
};
// strictly use UDP, we'll deal with truncated replies ourselves
- state.options |= RES_IGNTC;
+ state->options |= RES_IGNTC;
int responseLength = attemptToSend();
if (responseLength < 0)
- return;
+ return responseLength;
// check if we need to use the virtual circuit (TCP)
auto header = reinterpret_cast<HEADER *>(buffer.data());
@@ -208,17 +204,65 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
// remove the EDNS record in the query
reinterpret_cast<HEADER *>(qbuffer.data())->arcount = 0;
- queryLength -= sizeof(Edns0Record);
+ qbuffer = qbuffer.first(qbuffer.size() - sizeof(Edns0Record));
// send using the virtual circuit
- state.options |= RES_USEVC;
+ state->options |= RES_USEVC;
responseLength = attemptToSend();
if (Q_UNLIKELY(responseLength > buffer.size())) {
// Ok, we give up.
- return reply->setError(QDnsLookup::ResolverError,
- QDnsLookup::tr("Reply was too large"));
+ reply->setError(QDnsLookup::ResolverError, QDnsLookup::tr("Reply was too large"));
+ return -1;
}
}
+
+ // We only trust the AD bit in the reply if we're querying a custom name
+ // server or if we can tell the system administrator configured the resolver
+ // to trust replies.
+#ifndef RES_TRUSTAD
+ if (nameserver.isNull())
+ header->ad = false;
+#endif
+ reply->authenticData = header->ad;
+
+ return responseLength;
+}
+
+void QDnsLookupRunnable::query(QDnsLookupReply *reply)
+{
+ // Initialize state.
+ std::remove_pointer_t<res_state> state = {};
+ if (res_ninit(&state) < 0) {
+ int error = errno;
+ qErrnoWarning(error, "QDnsLookup: Resolver initialization failed");
+ return reply->makeResolverSystemError(error);
+ }
+ auto guard = qScopeGuard([&] { res_nclose(&state); });
+
+#ifdef QDNSLOOKUP_DEBUG
+ state.options |= RES_DEBUG;
+#endif
+
+ // Prepare the DNS query.
+ QueryBuffer qbuffer;
+ int queryLength = prepareQueryBuffer(&state, qbuffer, requestName.constData(), ns_rcode(requestType));
+ if (Q_UNLIKELY(queryLength < 0))
+ return reply->makeResolverSystemError();
+
+ // Perform DNS query.
+ ReplyBuffer buffer(ReplyBufferSize);
+ int responseLength = -1;
+ switch (protocol) {
+ case QDnsLookup::Standard:
+ responseLength = sendStandardDns(reply, &state, qbuffer, buffer, nameserver, port);
+ break;
+ case QDnsLookup::DnsOverTls:
+ if (!sendDnsOverTls(reply, qbuffer, buffer))
+ return;
+ responseLength = buffer.size();
+ break;
+ }
+
if (responseLength < 0)
return;
@@ -227,6 +271,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
return reply->makeInvalidReplyError();
// Parse the reply.
+ auto header = reinterpret_cast<HEADER *>(buffer.data());
if (header->rcode)
return reply->makeDnsRcodeError(header->rcode);
@@ -265,7 +310,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
expandHost(offset);
if (status < 0)
return;
- if (offset + status + 4 >= responseLength)
+ if (offset + status + 4 > responseLength)
header->qdcount = 0xffff; // invalid reply below
else
offset += status + 4;
@@ -348,6 +393,8 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid mail exchange record"));
reply->mailExchangeRecords.append(record);
} else if (type == QDnsLookup::SRV) {
+ if (size < 7)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid service record"));
const quint16 priority = qFromBigEndian<quint16>(response + offset);
const quint16 weight = qFromBigEndian<quint16>(response + offset + 2);
const quint16 port = qFromBigEndian<quint16>(response + offset + 4);
@@ -361,6 +408,23 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
if (status < 0)
return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid service record"));
reply->serviceRecords.append(record);
+ } else if (type == QDnsLookup::TLSA) {
+ // https://datatracker.ietf.org/doc/html/rfc6698#section-2.1
+ if (size < 3)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid TLS association record"));
+
+ const quint8 usage = response[offset];
+ const quint8 selector = response[offset + 1];
+ const quint8 matchType = response[offset + 2];
+
+ QDnsTlsAssociationRecord record;
+ record.d->name = name;
+ record.d->timeToLive = ttl;
+ record.d->usage = QDnsTlsAssociationRecord::CertificateUsage(usage);
+ record.d->selector = QDnsTlsAssociationRecord::Selector(selector);
+ record.d->matchType = QDnsTlsAssociationRecord::MatchingType(matchType);
+ record.d->value.assign(response + offset + 3, response + offset + size);
+ reply->tlsAssociationRecords.append(std::move(record));
} else if (type == QDnsLookup::TXT) {
QDnsTextRecord record;
record.d->name = name;
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp
index 72d5ae5c86..1b07776db9 100644
--- a/src/network/kernel/qdnslookup_win.cpp
+++ b/src/network/kernel/qdnslookup_win.cpp
@@ -5,9 +5,11 @@
#include <winsock2.h>
#include "qdnslookup_p.h"
-#include <qurl.h>
+#include <qendian.h>
#include <private/qnativesocketengine_p.h>
#include <private/qsystemerror_p.h>
+#include <qurl.h>
+#include <qspan.h>
#include <qt_windows.h>
#include <windns.h>
@@ -63,6 +65,58 @@ DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest,
QT_BEGIN_NAMESPACE
+static DNS_STATUS sendAlternate(QDnsLookupRunnable *self, QDnsLookupReply *reply,
+ PDNS_QUERY_REQUEST request, PDNS_QUERY_RESULT results)
+{
+ // WinDNS wants MTU - IP Header - UDP header for some reason, in spite
+ // of never needing that much
+ QVarLengthArray<unsigned char, 1472> query(1472);
+
+ auto dnsBuffer = new (query.data()) DNS_MESSAGE_BUFFER;
+ DWORD dnsBufferSize = query.size();
+ WORD xid = 0;
+ bool recursionDesired = true;
+
+ SetLastError(ERROR_SUCCESS);
+
+ // MinGW winheaders incorrectly declare the third parameter as LPWSTR
+ if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize,
+ const_cast<LPWSTR>(request->QueryName), request->QueryType,
+ xid, recursionDesired)) {
+ // let's try reallocating
+ query.resize(dnsBufferSize);
+ if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize,
+ const_cast<LPWSTR>(request->QueryName), request->QueryType,
+ xid, recursionDesired)) {
+ return GetLastError();
+ }
+ }
+
+ // set AD bit: we want to trust this server
+ dnsBuffer->MessageHead.AuthenticatedData = true;
+
+ QDnsLookupRunnable::ReplyBuffer replyBuffer;
+ if (!self->sendDnsOverTls(reply, { query.data(), qsizetype(dnsBufferSize) }, replyBuffer))
+ return DNS_STATUS(-1); // error set in reply
+
+ // interpret the RCODE in the reply
+ auto response = reinterpret_cast<PDNS_MESSAGE_BUFFER>(replyBuffer.data());
+ DNS_HEADER *header = &response->MessageHead;
+ if (!header->IsResponse)
+ return DNS_ERROR_BAD_PACKET; // not a reply
+
+ // Convert the byte order for the 16-bit quantities in the header, so
+ // DnsExtractRecordsFromMessage can parse the contents.
+ //header->Xid = qFromBigEndian(header->Xid);
+ header->QuestionCount = qFromBigEndian(header->QuestionCount);
+ header->AnswerCount = qFromBigEndian(header->AnswerCount);
+ header->NameServerCount = qFromBigEndian(header->NameServerCount);
+ header->AdditionalCount = qFromBigEndian(header->AdditionalCount);
+
+ results->QueryOptions = request->QueryOptions;
+ return DnsExtractRecordsFromMessage_W(response, replyBuffer.size(), &results->pQueryRecords);
+}
+
void QDnsLookupRunnable::query(QDnsLookupReply *reply)
{
// Perform DNS query.
@@ -73,7 +127,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
request.QueryType = requestType;
request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN;
- if (!nameserver.isNull()) {
+ if (protocol == QDnsLookup::Standard && !nameserver.isNull()) {
memset(dnsAddresses, 0, sizeof(dnsAddresses));
request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY;
auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1];
@@ -87,7 +141,18 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
DNS_QUERY_RESULT results = {};
results.Version = 1;
- const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr);
+ DNS_STATUS status = ERROR_INVALID_PARAMETER;
+ switch (protocol) {
+ case QDnsLookup::Standard:
+ status = DnsQueryEx(&request, &results, nullptr);
+ break;
+ case QDnsLookup::DnsOverTls:
+ status = sendAlternate(this, reply, &request, &results);
+ break;
+ }
+
+ if (status == DNS_STATUS(-1))
+ return; // error already set in reply
if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST)
return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1);
else if (status == ERROR_TIMEOUT)
@@ -159,6 +224,25 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
record.d->timeToLive = ptr->dwTtl;
record.d->weight = ptr->Data.Srv.wWeight;
reply->serviceRecords.append(record);
+ } else if (ptr->wType == QDnsLookup::TLSA) {
+ // Note: untested, because the DNS_RECORD reply appears to contain
+ // no records relating to TLSA. Maybe WinDNS filters them out of
+ // zones without DNSSEC.
+ QDnsTlsAssociationRecord record;
+ record.d->name = name;
+ record.d->timeToLive = ptr->dwTtl;
+
+ const auto &tlsa = ptr->Data.Tlsa;
+ const quint8 usage = tlsa.bCertUsage;
+ const quint8 selector = tlsa.bSelector;
+ const quint8 matchType = tlsa.bMatchingType;
+
+ record.d->usage = QDnsTlsAssociationRecord::CertificateUsage(usage);
+ record.d->selector = QDnsTlsAssociationRecord::Selector(selector);
+ record.d->matchType = QDnsTlsAssociationRecord::MatchingType(matchType);
+ record.d->value.assign(tlsa.bCertificateAssociationData,
+ tlsa.bCertificateAssociationData + tlsa.bCertificateAssociationDataLength);
+ reply->tlsAssociationRecords.append(std::move(record));
} else if (ptr->wType == QDnsLookup::TXT) {
QDnsTextRecord record;
record.d->name = name;
diff --git a/src/network/kernel/qnetworkinformation.h b/src/network/kernel/qnetworkinformation.h
index 4e70a7faf2..57a49f23c8 100644
--- a/src/network/kernel/qnetworkinformation.h
+++ b/src/network/kernel/qnetworkinformation.h
@@ -83,7 +83,6 @@ Q_SIGNALS:
private:
friend struct QNetworkInformationDeleter;
- friend class QNetworkInformationPrivate;
QNetworkInformation(QNetworkInformationBackend *backend);
~QNetworkInformation() override;
diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp
index 62bba24bce..9b91b11d6b 100644
--- a/src/network/kernel/qnetworkproxy.cpp
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -752,6 +752,53 @@ QNetworkProxy QNetworkProxy::applicationProxy()
}
/*!
+ \since 6.8
+
+ Returns headers that are set in this network request.
+
+ If the proxy is not of type HttpProxy or HttpCachingProxy,
+ default constructed QHttpHeaders is returned.
+
+ \sa setHeaders()
+*/
+QHttpHeaders QNetworkProxy::headers() const
+{
+ if (d->type != HttpProxy && d->type != HttpCachingProxy)
+ return {};
+ return d->headers.headers();
+}
+
+/*!
+ \since 6.8
+
+ Sets \a newHeaders as headers in this network request, overriding
+ any previously set headers.
+
+ If some headers correspond to the known headers, the values will
+ be parsed and the corresponding parsed form will also be set.
+
+ If the proxy is not of type HttpProxy or HttpCachingProxy this has no
+ effect.
+
+ \sa headers(), QNetworkRequest::KnownHeaders
+*/
+void QNetworkProxy::setHeaders(QHttpHeaders &&newHeaders)
+{
+ if (d->type == HttpProxy || d->type == HttpCachingProxy)
+ d->headers.setHeaders(std::move(newHeaders));
+}
+
+/*!
+ \overload
+ \since 6.8
+*/
+void QNetworkProxy::setHeaders(const QHttpHeaders &newHeaders)
+{
+ if (d->type == HttpProxy || d->type == HttpCachingProxy)
+ d->headers.setHeaders(newHeaders);
+}
+
+/*!
\since 5.0
Returns the value of the known network header \a header if it is
in use for this proxy. If it is not present, returns QVariant()
@@ -795,7 +842,7 @@ bool QNetworkProxy::hasRawHeader(const QByteArray &headerName) const
{
if (d->type != HttpProxy && d->type != HttpCachingProxy)
return false;
- return d->headers.findRawHeader(headerName) != d->headers.rawHeaders.constEnd();
+ return d->headers.headers().contains(headerName);
}
/*!
@@ -814,11 +861,7 @@ QByteArray QNetworkProxy::rawHeader(const QByteArray &headerName) const
{
if (d->type != HttpProxy && d->type != HttpCachingProxy)
return QByteArray();
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
- d->headers.findRawHeader(headerName);
- if (it != d->headers.rawHeaders.constEnd())
- return it->second;
- return QByteArray();
+ return d->headers.rawHeader(headerName);
}
/*!
diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h
index d04bd9ee13..9f92ffeb12 100644
--- a/src/network/kernel/qnetworkproxy.h
+++ b/src/network/kernel/qnetworkproxy.h
@@ -136,6 +136,10 @@ public:
static void setApplicationProxy(const QNetworkProxy &proxy);
static QNetworkProxy applicationProxy();
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+
// "cooked" headers
QVariant header(QNetworkRequest::KnownHeaders header) const;
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
diff --git a/src/network/kernel/qnetworkproxy_libproxy.cpp b/src/network/kernel/qnetworkproxy_libproxy.cpp
index 248a8d2456..da1e8fdbd4 100644
--- a/src/network/kernel/qnetworkproxy_libproxy.cpp
+++ b/src/network/kernel/qnetworkproxy_libproxy.cpp
@@ -166,13 +166,15 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
break;
// fake URLs to get libproxy to tell us the SOCKS proxy
case QNetworkProxyQuery::TcpSocket:
- queryUrl.setScheme(QStringLiteral("tcp"));
+ if (queryUrl.scheme().isEmpty())
+ queryUrl.setScheme(QStringLiteral("tcp"));
queryUrl.setHost(query.peerHostName());
queryUrl.setPort(query.peerPort());
requiredCapabilities |= QNetworkProxy::TunnelingCapability;
break;
case QNetworkProxyQuery::UdpSocket:
- queryUrl.setScheme(QStringLiteral("udp"));
+ if (queryUrl.scheme().isEmpty())
+ queryUrl.setScheme(QStringLiteral("udp"));
queryUrl.setHost(query.peerHostName());
queryUrl.setPort(query.peerPort());
requiredCapabilities |= QNetworkProxy::UdpTunnelingCapability;
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index a700023bd5..725bc21359 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -467,11 +467,14 @@ void QHttpSocketEngine::slotSocketConnected()
data += " HTTP/1.1\r\n";
data += "Proxy-Connection: keep-alive\r\n";
data += "Host: " + peerAddress + "\r\n";
- if (!d->proxy.hasRawHeader("User-Agent"))
+ const auto headers = d->proxy.headers();
+ if (!headers.contains(QHttpHeaders::WellKnownHeader::UserAgent))
data += "User-Agent: Mozilla/5.0\r\n";
- const auto headers = d->proxy.rawHeaderList();
- for (const QByteArray &header : headers)
- data += header + ": " + d->proxy.rawHeader(header) + "\r\n";
+ for (qsizetype i = 0; i < headers.size(); ++i) {
+ const auto name = headers.nameAt(i);
+ data += QByteArrayView(name.data(), name.size()) + ": "
+ + headers.valueAt(i) + "\r\n";
+ }
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
//qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1);
if (priv && priv->method != QAuthenticatorPrivate::None) {
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 0564ad7a33..b0fdc63d66 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -1460,7 +1460,7 @@ qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
//imitate remote closed
close();
setError(QAbstractSocket::RemoteHostClosedError,
- "Remote host closed connection###"_L1);
+ "Remote host closed connection"_L1);
setState(QAbstractSocket::UnconnectedState);
return -1;
} else {
diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt
index d5a275a76c..1e22a5c1cc 100644
--- a/src/plugins/platforms/android/CMakeLists.txt
+++ b/src/plugins/platforms/android/CMakeLists.txt
@@ -9,7 +9,7 @@ qt_find_package(EGL)
qt_internal_add_plugin(QAndroidIntegrationPlugin
OUTPUT_NAME qtforandroid
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES android
+ DEFAULT_IF "android" IN_LIST QT_QPA_PLATFORMS
SOURCES
androidcontentfileengine.cpp androidcontentfileengine.h
androiddeadlockprotector.h
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index 8f1c76ca26..da5b63ef21 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -127,6 +127,12 @@ namespace QtAndroidAccessibility
QtAndroid::notifyObjectHide(accessibilityObjectId, parentObjectId);
}
+ void notifyObjectShow(uint accessibilityObjectId)
+ {
+ const auto parentObjectId = parentId_helper(accessibilityObjectId);
+ QtAndroid::notifyObjectShow(parentObjectId);
+ }
+
void notifyObjectFocus(uint accessibilityObjectId)
{
QtAndroid::notifyObjectFocus(accessibilityObjectId);
diff --git a/src/plugins/platforms/android/androidjniaccessibility.h b/src/plugins/platforms/android/androidjniaccessibility.h
index d967dde3ff..6e8e059334 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.h
+++ b/src/plugins/platforms/android/androidjniaccessibility.h
@@ -18,6 +18,7 @@ namespace QtAndroidAccessibility
bool registerNatives(QJniEnvironment &env);
void notifyLocationChange(uint accessibilityObjectId);
void notifyObjectHide(uint accessibilityObjectId);
+ void notifyObjectShow(uint accessibilityObjectId);
void notifyObjectFocus(uint accessibilityObjectId);
void notifyValueChanged(uint accessibilityObjectId);
void notifyScrolledEvent(uint accessibilityObjectId);
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index 00e6b7ca51..d074e73b9e 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -28,6 +28,8 @@ Q_DECLARE_JNI_CLASS(QtLayout, "org/qtproject/qt/android/QtLayout")
namespace QtAndroidInput
{
static bool m_ignoreMouseEvents = false;
+ static Qt::MouseButtons m_buttons = Qt::NoButton;
+
static QRect m_softwareKeyboardRect;
static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
@@ -160,7 +162,72 @@ namespace QtAndroidInput
anchor.x(), anchor.y(), rtl);
}
- static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
+ // from https://developer.android.com/reference/android/view/MotionEvent#getButtonState()
+ enum AndroidMouseButton {
+ BUTTON_PRIMARY = 0x00000001,
+ BUTTON_SECONDARY = 0x00000002,
+ BUTTON_TERTIARY = 0x00000004,
+ BUTTON_BACK = 0x00000008,
+ BUTTON_FORWARD = 0x00000010,
+ BUTTON_STYLUS_PRIMARY = 0x00000020,
+ BUTTON_STYLUS_SECONDARY = 0x00000040,
+ };
+ Q_DECLARE_FLAGS(AndroidMouseButtons, AndroidMouseButton)
+
+ static Qt::MouseButtons toMouseButtons(jint j_buttons)
+ {
+ const auto buttons = static_cast<AndroidMouseButtons>(j_buttons);
+ Qt::MouseButtons mouseButtons;
+ if (buttons.testFlag(BUTTON_PRIMARY))
+ mouseButtons.setFlag(Qt::LeftButton);
+
+ if (buttons.testFlag(BUTTON_SECONDARY))
+ mouseButtons.setFlag(Qt::RightButton);
+
+ if (buttons.testFlag(BUTTON_TERTIARY))
+ mouseButtons.setFlag(Qt::MiddleButton);
+
+ if (buttons.testFlag(BUTTON_BACK))
+ mouseButtons.setFlag(Qt::BackButton);
+
+ if (buttons.testFlag(BUTTON_FORWARD))
+ mouseButtons.setFlag(Qt::ForwardButton);
+
+ if (buttons.testFlag(BUTTON_STYLUS_PRIMARY))
+ mouseButtons.setFlag(Qt::LeftButton);
+
+ if (buttons.testFlag(BUTTON_STYLUS_SECONDARY))
+ mouseButtons.setFlag(Qt::RightButton);
+
+ // Fall back to left button
+ if (Q_UNLIKELY(buttons != 0 && mouseButtons == Qt::NoButton)) {
+ qWarning() << "Unhandled button value:" << buttons << "Falling back to Qt::LeftButton";
+ mouseButtons = Qt::LeftButton;
+ }
+ return mouseButtons;
+ }
+
+ static void sendMouseButtonEvents(QWindow *topLevel, QPoint localPos, QPoint globalPos,
+ jint mouseButtonState, QEvent::Type type)
+ {
+ const Qt::MouseButtons mouseButtons = toMouseButtons(mouseButtonState);
+ const Qt::MouseButtons changedButtons = mouseButtons & ~m_buttons;
+
+ if (changedButtons == Qt::NoButton)
+ return;
+
+ static_assert (sizeof(changedButtons) <= sizeof(uint), "Qt::MouseButtons size changed. Adapt code.");
+
+ for (uint buttonInt = 0x1; static_cast<uint>(changedButtons) >= buttonInt; buttonInt <<= 1) {
+ const auto button = static_cast<Qt::MouseButton>(buttonInt);
+ if (changedButtons.testFlag(button)) {
+ QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos,
+ mouseButtons, button, type);
+ }
+ }
+ }
+
+ static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState)
{
if (m_ignoreMouseEvents)
return;
@@ -169,13 +236,11 @@ namespace QtAndroidInput
QWindow *window = windowFromId(winId);
m_mouseGrabber = window;
const QPoint localPos = window && window->handle() ?
- window->handle()->mapFromGlobal(globalPos) : globalPos;
- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
- Qt::MouseButtons(Qt::LeftButton),
- Qt::LeftButton, QEvent::MouseButtonPress);
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonPress);
}
- static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
+ static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState)
{
const QPoint globalPos(x,y);
QWindow *window = m_mouseGrabber.data();
@@ -184,9 +249,8 @@ namespace QtAndroidInput
const QPoint localPos = window && window->handle() ?
window->handle()->mapFromGlobal(globalPos) : globalPos;
- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
- Qt::MouseButtons(Qt::NoButton),
- Qt::LeftButton, QEvent::MouseButtonRelease);
+
+ sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonRelease);
m_ignoreMouseEvents = false;
m_mouseGrabber.clear();
}
@@ -900,8 +964,8 @@ namespace QtAndroidInput
{"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd},
{"touchEnd","(II)V",(void*)touchEnd},
{"touchCancel", "(I)V", (void *)touchCancel},
- {"mouseDown", "(III)V", (void *)mouseDown},
- {"mouseUp", "(III)V", (void *)mouseUp},
+ {"mouseDown", "(IIII)V", (void *)mouseDown},
+ {"mouseUp", "(IIII)V", (void *)mouseUp},
{"mouseMove", "(III)V", (void *)mouseMove},
{"mouseWheel", "(IIIFF)V", (void *)mouseWheel},
{"longPress", "(III)V", (void *)longPress},
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 206bbd03d6..9fdcf3936b 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -245,6 +245,12 @@ namespace QtAndroid
accessibilityObjectId, parentObjectId);
}
+ void notifyObjectShow(uint parentObjectId)
+ {
+ qtActivityDelegate().callMethod<void>("notifyObjectShow",
+ parentObjectId);
+ }
+
void notifyObjectFocus(uint accessibilityObjectId)
{
qtActivityDelegate().callMethod<void>("notifyObjectFocus", accessibilityObjectId);
@@ -435,7 +441,7 @@ static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
Q_UNUSED(env);
// The service must wait until the QCoreApplication starts otherwise onBind will be
// called too early
- if (QtAndroidPrivate::service().isValid())
+ if (QtAndroidPrivate::service().isValid() && QtAndroid::isQtApplication())
QtAndroidPrivate::waitForServiceSetup();
}
@@ -703,7 +709,7 @@ Q_DECLARE_JNI_NATIVE_METHOD(handleScreenRemoved)
static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode)
{
- QAndroidPlatformIntegration::setColorScheme(
+ QAndroidPlatformIntegration::updateColorScheme(
(newUiMode == 1 ) ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light);
}
Q_DECLARE_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h
index 57a71a8650..99fff96d2b 100644
--- a/src/plugins/platforms/android/androidjnimain.h
+++ b/src/plugins/platforms/android/androidjnimain.h
@@ -65,6 +65,7 @@ namespace QtAndroid
void notifyAccessibilityLocationChange(uint accessibilityObjectId);
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId);
+ void notifyObjectShow(uint parentObjectId);
void notifyObjectFocus(uint accessibilityObjectId);
void notifyValueChanged(uint accessibilityObjectId, jstring value);
void notifyScrolledEvent(uint accessibilityObjectId);
diff --git a/src/plugins/platforms/android/androidwindowembedding.cpp b/src/plugins/platforms/android/androidwindowembedding.cpp
index 230776f571..65dabcac66 100644
--- a/src/plugins/platforms/android/androidwindowembedding.cpp
+++ b/src/plugins/platforms/android/androidwindowembedding.cpp
@@ -12,7 +12,6 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_JNI_CLASS(QtView, "org/qtproject/qt/android/QtView");
-Q_DECLARE_JNI_CLASS(QtEmbeddedDelegate, "org/qtproject/qt/android/QtEmbeddedDelegate");
namespace QtAndroidWindowEmbedding {
void createRootWindow(JNIEnv *, jclass, QtJniTypes::View rootView,
@@ -59,16 +58,12 @@ namespace QtAndroidWindowEmbedding {
}
bool registerNatives(QJniEnvironment& env) {
- using namespace QtJniTypes;
- bool success = env.registerNativeMethods(Traits<QtEmbeddedDelegate>::className(),
- {Q_JNI_NATIVE_SCOPED_METHOD(createRootWindow, QtAndroidWindowEmbedding),
- Q_JNI_NATIVE_SCOPED_METHOD(deleteWindow, QtAndroidWindowEmbedding)});
-
- success &= env.registerNativeMethods(Traits<QtView>::className(),
- {Q_JNI_NATIVE_SCOPED_METHOD(setWindowVisible, QtAndroidWindowEmbedding),
- Q_JNI_NATIVE_SCOPED_METHOD(resizeWindow, QtAndroidWindowEmbedding)});
- return success;
-
+ return env.registerNativeMethods(
+ QtJniTypes::Traits<QtJniTypes::QtView>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(createRootWindow, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(deleteWindow, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(setWindowVisible, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(resizeWindow, QtAndroidWindowEmbedding) });
}
}
diff --git a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
index 61fc21a6bc..ea7f22295d 100644
--- a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
+++ b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
@@ -28,6 +28,8 @@ void QAndroidPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *
QtAndroidAccessibility::notifyLocationChange(event->uniqueId());
} else if (event->type() == QAccessible::ObjectHide) {
QtAndroidAccessibility::notifyObjectHide(event->uniqueId());
+ } else if (event->type() == QAccessible::ObjectShow) {
+ QtAndroidAccessibility::notifyObjectShow(event->uniqueId());
} else if (event->type() == QAccessible::Focus) {
QtAndroidAccessibility::notifyObjectFocus(event->uniqueId());
} else if (event->type() == QAccessible::ValueChanged) {
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 038fe5172a..6efd3fc631 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -72,6 +72,12 @@ QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
return new QAndroidPlatformScreen(display);
}
+static bool isValidAndroidContextForRendering()
+{
+ return QtAndroid::isQtApplication() ? QtAndroidPrivate::activity().isValid()
+ : QtAndroidPrivate::context().isValid();
+}
+
} // anonymous namespace
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
@@ -317,9 +323,12 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
case ApplicationState: return true;
case ThreadedPixmaps: return true;
case NativeWidgets: return QtAndroidPrivate::activity().isValid();
- case OpenGL: return QtAndroidPrivate::activity().isValid();
- case ForeignWindows: return QtAndroidPrivate::activity().isValid();
- case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroidPrivate::activity().isValid();
+ case OpenGL:
+ return isValidAndroidContextForRendering();
+ case ForeignWindows:
+ return isValidAndroidContextForRendering();
+ case ThreadedOpenGL:
+ return !needsBasicRenderloopWorkaround() && isValidAndroidContextForRendering();
case RasterGLSurface: return QtAndroidPrivate::activity().isValid();
case TopStackedNativeChildWindows: return false;
case MaximizeUsingFullscreenGeometry: return true;
@@ -341,7 +350,7 @@ QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(Q
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- if (!QtAndroidPrivate::activity().isValid())
+ if (!isValidAndroidContextForRendering())
return nullptr;
QSurfaceFormat format(context->format());
format.setAlphaBufferSize(8);
@@ -384,7 +393,7 @@ QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWi
QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
{
- if (!QtAndroidPrivate::activity().isValid())
+ if (!isValidAndroidContextForRendering())
return nullptr;
#if QT_CONFIG(vulkan)
@@ -537,7 +546,7 @@ void QAndroidPlatformIntegration::setScreenSize(int width, int height)
Qt::ColorScheme QAndroidPlatformIntegration::m_colorScheme = Qt::ColorScheme::Light;
-void QAndroidPlatformIntegration::setColorScheme(Qt::ColorScheme colorScheme)
+void QAndroidPlatformIntegration::updateColorScheme(Qt::ColorScheme colorScheme)
{
if (m_colorScheme == colorScheme)
return;
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h
index 5f1126fafc..b7bfb58d1d 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/qandroidplatformintegration.h
@@ -110,7 +110,7 @@ public:
void flushPendingUpdates();
- static void setColorScheme(Qt::ColorScheme colorScheme);
+ static void updateColorScheme(Qt::ColorScheme colorScheme);
static Qt::ColorScheme colorScheme() { return m_colorScheme; }
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp
index f43e7cdd6a..39287aa905 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.cpp
+++ b/src/plugins/platforms/android/qandroidplatformservices.cpp
@@ -24,15 +24,18 @@ QAndroidPlatformServices::QAndroidPlatformServices()
QtAndroidPrivate::registerNewIntentListener(this);
- QMetaObject::invokeMethod(
- this,
- [this] {
- QJniObject context = QJniObject(QtAndroidPrivate::context());
- QJniObject intent =
- context.callObjectMethod("getIntent", "()Landroid/content/Intent;");
- handleNewIntent(nullptr, intent.object());
- },
- Qt::QueuedConnection);
+ // Qt applications without Activity contexts cannot retrieve intents from the Activity.
+ if (QNativeInterface::QAndroidApplication::isActivityContext()) {
+ QMetaObject::invokeMethod(
+ this,
+ [this] {
+ QJniObject context = QJniObject(QtAndroidPrivate::context());
+ QJniObject intent =
+ context.callObjectMethod("getIntent", "()Landroid/content/Intent;");
+ handleNewIntent(nullptr, intent.object());
+ },
+ Qt::QueuedConnection);
+ }
}
Q_DECLARE_JNI_CLASS(UriType, "android/net/Uri")
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp
index 7b9072df69..99eeabac1d 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp
@@ -161,7 +161,10 @@ QJsonObject AndroidStyle::loadStyleData()
if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar))
stylePath += slashChar;
- if (QAndroidPlatformIntegration::colorScheme() == Qt::ColorScheme::Dark)
+ const Qt::ColorScheme colorScheme = QAndroidPlatformTheme::instance()
+ ? QAndroidPlatformTheme::instance()->colorScheme()
+ : QAndroidPlatformIntegration::colorScheme();
+ if (colorScheme == Qt::ColorScheme::Dark)
stylePath += "darkUiMode/"_L1;
Q_ASSERT(!stylePath.isEmpty());
@@ -423,9 +426,19 @@ void QAndroidPlatformTheme::showPlatformMenuBar()
Qt::ColorScheme QAndroidPlatformTheme::colorScheme() const
{
+ if (m_colorSchemeOverride != Qt::ColorScheme::Unknown)
+ return m_colorSchemeOverride;
return QAndroidPlatformIntegration::colorScheme();
}
+void QAndroidPlatformTheme::requestColorScheme(Qt::ColorScheme scheme)
+{
+ m_colorSchemeOverride = scheme;
+ QMetaObject::invokeMethod(qGuiApp, [this]{
+ updateColorScheme();
+ });
+}
+
static inline int paletteType(QPlatformTheme::Palette type)
{
switch (type) {
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h
index ce3d6d5f73..1b4ab5664d 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.h
+++ b/src/plugins/platforms/android/qandroidplatformtheme.h
@@ -40,6 +40,8 @@ public:
QPlatformMenuItem *createPlatformMenuItem() const override;
void showPlatformMenuBar() override;
Qt::ColorScheme colorScheme() const override;
+ void requestColorScheme(Qt::ColorScheme scheme) override;
+
const QPalette *palette(Palette type = SystemPalette) const override;
const QFont *font(Font type = SystemFont) const override;
QIconEngine *createIconEngine(const QString &iconName) const override;
@@ -57,6 +59,7 @@ private:
std::shared_ptr<AndroidStyle> m_androidStyleData;
QPalette m_defaultPalette;
QFont m_systemFont;
+ Qt::ColorScheme m_colorSchemeOverride = Qt::ColorScheme::Unknown;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp
index e47281664d..979f0fb98a 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp
@@ -64,11 +64,20 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
if (window->isTopLevel())
platformScreen()->addWindow(this);
- // TODO should handle case where this changes at runtime -> need to change existing window
- // into TextureView (or perhaps not, if the parent window would be SurfaceView, as long as
- // onTop was false it would stay below the children)
- if (platformScreen()->windows().size() <= 1)
+ static bool ok = false;
+ static const int value = qEnvironmentVariableIntValue("QT_ANDROID_SURFACE_CONTAINER_TYPE", &ok);
+ if (ok) {
+ static const SurfaceContainer type = static_cast<SurfaceContainer>(value);
+ if (type == SurfaceContainer::SurfaceView || type == SurfaceContainer::TextureView)
+ m_surfaceContainerType = type;
+ } else if (platformScreen()->windows().size() <= 1) {
+ // TODO should handle case where this changes at runtime -> need to change existing window
+ // into TextureView (or perhaps not, if the parent window would be SurfaceView, as long as
+ // onTop was false it would stay below the children)
m_surfaceContainerType = SurfaceContainer::SurfaceView;
+ }
+ qCDebug(lcQpaWindow) << "Window" << m_nativeViewId << "using surface container type"
+ << static_cast<int>(m_surfaceContainerType);
}
QAndroidPlatformWindow::~QAndroidPlatformWindow()
diff --git a/src/plugins/platforms/cocoa/CMakeLists.txt b/src/plugins/platforms/cocoa/CMakeLists.txt
index 92e681d8fb..491c61703f 100644
--- a/src/plugins/platforms/cocoa/CMakeLists.txt
+++ b/src/plugins/platforms/cocoa/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QCocoaIntegrationPlugin
OUTPUT_NAME qcocoa
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES cocoa
+ DEFAULT_IF "cocoa" IN_LIST QT_QPA_PLATFORMS
PLUGIN_TYPE platforms
SOURCES
main.mm
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index c5e40a4087..40c1e90511 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -36,6 +36,23 @@ void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
}
switch (event->type()) {
+ case QAccessible::Announcement: {
+ auto *announcementEvent = static_cast<QAccessibleAnnouncementEvent *>(event);
+ auto priorityLevel = (announcementEvent->priority() == QAccessible::AnnouncementPriority::Assertive)
+ ? NSAccessibilityPriorityHigh
+ : NSAccessibilityPriorityMedium;
+ NSDictionary *announcementInfo = @{
+ NSAccessibilityPriorityKey: [NSNumber numberWithInt:priorityLevel],
+ NSAccessibilityAnnouncementKey: announcementEvent->message().toNSString()
+ };
+ // post event for application element, as the comment for
+ // NSAccessibilityAnnouncementRequestedNotification in the
+ // NSAccessibilityConstants.h header says
+ NSAccessibilityPostNotificationWithUserInfo(NSApp,
+ NSAccessibilityAnnouncementRequestedNotification,
+ announcementInfo);
+ break;
+ }
case QAccessible::Focus: {
NSAccessibilityPostNotification(element, NSAccessibilityFocusedUIElementChangedNotification);
break;
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index d7f8a1665e..d642115926 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -334,16 +334,50 @@ QT_USE_NAMESPACE
[self doesNotRecognizeSelector:invocationSelector];
}
+- (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ restorationHandler:(void(^)(NSArray<id<NSUserActivityRestoring>> *restorableObjects))restorationHandler
+{
+ // Check if eg. user has installed an app delegate capable of handling this
+ if ([reflectionDelegate respondsToSelector:_cmd]
+ && [reflectionDelegate application:application continueUserActivity:userActivity
+ restorationHandler:restorationHandler] == YES) {
+ return YES;
+ }
+
+ if (!QGuiApplication::instance())
+ return NO;
+
+ if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
+ QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance();
+ Q_ASSERT(cocoaIntegration);
+ return cocoaIntegration->services()->handleUrl(QUrl::fromNSURL(userActivity.webpageURL));
+ }
+
+ return NO;
+}
+
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
Q_UNUSED(replyEvent);
+
NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
+ const QString qurlString = QString::fromNSString(urlString);
+
+ if (event.eventClass == kInternetEventClass && event.eventID == kAEGetURL) {
+ // 'GURL' (Get URL) event this application should handle
+ if (!QGuiApplication::instance())
+ return;
+ QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance();
+ Q_ASSERT(cocoaIntegration);
+ cocoaIntegration->services()->handleUrl(QUrl(qurlString));
+ return;
+ }
+
// The string we get from the requesting application might not necessarily meet
// QUrl's requirement for a IDN-compliant host. So if we can't parse into a QUrl,
// then we pass the string on to the application as the name of a file (and
// QFileOpenEvent::file is not guaranteed to be the path to a local, open'able
// file anyway).
- const QString qurlString = QString::fromNSString(urlString);
if (const QUrl url(qurlString); url.isValid())
QWindowSystemInterface::handleFileOpenEvent(url);
else
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 7a6999c2cc..fa88a19d45 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -326,7 +326,9 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
QPointer<QCocoaMenu> guard = this;
QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height());
- QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : nullptr;
+ // If the app quits while the menu is open (e.g. through a timer that starts before the menu was opened),
+ // then the window will have been destroyed before this function finishes executing. Account for that with QPointer.
+ QPointer<QCocoaWindow> cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : nullptr;
NSView *view = cocoaWindow ? cocoaWindow->view() : nil;
NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
diff --git a/src/plugins/platforms/cocoa/qcocoaservices.h b/src/plugins/platforms/cocoa/qcocoaservices.h
index a0aec6f16b..b6299570e8 100644
--- a/src/plugins/platforms/cocoa/qcocoaservices.h
+++ b/src/plugins/platforms/cocoa/qcocoaservices.h
@@ -4,6 +4,8 @@
#ifndef QCOCOADESKTOPSERVICES_H
#define QCOCOADESKTOPSERVICES_H
+#include <QtCore/qurl.h>
+
#include <qpa/qplatformservices.h>
QT_BEGIN_NAMESPACE
@@ -15,8 +17,12 @@ public:
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
+ bool handleUrl(const QUrl &url);
QPlatformServiceColorPicker *colorPicker(QWindow *parent) override;
+
+private:
+ QUrl m_handlingUrl;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaservices.mm b/src/plugins/platforms/cocoa/qcocoaservices.mm
index 4566cbb8f7..87212c265c 100644
--- a/src/plugins/platforms/cocoa/qcocoaservices.mm
+++ b/src/plugins/platforms/cocoa/qcocoaservices.mm
@@ -8,12 +8,19 @@
#include <Foundation/NSURL.h>
#include <QtCore/QUrl>
+#include <QtCore/qscopedvaluerollback.h>
+
+#include <QtGui/qdesktopservices.h>
#include <QtGui/private/qcoregraphics_p.h>
QT_BEGIN_NAMESPACE
bool QCocoaServices::openUrl(const QUrl &url)
{
+ // avoid recursing back into self
+ if (url == m_handlingUrl)
+ return false;
+
return [[NSWorkspace sharedWorkspace] openURL:url.toNSURL()];
}
@@ -22,6 +29,16 @@ bool QCocoaServices::openDocument(const QUrl &url)
return openUrl(url);
}
+/* Callback from macOS that the application should handle a URL */
+bool QCocoaServices::handleUrl(const QUrl &url)
+{
+ QScopedValueRollback<QUrl> rollback(m_handlingUrl, url);
+ // FIXME: Add platform services callback from QDesktopServices::setUrlHandler
+ // so that we can warn the user if calling setUrlHandler without also setting
+ // up the matching keys in the Info.plist file (CFBundleURLTypes and friends).
+ return QDesktopServices::openUrl(url);
+}
+
class QCocoaColorPicker : public QPlatformServiceColorPicker
{
public:
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index c49d83feae..97e0f633a7 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -44,6 +44,7 @@ public:
static const char *name;
+ void requestColorScheme(Qt::ColorScheme scheme) override;
void handleSystemThemeChange();
#ifndef QT_NO_SHORTCUT
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index f4fbfadbe4..d9135c76c8 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -478,6 +478,23 @@ Qt::ColorScheme QCocoaTheme::colorScheme() const
return m_colorScheme;
}
+void QCocoaTheme::requestColorScheme(Qt::ColorScheme scheme)
+{
+ NSAppearance *appearance = nil;
+ switch (scheme) {
+ case Qt::ColorScheme::Dark:
+ appearance = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
+ break;
+ case Qt::ColorScheme::Light:
+ appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
+ break;
+ case Qt::ColorScheme::Unknown:
+ break;
+ }
+ if (appearance != NSApp.effectiveAppearance)
+ NSApplication.sharedApplication.appearance = appearance;
+}
+
/*
Update the theme's color scheme based on the current appearance.
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 4a245a0f8a..d2c9bb0196 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -514,7 +514,7 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
auto *nsWindow = transientCocoaWindow->nativeWindow();
// We only upgrade the window level for "special" windows, to work
- // around Qt Designer parenting the designer windows to the widget
+ // around Qt Widgets Designer parenting the designer windows to the widget
// palette window (QTBUG-31779). This should be fixed in designer.
if (type != Qt::Window)
windowLevel = qMax(windowLevel, nsWindow.level);
diff --git a/src/plugins/platforms/eglfs/CMakeLists.txt b/src/plugins/platforms/eglfs/CMakeLists.txt
index a0a6116a45..cb4b5d1eb9 100644
--- a/src/plugins/platforms/eglfs/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/CMakeLists.txt
@@ -92,7 +92,7 @@ endif()
qt_internal_add_plugin(QEglFSIntegrationPlugin
OUTPUT_NAME qeglfs
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES eglfs
+ DEFAULT_IF "eglfs" IN_LIST QT_QPA_PLATFORMS
SOURCES
qeglfsmain.cpp
DEFINES
diff --git a/src/plugins/platforms/ios/CMakeLists.txt b/src/plugins/platforms/ios/CMakeLists.txt
index 4cc3efc91e..51c1b52cf3 100644
--- a/src/plugins/platforms/ios/CMakeLists.txt
+++ b/src/plugins/platforms/ios/CMakeLists.txt
@@ -5,10 +5,23 @@
## QIOSIntegrationPlugin Plugin:
#####################################################################
+if(VISIONOS)
+ include(SwiftIntegration.cmake)
+
+ qt_install(TARGETS QIOSIntegrationPluginSwift
+ EXPORT "${INSTALL_CMAKE_NAMESPACE}QIOSIntegrationPluginTargets"
+ DESTINATION "${INSTALL_LIBDIR}"
+ )
+ qt_internal_add_targets_to_additional_targets_export_file(
+ TARGETS QIOSIntegrationPluginSwift
+ EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}QIOSIntegrationPlugin"
+ )
+endif()
+
qt_internal_add_plugin(QIOSIntegrationPlugin
OUTPUT_NAME qios
STATIC # Force static, even in shared builds
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES ios
+ DEFAULT_IF "ios" IN_LIST QT_QPA_PLATFORMS
PLUGIN_TYPE platforms
SOURCES
plugin.mm
@@ -86,3 +99,7 @@ qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT (TVOS OR VISIONOS)
)
add_subdirectory(optional)
+
+if(VISIONOS)
+ target_link_libraries(QIOSIntegrationPlugin PRIVATE QIOSIntegrationPluginSwift)
+endif()
diff --git a/src/plugins/platforms/ios/SwiftIntegration.cmake b/src/plugins/platforms/ios/SwiftIntegration.cmake
new file mode 100644
index 0000000000..d52edb3ad2
--- /dev/null
+++ b/src/plugins/platforms/ios/SwiftIntegration.cmake
@@ -0,0 +1,78 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(CMAKE_Swift_COMPILER_TARGET arm64-apple-xros)
+if($CACHE{CMAKE_OSX_SYSROOT} MATCHES "^[a-z]+simulator$")
+ set(CMAKE_Swift_COMPILER_TARGET "${CMAKE_Swift_COMPILER_TARGET}-simulator")
+endif()
+
+cmake_policy(SET CMP0157 NEW)
+enable_language(Swift)
+
+# Verify that we have a new enough compiler
+if("${CMAKE_Swift_COMPILER_VERSION}" VERSION_LESS 5.9)
+ message(FATAL_ERROR "Swift 5.9 required for C++ interoperability")
+endif()
+
+get_target_property(QT_CORE_INCLUDES Qt6::Core INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(QT_GUI_INCLUDES Qt6::Gui INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(QT_CORE_PRIVATE_INCLUDES Qt6::CorePrivate INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(QT_GUI_PRIVATE_INCLUDES Qt6::GuiPrivate INTERFACE_INCLUDE_DIRECTORIES)
+
+set(target QIOSIntegrationPluginSwift)
+# Swift library
+set(SWIFT_SOURCES
+ "${CMAKE_CURRENT_SOURCE_DIR}/qiosapplication.swift"
+)
+add_library(${target} STATIC ${SWIFT_SOURCES})
+set_target_properties(${target} PROPERTIES
+ Swift_MODULE_NAME ${target})
+target_include_directories(${target} PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${QT_CORE_INCLUDES}"
+ "${QT_GUI_INCLUDES}"
+ "${QT_CORE_PRIVATE_INCLUDES}"
+ "${QT_GUI_PRIVATE_INCLUDES}"
+
+)
+target_compile_options(${target} PUBLIC
+ $<$<COMPILE_LANGUAGE:Swift>:-cxx-interoperability-mode=default>
+ $<$<COMPILE_LANGUAGE:Swift>:-Xcc -std=c++17>)
+
+# Swift to C++ bridging header
+set(SWIFT_BRIDGING_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qiosswiftintegration.h")
+list(TRANSFORM QT_CORE_INCLUDES PREPEND "-I")
+list(TRANSFORM QT_GUI_INCLUDES PREPEND "-I")
+list(TRANSFORM QT_CORE_PRIVATE_INCLUDES PREPEND "-I")
+list(TRANSFORM QT_GUI_PRIVATE_INCLUDES PREPEND "-I")
+add_custom_command(
+ COMMAND
+ ${CMAKE_Swift_COMPILER} -frontend -typecheck
+ ${SWIFT_SOURCES}
+ -I ${CMAKE_CURRENT_SOURCE_DIR}
+ ${QT_CORE_INCLUDES}
+ ${QT_GUI_INCLUDES}
+ ${QT_CORE_PRIVATE_INCLUDES}
+ ${QT_GUI_PRIVATE_INCLUDES}
+ -sdk ${CMAKE_OSX_SYSROOT}
+ -module-name ${target}
+ -cxx-interoperability-mode=default
+ -Xcc -std=c++17
+ -emit-clang-header-path "${SWIFT_BRIDGING_HEADER}"
+ -target ${CMAKE_Swift_COMPILER_TARGET}
+ OUTPUT
+ "${SWIFT_BRIDGING_HEADER}"
+ DEPENDS
+ ${SWIFT_SOURCES}
+ )
+
+set(header_target "${target}Header")
+add_custom_target(${header_target}
+ DEPENDS "${SWIFT_BRIDGING_HEADER}"
+)
+# Make sure the "'__bridge_transfer' casts have no effect when not using ARC"
+# warning doesn't break warnings-are-error builds.
+target_compile_options(${target} INTERFACE
+ -Wno-error=arc-bridge-casts-disallowed-in-nonarc)
+
+add_dependencies(${target} ${header_target})
diff --git a/src/plugins/platforms/ios/module.modulemap b/src/plugins/platforms/ios/module.modulemap
new file mode 100644
index 0000000000..af42b3e1f5
--- /dev/null
+++ b/src/plugins/platforms/ios/module.modulemap
@@ -0,0 +1,4 @@
+module QIOSIntegrationPlugin {
+ header "qiosapplicationdelegate.h"
+ header "qiosintegration.h"
+}
diff --git a/src/plugins/platforms/ios/qiosapplication.swift b/src/plugins/platforms/ios/qiosapplication.swift
new file mode 100644
index 0000000000..6f75ebd0b5
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplication.swift
@@ -0,0 +1,82 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import SwiftUI
+import CompositorServices
+import QIOSIntegrationPlugin
+import RealityKit
+
+struct QIOSSwiftApplication: App {
+ @UIApplicationDelegateAdaptor private var appDelegate: QIOSApplicationDelegate
+
+ var body: some SwiftUI.Scene {
+ WindowGroup() {
+ ImmersiveSpaceControlView()
+ }
+
+ ImmersiveSpace(id: "QIOSImmersiveSpace") {
+ CompositorLayer(configuration: QIOSLayerConfiguration()) { layerRenderer in
+ QIOSIntegration.instance().renderCompositorLayer(layerRenderer)
+ }
+ }
+ // CompositorLayer immersive spaces are always full, and should not need
+ // to set the immersion style, but lacking this we get a warning in the
+ // console about not being able to "configure an immersive space with
+ // selected style 'AutomaticImmersionStyle' since it is not in the list
+ // of supported styles for this type of content: 'FullImmersionStyle'."
+ .immersionStyle(selection: .constant(.full), in: .full)
+ }
+}
+
+public struct QIOSLayerConfiguration: CompositorLayerConfiguration {
+ public func makeConfiguration(capabilities: LayerRenderer.Capabilities,
+ configuration: inout LayerRenderer.Configuration) {
+ // Use reflection to pull out underlying C handles
+ // FIXME: Use proper bridging APIs when available
+ let capabilitiesMirror = Mirror(reflecting: capabilities)
+ let configurationMirror = Mirror(reflecting: configuration)
+ QIOSIntegration.instance().configureCompositorLayer(
+ capabilitiesMirror.descendant("c_capabilities") as? cp_layer_renderer_capabilities_t,
+ configurationMirror.descendant("box", "value") as? cp_layer_renderer_configuration_t
+ )
+ }
+}
+
+public func runSwiftAppMain() {
+ QIOSSwiftApplication.main()
+}
+
+public class ImmersiveState: ObservableObject {
+ static let shared = ImmersiveState()
+ @Published var showImmersiveSpace: Bool = false
+}
+
+struct ImmersiveSpaceControlView: View {
+ @ObservedObject private var immersiveState = ImmersiveState.shared
+
+ @Environment(\.openImmersiveSpace) var openImmersiveSpace
+ @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
+
+ var body: some View {
+ VStack {}
+ .onChange(of: immersiveState.showImmersiveSpace) { _, newValue in
+ Task {
+ if newValue {
+ await openImmersiveSpace(id: "QIOSImmersiveSpace")
+ } else {
+ await dismissImmersiveSpace()
+ }
+ }
+ }
+ }
+}
+
+public class ImmersiveSpaceManager : NSObject {
+ @objc public static func openImmersiveSpace() {
+ ImmersiveState.shared.showImmersiveSpace = true
+ }
+
+ @objc public static func dismissImmersiveSpace() {
+ ImmersiveState.shared.showImmersiveSpace = false
+ }
+}
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h
index 39bb9fdedb..7e12d64cbf 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.h
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h
@@ -1,6 +1,9 @@
// 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
+#ifndef QIOSAPPLICATIONDELEGATE_H
+#define QIOSAPPLICATIONDELEGATE_H
+
#import <UIKit/UIKit.h>
#import <QtGui/QtGui>
@@ -8,3 +11,5 @@
@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate>
@end
+
+#endif // QIOSAPPLICATIONDELEGATE_H
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
index a017fef457..c6e5a83874 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -3,15 +3,21 @@
#include "qiosapplicationdelegate.h"
+#include "qiosglobal.h"
#include "qiosintegration.h"
#include "qiosservices.h"
#include "qiosviewcontroller.h"
#include "qioswindow.h"
+#include "qiosscreen.h"
+#include "quiwindow.h"
#include <qpa/qplatformintegration.h>
#include <QtCore/QtCore>
+@interface QIOSWindowSceneDelegate : NSObject<UIWindowSceneDelegate>
+@end
+
@implementation QIOSApplicationDelegate
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler
@@ -50,5 +56,44 @@
return iosServices->handleUrl(QUrl::fromNSURL(url));
}
+- (UISceneConfiguration *)application:(UIApplication *)application
+ configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession
+ options:(UISceneConnectionOptions *)options
+{
+ qCDebug(lcQpaWindowScene) << "Configuring scene for" << connectingSceneSession
+ << "with options" << options;
+
+ auto *sceneConfig = connectingSceneSession.configuration;
+ sceneConfig.delegateClass = QIOSWindowSceneDelegate.class;
+ return sceneConfig;
+}
+
@end
+@implementation QIOSWindowSceneDelegate
+
+- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
+{
+ qCDebug(lcQpaWindowScene) << "Connecting" << scene << "to" << session;
+
+ Q_ASSERT([scene isKindOfClass:UIWindowScene.class]);
+ UIWindowScene *windowScene = static_cast<UIWindowScene*>(scene);
+
+ QUIWindow *window = [[QUIWindow alloc] initWithWindowScene:windowScene];
+
+ QIOSScreen *screen = [&]{
+ for (auto *screen : qGuiApp->screens()) {
+ auto *platformScreen = static_cast<QIOSScreen*>(screen->handle());
+#if !defined(Q_OS_VISIONOS)
+ if (platformScreen->uiScreen() == windowScene.screen)
+#endif
+ return platformScreen;
+ }
+ Q_UNREACHABLE();
+ }();
+
+ window.rootViewController = [[[QIOSViewController alloc]
+ initWithWindow:window andScreen:screen] autorelease];
+}
+
+@end
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
index fca0432426..09e2f2f4c3 100644
--- a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
@@ -30,14 +30,14 @@
case QFileDialogOptions::AnyFile:
case QFileDialogOptions::ExistingFile:
case QFileDialogOptions::ExistingFiles:
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeContent]];
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeItem]];
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeData]];
+ [docTypes addObject:UTTypeContent];
+ [docTypes addObject:UTTypeItem];
+ [docTypes addObject:UTTypeData];
break;
// Showing files is not supported in Directory mode in iOS
case QFileDialogOptions::Directory:
case QFileDialogOptions::DirectoryOnly:
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeFolder]];
+ [docTypes addObject:UTTypeFolder];
break;
}
}
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
index b40024ec19..5eee0556f5 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.h
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -16,6 +16,8 @@ public:
static QIOSEventDispatcher* create();
bool processPostedEvents() override;
+ static bool isQtApplication();
+
protected:
explicit QIOSEventDispatcher(QObject *parent = nullptr);
};
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index 24d9d88294..710a834bfd 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -5,6 +5,10 @@
#include "qiosapplicationdelegate.h"
#include "qiosglobal.h"
+#if defined(Q_OS_VISIONOS)
+#include "qiosswiftintegration.h"
+#endif
+
#include <QtCore/qprocessordetection.h>
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qthread_p.h>
@@ -173,12 +177,16 @@ namespace
QAppleLogActivity UIApplicationMain;
QAppleLogActivity applicationDidFinishLaunching;
} logActivity;
+
+ static bool s_isQtApplication = false;
}
using namespace QT_PREPEND_NAMESPACE(QtPrivate);
extern "C" int qt_main_wrapper(int argc, char *argv[])
{
+ s_isQtApplication = true;
+
@autoreleasepool {
size_t defaultStackSize = 512 * kBytesPerKiloByte; // Same as secondary threads
@@ -202,8 +210,16 @@ extern "C" int qt_main_wrapper(int argc, char *argv[])
logActivity.UIApplicationMain = QT_APPLE_LOG_ACTIVITY(
lcEventDispatcher().isDebugEnabled(), "UIApplicationMain").enter();
+#if defined(Q_OS_VISIONOS)
+ Q_UNUSED(argc);
+ Q_UNUSED(argv);
+ qCDebug(lcEventDispatcher) << "Starting Swift app";
+ QIOSIntegrationPluginSwift::runSwiftAppMain();
+ Q_UNREACHABLE();
+#else
qCDebug(lcEventDispatcher) << "Running UIApplicationMain";
return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate class]));
+#endif
}
}
@@ -424,6 +440,11 @@ QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
QWindowSystemInterface::setSynchronousWindowSystemEvents(true);
}
+bool QIOSEventDispatcher::isQtApplication()
+{
+ return s_isQtApplication;
+}
+
/*!
Override of the CoreFoundation posted events runloop source callback
so that we can send window system (QPA) events in addition to sending
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
index 0fafbe1936..9428487a00 100644
--- a/src/plugins/platforms/ios/qiosglobal.h
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -14,6 +14,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaApplication);
Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods);
Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindowScene);
#if !defined(QT_NO_DEBUG)
#define qImDebug \
@@ -36,7 +37,9 @@ UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation)
int infoPlistValue(NSString* key, int defaultValue);
class QWindow;
+class QScreen;
UIWindow *presentationWindow(QWindow *);
+UIView *rootViewForScreen(QScreen *);
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index eb9e713b0d..1722e09aaa 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -5,6 +5,8 @@
#include "qiosapplicationdelegate.h"
#include "qiosviewcontroller.h"
#include "qiosscreen.h"
+#include "quiwindow.h"
+#include "qioseventdispatcher.h"
#include <QtCore/private/qcore_mac_p.h>
@@ -13,20 +15,17 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+Q_LOGGING_CATEGORY(lcQpaWindowScene, "qt.qpa.window.scene");
bool isQtApplication()
{
- if (qt_apple_isApplicationExtension())
- return false;
-
// Returns \c true if the plugin is in full control of the whole application. This means
// that we control the application delegate and the top view controller, and can take
// actions that impacts all parts of the application. The opposite means that we are
// embedded inside a native iOS application, and should be more focused on playing along
// with native UIControls, and less inclined to change structures that lies outside the
// scope of our QWindows/UIViews.
- static bool isQt = ([qt_apple_sharedApplication().delegate isKindOfClass:[QIOSApplicationDelegate class]]);
- return isQt;
+ return QIOSEventDispatcher::isQtApplication();
}
bool isRunningOnVisionOS()
@@ -109,6 +108,38 @@ UIWindow *presentationWindow(QWindow *window)
return uiWindow;
}
+UIView *rootViewForScreen(QScreen *screen)
+{
+ const auto *iosScreen = static_cast<QIOSScreen *>(screen->handle());
+ for (UIScene *scene in [qt_apple_sharedApplication().connectedScenes allObjects]) {
+ if (![scene isKindOfClass:UIWindowScene.class])
+ continue;
+
+ auto *windowScene = static_cast<UIWindowScene*>(scene);
+
+#if !defined(Q_OS_VISIONOS)
+ if (windowScene.screen != iosScreen->uiScreen())
+ continue;
+#else
+ Q_UNUSED(iosScreen);
+#endif
+
+ UIWindow *uiWindow = qt_objc_cast<QUIWindow*>(windowScene.keyWindow);
+ if (!uiWindow) {
+ for (UIWindow *win in windowScene.windows) {
+ if (qt_objc_cast<QUIWindow*>(win)) {
+ uiWindow = win;
+ break;
+ }
+ }
+ }
+
+ return uiWindow.rootViewController.view;
+ }
+
+ return nullptr;
+}
+
QT_END_NAMESPACE
// -------------------------------------------------------------------------
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 2c7d33cc94..53f64c1748 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -16,11 +16,24 @@
#include "qiostextinputoverlay.h"
#endif
+#if defined(Q_OS_VISIONOS)
+#include <swift/bridging>
+#endif
+
QT_BEGIN_NAMESPACE
+using namespace QNativeInterface;
+
class QIOSServices;
-class QIOSIntegration : public QPlatformNativeInterface, public QPlatformIntegration
+class
+#if defined(Q_OS_VISIONOS)
+ SWIFT_IMMORTAL_REFERENCE
+#endif
+QIOSIntegration : public QPlatformNativeInterface, public QPlatformIntegration
+#if defined(Q_OS_VISIONOS)
+ , public QVisionOSApplication
+#endif
{
Q_OBJECT
public:
@@ -77,6 +90,17 @@ public:
QIOSApplicationState applicationState;
+#if defined(Q_OS_VISIONOS)
+ void openImmersiveSpace() override;
+ void dismissImmersiveSpace() override;
+
+ using CompositorLayer = QVisionOSApplication::ImmersiveSpaceCompositorLayer;
+ void setImmersiveSpaceCompositorLayer(CompositorLayer *layer) override;
+
+ void configureCompositorLayer(cp_layer_renderer_capabilities_t, cp_layer_renderer_configuration_t);
+ void renderCompositorLayer(cp_layer_renderer_t);
+#endif
+
private:
QPlatformFontDatabase *m_fontDatabase;
#if QT_CONFIG(clipboard)
@@ -90,6 +114,10 @@ private:
#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QIOSTextInputOverlay m_textInputOverlay;
#endif
+
+#if defined(Q_OS_VISIONOS)
+ CompositorLayer *m_immersiveSpaceCompositorLayer = nullptr;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 7cd21f83f6..2c32957c03 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -17,6 +17,10 @@
#include "qiosservices.h"
#include "qiosoptionalplugininterface.h"
+#if defined(Q_OS_VISIONOS)
+#include "qiosswiftintegration.h"
+#endif
+
#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qrhibackingstore_p.h>
@@ -296,6 +300,39 @@ void QIOSIntegration::setApplicationBadge(qint64 number)
// ---------------------------------------------------------
+#if defined(Q_OS_VISIONOS)
+void QIOSIntegration::openImmersiveSpace()
+{
+ [ImmersiveSpaceManager openImmersiveSpace];
+}
+
+void QIOSIntegration::dismissImmersiveSpace()
+{
+ [ImmersiveSpaceManager dismissImmersiveSpace];
+}
+
+void QIOSIntegration::setImmersiveSpaceCompositorLayer(CompositorLayer *layer)
+{
+ m_immersiveSpaceCompositorLayer = layer;
+}
+
+void QIOSIntegration::configureCompositorLayer(cp_layer_renderer_capabilities_t capabilities,
+ cp_layer_renderer_configuration_t configuration)
+{
+ if (m_immersiveSpaceCompositorLayer)
+ m_immersiveSpaceCompositorLayer->configure(capabilities, configuration);
+}
+
+void QIOSIntegration::renderCompositorLayer(cp_layer_renderer_t renderer)
+{
+ if (m_immersiveSpaceCompositorLayer)
+ m_immersiveSpaceCompositorLayer->render(renderer);
+}
+
+#endif
+
+// ---------------------------------------------------------
+
void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
{
if (!window || !window->handle())
diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h
index 005ea8b2ee..dd69428390 100644
--- a/src/plugins/platforms/ios/qiosscreen.h
+++ b/src/plugins/platforms/ios/qiosscreen.h
@@ -43,7 +43,6 @@ public:
#if !defined(Q_OS_VISIONOS)
UIScreen *uiScreen() const;
#endif
- UIWindow *uiWindow() const;
void setUpdatesPaused(bool);
@@ -55,7 +54,6 @@ private:
#if !defined(Q_OS_VISIONOS)
UIScreen *m_uiScreen = nullptr;
#endif
- UIWindow *m_uiWindow = nullptr;
QRect m_geometry;
QRect m_availableGeometry;
int m_depth;
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index e41a6ab46f..7559979f33 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -176,21 +176,6 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
m_physicalDpi = 96;
}
- if (!qt_apple_isApplicationExtension()) {
- for (UIWindow *existingWindow in qt_apple_sharedApplication().windows) {
- if (existingWindow.screen == m_uiScreen) {
- m_uiWindow = [existingWindow retain];
- break;
- }
- }
-
- if (!m_uiWindow) {
- // Create a window and associated view-controller that we can use
- m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]];
- m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
- }
- }
-
m_displayLink = [m_uiScreen displayLinkWithBlock:^(CADisplayLink *) { deliverUpdateRequests(); }];
m_displayLink.paused = YES; // Enabled when clients call QWindow::requestUpdate()
[m_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
@@ -203,8 +188,6 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
QIOSScreen::~QIOSScreen()
{
[m_displayLink invalidate];
-
- [m_uiWindow release];
}
QString QIOSScreen::name() const
@@ -390,7 +373,8 @@ QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height)
if (window && ![reinterpret_cast<id>(window) isKindOfClass:[UIView class]])
return QPixmap();
- UIView *view = window ? reinterpret_cast<UIView *>(window) : m_uiWindow.rootViewController.view;
+ UIView *view = window ? reinterpret_cast<UIView *>(window)
+ : rootViewForScreen(screen());
if (width < 0)
width = qMax(view.bounds.size.width - x, CGFloat(0));
@@ -424,11 +408,6 @@ UIScreen *QIOSScreen::uiScreen() const
}
#endif
-UIWindow *QIOSScreen::uiWindow() const
-{
- return m_uiWindow;
-}
-
QT_END_NAMESPACE
#include "moc_qiosscreen.cpp"
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index 01046334a1..83170c1851 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -434,7 +434,7 @@ static void executeBlockWithoutAnimation(Block block)
if (enabled) {
_focusView = [reinterpret_cast<UIView *>(qApp->focusWindow()->winId()) retain];
- _desktopView = [qt_apple_sharedApplication().keyWindow.rootViewController.view retain];
+ _desktopView = [presentationWindow(nullptr).rootViewController.view retain];
Q_ASSERT(_focusView && _desktopView && _desktopView.superview);
[_desktopView addGestureRecognizer:self];
} else {
diff --git a/src/plugins/platforms/ios/qiostheme.h b/src/plugins/platforms/ios/qiostheme.h
index f0a404a61a..70e2c37ff1 100644
--- a/src/plugins/platforms/ios/qiostheme.h
+++ b/src/plugins/platforms/ios/qiostheme.h
@@ -4,6 +4,8 @@
#ifndef QIOSTHEME_H
#define QIOSTHEME_H
+#import <UIKit/UIKit.h>
+
#include <QtCore/QHash>
#include <QtGui/QPalette>
#include <qpa/qplatformtheme.h>
@@ -22,6 +24,7 @@ public:
QVariant themeHint(ThemeHint hint) const override;
Qt::ColorScheme colorScheme() const override;
+ void requestColorScheme(Qt::ColorScheme scheme) override;
#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QPlatformMenuItem* createPlatformMenuItem() const override;
@@ -37,9 +40,11 @@ public:
static const char *name;
static void initializeSystemPalette();
+ static void applyTheme(UIWindow *window);
private:
static QPalette s_systemPalette;
+ static inline Qt::ColorScheme s_colorSchemeOverride = Qt::ColorScheme::Unknown;
QMacNotificationObserver m_contentSizeCategoryObserver;
};
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
index 3853de9cf1..0b420a875a 100644
--- a/src/plugins/platforms/ios/qiostheme.mm
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -154,6 +154,9 @@ Qt::ColorScheme QIOSTheme::colorScheme() const
// the OS reports itself as always being in dark mode.
return Qt::ColorScheme::Dark;
#else
+ if (s_colorSchemeOverride != Qt::ColorScheme::Unknown)
+ return s_colorSchemeOverride;
+
// Set the appearance based on the QUIWindow
// Fallback to the UIScreen if no window is created yet
UIUserInterfaceStyle appearance = UIScreen.mainScreen.traitCollection.userInterfaceStyle;
@@ -171,6 +174,38 @@ Qt::ColorScheme QIOSTheme::colorScheme() const
#endif
}
+void QIOSTheme::requestColorScheme(Qt::ColorScheme scheme)
+{
+#if defined(Q_OS_VISIONOS)
+ Q_UNUSED(scheme);
+#else
+ s_colorSchemeOverride = scheme;
+
+ const NSArray<UIWindow *> *windows = qt_apple_sharedApplication().windows;
+ for (UIWindow *window in windows) {
+ // don't apply a theme to windows we don't own
+ if (qt_objc_cast<QUIWindow*>(window))
+ applyTheme(window);
+ }
+#endif
+}
+
+void QIOSTheme::applyTheme(UIWindow *window)
+{
+ const UIUserInterfaceStyle style = []{
+ switch (s_colorSchemeOverride) {
+ case Qt::ColorScheme::Dark:
+ return UIUserInterfaceStyleDark;
+ case Qt::ColorScheme::Light:
+ return UIUserInterfaceStyleLight;
+ case Qt::ColorScheme::Unknown:
+ return UIUserInterfaceStyleUnspecified;
+ }
+ }();
+
+ window.overrideUserInterfaceStyle = style;
+}
+
const QFont *QIOSTheme::font(Font type) const
{
const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
index 71a5271934..1f8da41ba4 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.h
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -12,7 +12,7 @@ QT_END_NAMESPACE
@interface QIOSViewController : UIViewController
-- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
+- (instancetype)initWithWindow:(UIWindow*)window andScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
- (void)updateProperties;
- (NSArray*)keyCommands;
- (void)handleShortcut:(UIKeyCommand*)keyCommand;
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index 4f0c8a2ecc..436d1e7bed 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -26,6 +26,7 @@
// -------------------------------------------------------------------------
@interface QIOSViewController ()
+@property (nonatomic, assign) UIWindow *window;
@property (nonatomic, assign) QPointer<QT_PREPEND_NAMESPACE(QIOSScreen)> platformScreen;
@property (nonatomic, assign) BOOL changingOrientation;
@end
@@ -88,28 +89,25 @@
- (void)didAddSubview:(UIView *)subview
{
-#if !defined(Q_OS_VISIONOS)
Q_UNUSED(subview);
- QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController.platformScreen;
-
- // The 'window' property of our view is not valid until the window
- // has been shown, so we have to access it through the QIOSScreen.
- UIWindow *uiWindow = screen->uiWindow();
+ // Track UIWindow via explicit property on QIOSViewController,
+ // as the window property of our own view is not valid until
+ // the window has been shown (below).
+ UIWindow *uiWindow = self.qtViewController.window;
if (uiWindow.hidden) {
- // Associate UIWindow to screen and show it the first time a QWindow
- // is mapped to the screen. For external screens this means disabling
- // mirroring mode and presenting alternate content on the screen.
- uiWindow.screen = screen->uiScreen();
+ // Show the UIWindow the first time a QWindow is mapped to the screen.
+ // For the main screen this hides the launch screen, while for external
+ // screens this disables mirroring of the main screen, so the external
+ // screen can be used for alternate content.
uiWindow.hidden = NO;
}
-#endif
}
+#if !defined(Q_OS_VISIONOS)
- (void)willRemoveSubview:(UIView *)subview
{
-#if !defined(Q_OS_VISIONOS)
Q_UNUSED(subview);
UIWindow *uiWindow = self.window;
@@ -124,11 +122,10 @@
// to ensure that we don't try to layout the view that's being removed.
dispatch_async(dispatch_get_main_queue(), ^{
uiWindow.hidden = YES;
- uiWindow.screen = [UIScreen mainScreen];
});
}
-#endif
}
+#endif
- (void)layoutSubviews
{
@@ -234,9 +231,10 @@
@synthesize preferredStatusBarStyle;
#endif
-- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
+- (instancetype)initWithWindow:(UIWindow*)window andScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
{
if (self = [self init]) {
+ self.window = window;
self.platformScreen = screen;
self.changingOrientation = NO;
@@ -297,6 +295,15 @@
name:UIApplicationDidChangeStatusBarOrientationNotification
object:qt_apple_sharedApplication()];
#endif
+
+ // Make sure any top level windows that have already been created
+ // for this screen are reparented into our desktop manager view.
+ for (auto *window : qGuiApp->topLevelWindows()) {
+ if (window->screen()->handle() != self.platformScreen)
+ continue;
+ if (auto *platformWindow = window->handle())
+ platformWindow->setParent(nullptr);
+ }
}
- (void)viewDidUnload
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 90e955b90b..f461a5f55b 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -55,8 +55,10 @@ QIOSWindow::QIOSWindow(QWindow *window, WId nativeHandle)
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QIOSWindow::applicationStateChanged);
- if (QPlatformWindow::parent())
- setParent(QPlatformWindow::parent());
+ // Always set parent, even if we don't have a parent window,
+ // as we use setParent to reparent top levels into our desktop
+ // manager view.
+ setParent(QPlatformWindow::parent());
if (!isForeignWindow()) {
// Resolve default window geometry in case it was not set before creating the
@@ -298,14 +300,14 @@ void QIOSWindow::setWindowState(Qt::WindowStates state)
void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
{
- UIView *parentView = parentWindow ?
- reinterpret_cast<UIView *>(parentWindow->winId())
- : isQtApplication() && !isForeignWindow() ?
- static_cast<QIOSScreen *>(screen())->uiWindow().rootViewController.view
- : nullptr;
-
- if (parentView)
- [parentView addSubview:m_view];
+ UIView *superview = nullptr;
+ if (parentWindow)
+ superview = reinterpret_cast<UIView *>(parentWindow->winId());
+ else if (isQtApplication() && !isForeignWindow())
+ superview = rootViewForScreen(window()->screen());
+
+ if (superview)
+ [superview addSubview:m_view];
else if (quiview_cast(m_view.superview))
[m_view removeFromSuperview];
}
diff --git a/src/plugins/platforms/ios/quiwindow.mm b/src/plugins/platforms/ios/quiwindow.mm
index 7c910b6d9e..783e243e10 100644
--- a/src/plugins/platforms/ios/quiwindow.mm
+++ b/src/plugins/platforms/ios/quiwindow.mm
@@ -22,6 +22,15 @@
return self;
}
+- (instancetype)initWithWindowScene:(UIWindowScene *)windowScene
+{
+ if ((self = [super initWithWindowScene:windowScene]))
+ self->_sendingEvent = NO;
+
+ QIOSTheme::applyTheme(self);
+ return self;
+}
+
- (void)sendEvent:(UIEvent *)event
{
QScopedValueRollback<BOOL> sendingEvent(self->_sendingEvent, YES);
diff --git a/src/plugins/platforms/linuxfb/CMakeLists.txt b/src/plugins/platforms/linuxfb/CMakeLists.txt
index 9f75f53828..ba18cea50c 100644
--- a/src/plugins/platforms/linuxfb/CMakeLists.txt
+++ b/src/plugins/platforms/linuxfb/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QLinuxFbIntegrationPlugin
OUTPUT_NAME qlinuxfb
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES linuxfb
+ DEFAULT_IF "linuxfb" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qlinuxfbintegration.cpp qlinuxfbintegration.h
diff --git a/src/plugins/platforms/minimal/CMakeLists.txt b/src/plugins/platforms/minimal/CMakeLists.txt
index f3683deccf..18d8828134 100644
--- a/src/plugins/platforms/minimal/CMakeLists.txt
+++ b/src/plugins/platforms/minimal/CMakeLists.txt
@@ -10,7 +10,7 @@ qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
qt_internal_add_plugin(QMinimalIntegrationPlugin
OUTPUT_NAME qminimal
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimal
+ DEFAULT_IF "minimal" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qminimalbackingstore.cpp qminimalbackingstore.h
diff --git a/src/plugins/platforms/minimalegl/CMakeLists.txt b/src/plugins/platforms/minimalegl/CMakeLists.txt
index a6ec8be781..b93f325b8f 100644
--- a/src/plugins/platforms/minimalegl/CMakeLists.txt
+++ b/src/plugins/platforms/minimalegl/CMakeLists.txt
@@ -10,7 +10,7 @@ qt_find_package(EGL)
qt_internal_add_plugin(QMinimalEglIntegrationPlugin
OUTPUT_NAME qminimalegl
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimalegl
+ DEFAULT_IF "minimalegl" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qminimaleglintegration.cpp qminimaleglintegration.h
diff --git a/src/plugins/platforms/offscreen/CMakeLists.txt b/src/plugins/platforms/offscreen/CMakeLists.txt
index 09ad9a384d..907c2c9cc6 100644
--- a/src/plugins/platforms/offscreen/CMakeLists.txt
+++ b/src/plugins/platforms/offscreen/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QOffscreenIntegrationPlugin
OUTPUT_NAME qoffscreen
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES offscreen
+ DEFAULT_IF "offscreen" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qoffscreencommon.cpp qoffscreencommon.h
diff --git a/src/plugins/platforms/qnx/CMakeLists.txt b/src/plugins/platforms/qnx/CMakeLists.txt
index 9fb412d8a4..0f9deaa00b 100644
--- a/src/plugins/platforms/qnx/CMakeLists.txt
+++ b/src/plugins/platforms/qnx/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QQnxIntegrationPlugin
OUTPUT_NAME qqnx
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES qnx
+ DEFAULT_IF "qnx" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp main.h
qqnxabstractcover.h
diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
index 05389d3ea6..9b1107b7ec 100644
--- a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
+++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
@@ -6,14 +6,10 @@
#include <QDebug>
#include <QUrl>
-#if defined(QQNXNAVIGATOR_DEBUG)
-#define qNavigatorDebug qDebug
-#else
-#define qNavigatorDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaQnxNavigator, "qt.qpa.qnx.navigator");
+
QQnxAbstractNavigator::QQnxAbstractNavigator(QObject *parent)
: QObject(parent)
{
@@ -32,7 +28,7 @@ bool QQnxAbstractNavigator::invokeUrl(const QUrl &url)
// which is not recognized by the navigator anymore
const bool result = requestInvokeUrl(url.toString().toUtf8());
- qNavigatorDebug() << "url=" << url << "result=" << result;
+ qCDebug(lcQpaQnxNavigator) << Q_FUNC_INFO << "url =" << url << "result =" << result;
return result;
}
diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.h b/src/plugins/platforms/qnx/qqnxabstractnavigator.h
index b4e4dd9bf8..fc92592307 100644
--- a/src/plugins/platforms/qnx/qqnxabstractnavigator.h
+++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.h
@@ -5,9 +5,12 @@
#define QQNXABSTRACTNAVIGATOR_H
#include <QObject>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxNavigator);
+
class QUrl;
class QQnxAbstractNavigator : public QObject
diff --git a/src/plugins/platforms/qnx/qqnxbuffer.cpp b/src/plugins/platforms/qnx/qqnxbuffer.cpp
index 1ea9a8b0d3..4d3b5256b2 100644
--- a/src/plugins/platforms/qnx/qqnxbuffer.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuffer.cpp
@@ -10,24 +10,20 @@
#include <errno.h>
#include <sys/mman.h>
-#if defined(QQNXBUFFER_DEBUG)
-#define qBufferDebug qDebug
-#else
-#define qBufferDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaScreenBuffer, "qt.qpa.screen.buffer");
+
QQnxBuffer::QQnxBuffer()
: m_buffer(0)
{
- qBufferDebug("empty");
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO << "Empty";
}
QQnxBuffer::QQnxBuffer(screen_buffer_t buffer)
: m_buffer(buffer)
{
- qBufferDebug("normal");
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO << "Normal";
// Get size of buffer
int size[2];
@@ -77,7 +73,7 @@ QQnxBuffer::QQnxBuffer(screen_buffer_t buffer)
imageFormat = QImage::Format_ARGB32_Premultiplied;
break;
default:
- qFatal("QQNX: unsupported buffer format, format=%d", screenFormat);
+ qFatal(lcQpaScreenBuffer, "QQNX: unsupported buffer format, format=%d", screenFormat);
}
// wrap buffer in an image
@@ -88,27 +84,27 @@ QQnxBuffer::QQnxBuffer(const QQnxBuffer &other)
: m_buffer(other.m_buffer),
m_image(other.m_image)
{
- qBufferDebug("copy");
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO << "Copy";
}
QQnxBuffer::~QQnxBuffer()
{
- qBufferDebug();
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO;
}
void QQnxBuffer::invalidateInCache()
{
- qBufferDebug();
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO;
// Verify native buffer exists
if (Q_UNLIKELY(!m_buffer))
- qFatal("QQNX: can't invalidate cache for null buffer");
+ qFatal(lcQpaScreenBuffer, "QQNX: can't invalidate cache for null buffer");
// Evict buffer's data from cache
errno = 0;
int result = msync(m_image.bits(), m_image.height() * m_image.bytesPerLine(), MS_INVALIDATE | MS_CACHE_ONLY);
if (Q_UNLIKELY(result != 0))
- qFatal("QQNX: failed to invalidate cache, errno=%d", errno);
+ qFatal(lcQpaScreenBuffer, "QQNX: failed to invalidate cache, errno=%d", errno);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxbuffer.h b/src/plugins/platforms/qnx/qqnxbuffer.h
index b8f1443ad1..b456eb2a62 100644
--- a/src/plugins/platforms/qnx/qqnxbuffer.h
+++ b/src/plugins/platforms/qnx/qqnxbuffer.h
@@ -5,11 +5,14 @@
#define QQNXBUFFER_H
#include <QtGui/QImage>
+#include <QtCore/QLoggingCategory>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenBuffer)
+
class QQnxBuffer
{
public:
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
index 6497367579..788cddea87 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
@@ -13,14 +13,10 @@
#include <QtCore/QSocketNotifier>
#include <QtCore/private/qcore_unix_p.h>
-#if defined(QQNXBUTTON_DEBUG)
-#define qButtonDebug qDebug
-#else
-#define qButtonDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaInputHwButton, "qt.qpa.input.hwbutton");
+
const char *QQnxButtonEventNotifier::ppsPath = "/pps/system/buttons/status";
const size_t QQnxButtonEventNotifier::ppsBufferSize = 256;
@@ -47,7 +43,7 @@ QQnxButtonEventNotifier::~QQnxButtonEventNotifier()
void QQnxButtonEventNotifier::start()
{
- qButtonDebug("starting hardware button event processing");
+ qCDebug(lcQpaInputHwButton) << "Starting hardware button event processing";
if (m_fd != -1)
return;
@@ -64,7 +60,7 @@ void QQnxButtonEventNotifier::start()
m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
QObject::connect(m_readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(updateButtonStates()));
- qButtonDebug("successfully connected to Navigator. fd = %d", m_fd);
+ qCDebug(lcQpaInputHwButton, "successfully connected to Navigator. fd = %d", m_fd);
}
void QQnxButtonEventNotifier::updateButtonStates()
@@ -75,7 +71,8 @@ void QQnxButtonEventNotifier::updateButtonStates()
// Attempt to read pps data
errno = 0;
int bytes = qt_safe_read(m_fd, buffer, ppsBufferSize - 1);
- qButtonDebug() << "Read" << bytes << "bytes of data";
+ qCDebug(lcQpaInputHwButton) << "Read" << bytes << "bytes of data";
+
if (bytes == -1) {
qWarning("QQNX: failed to read hardware buttons pps object, errno=%d", errno);
return;
@@ -88,7 +85,7 @@ void QQnxButtonEventNotifier::updateButtonStates()
// Ensure data is null terminated
buffer[bytes] = '\0';
- qButtonDebug("received PPS message:\n%s", buffer);
+ qCDebug(lcQpaInputHwButton, "Received PPS message:\n%s", buffer);
// Process received message
QByteArray ppsData = QByteArray::fromRawData(buffer, bytes);
@@ -104,7 +101,8 @@ void QQnxButtonEventNotifier::updateButtonStates()
// If state has changed, update our state and inject a keypress event
if (m_state[buttonId] != newState) {
- qButtonDebug() << "Hardware button event: button =" << key << "state =" << fields.value(key);
+ qCDebug(lcQpaInputHwButton) << "Hardware button event: button =" << key << "state =" << fields.value(key);
+
m_state[buttonId] = newState;
// Is it a key press or key release event?
@@ -129,7 +127,7 @@ void QQnxButtonEventNotifier::updateButtonStates()
break;
default:
- qButtonDebug("Unknown hardware button");
+ qCDebug(lcQpaInputHwButton) << "Unknown hardware button";
continue;
}
@@ -170,7 +168,7 @@ bool QQnxButtonEventNotifier::parsePPS(const QByteArray &ppsData, QHash<QByteArr
// tokenize current attribute
const QByteArray &attr = lines.at(i);
- qButtonDebug() << "attr=" << attr;
+ qCDebug(lcQpaInputHwButton) << Q_FUNC_INFO << "attr =" << attr;
int doubleColon = attr.indexOf(QByteArrayLiteral("::"));
if (doubleColon == -1) {
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
index 81ccf64415..476119ae27 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
@@ -5,9 +5,12 @@
#define QQNXBUTTONSEVENTNOTIFIER_H
#include <QObject>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaInputHwButton);
+
class QSocketNotifier;
class QQnxButtonEventNotifier : public QObject
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.cpp b/src/plugins/platforms/qnx/qqnxclipboard.cpp
index 8e42148c12..3f27ec8069 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.cpp
+++ b/src/plugins/platforms/qnx/qqnxclipboard.cpp
@@ -17,14 +17,10 @@
#include <clipboard/clipboard.h>
#include <errno.h>
-#if defined(QQNXCLIPBOARD_DEBUG)
-#define qClipboardDebug qDebug
-#else
-#define qClipboardDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard");
+
// null terminated array
static const char *typeList[] = {"text/html", "text/plain", "image/png", "image/jpeg", "application/x-color", 0};
@@ -66,13 +62,13 @@ public:
void addFormatToCheck(const QString &format) {
m_formatsToCheck << format;
- qClipboardDebug() << "formats=" << m_formatsToCheck;
+ qCDebug(lcQpaClipboard) << "formats=" << m_formatsToCheck;
}
bool hasFormat(const QString &mimetype) const override
{
const bool result = is_clipboard_format_present(mimetype.toUtf8().constData()) == 0;
- qClipboardDebug() << "mimetype=" << mimetype << "result=" << result;
+ qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "result=" << result;
return result;
}
@@ -85,7 +81,7 @@ public:
result << format;
}
- qClipboardDebug() << "result=" << result;
+ qCDebug(lcQpaClipboard) << "result=" << result;
return result;
}
@@ -109,7 +105,7 @@ public:
protected:
QVariant retrieveData(const QString &mimetype, QMetaType preferredType) const override
{
- qClipboardDebug() << "mimetype=" << mimetype << "preferredType=" << preferredType.name();
+ qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "preferredType=" << preferredType.name();
if (is_clipboard_format_present(mimetype.toUtf8().constData()) != 0)
return QMimeData::retrieveData(mimetype, preferredType);
@@ -121,7 +117,7 @@ private Q_SLOTS:
void releaseOwnership()
{
if (m_userMimeData) {
- qClipboardDebug() << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats();
+ qCDebug(lcQpaClipboard) << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats();
delete m_userMimeData;
m_userMimeData = 0;
m_clipboard->emitChanged(QClipboard::Clipboard);
@@ -167,7 +163,7 @@ void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
}
const QStringList formats = data->formats();
- qClipboardDebug() << "formats=" << formats;
+ qCDebug(lcQpaClipboard) << "formats=" << formats;
Q_FOREACH (const QString &format, formats) {
const QByteArray buf = data->data(format);
@@ -176,7 +172,7 @@ void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
continue;
int ret = set_clipboard_data(format.toUtf8().data(), buf.size(), buf.data());
- qClipboardDebug() << "set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret;
+ qCDebug(lcQpaClipboard) << "set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret;
if (ret)
m_mimeData->addFormatToCheck(format);
}
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.h b/src/plugins/platforms/qnx/qqnxclipboard.h
index adc70b158a..66f862f0dc 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.h
+++ b/src/plugins/platforms/qnx/qqnxclipboard.h
@@ -11,6 +11,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard);
+
class QQnxClipboard : public QPlatformClipboard
{
public:
diff --git a/src/plugins/platforms/qnx/qqnxcursor.cpp b/src/plugins/platforms/qnx/qqnxcursor.cpp
index 03c4e16401..7c55dd79b3 100644
--- a/src/plugins/platforms/qnx/qqnxcursor.cpp
+++ b/src/plugins/platforms/qnx/qqnxcursor.cpp
@@ -5,14 +5,10 @@
#include <QtCore/QDebug>
-#if defined(QQNXCURSOR_DEBUG)
-#define qCursorDebug qDebug
-#else
-#define qCursorDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaQnx, "qt.qpa.qnx");
+
QQnxCursor::QQnxCursor()
{
}
@@ -27,13 +23,13 @@ void QQnxCursor::changeCursor(QCursor *windowCursor, QWindow *window)
void QQnxCursor::setPos(const QPoint &pos)
{
- qCursorDebug() << "QQnxCursor::setPos -" << pos;
+ qCDebug(lcQpaQnx) << "QQnxCursor::setPos -" << pos;
m_pos = pos;
}
QPoint QQnxCursor::pos() const
{
- qCursorDebug() << "QQnxCursor::pos -" << m_pos;
+ qCDebug(lcQpaQnx) << "QQnxCursor::pos -" << m_pos;
return m_pos;
}
diff --git a/src/plugins/platforms/qnx/qqnxcursor.h b/src/plugins/platforms/qnx/qqnxcursor.h
index 6592e0a5ee..707bdbaaa2 100644
--- a/src/plugins/platforms/qnx/qqnxcursor.h
+++ b/src/plugins/platforms/qnx/qqnxcursor.h
@@ -5,9 +5,12 @@
#define QQNXCURSOR_H
#include <qpa/qplatformcursor.h>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+// Q_DECLARE_LOGGING_CATEGORY(lcQpaQnx);
+
class QQnxCursor : public QPlatformCursor
{
public:
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
index ed53308216..854ad46c3d 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
@@ -10,14 +10,10 @@
#include <errno.h>
-#if defined(QQNXEGLWINDOW_DEBUG)
-#define qEglWindowDebug qDebug
-#else
-#define qEglWindowDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaWindowEgl, "qt.qpa.window.egl");
+
QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow) :
QQnxWindow(window, context, needRootWindow),
m_newSurfaceRequested(true),
@@ -96,8 +92,8 @@ void QQnxEglWindow::createEGLSurface(QQnxGLContext *context)
EGL_NONE
};
- qEglWindowDebug() << "Creating EGL surface from" << this << context
- << window()->surfaceType() << window()->type();
+ qCDebug(lcQpaWindowEgl) << "Creating EGL surface from" << this << context
+ << window()->surfaceType() << window()->type();
// Create EGL surface
EGLSurface eglSurface = eglCreateWindowSurface(
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h
index 909a901d3c..548d9be1ee 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.h
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.h
@@ -6,9 +6,12 @@
#include "qqnxwindow.h"
#include <QtCore/QMutex>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindowEgl);
+
class QQnxGLContext;
class QQnxEglWindow : public QQnxWindow
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp
index 7b5b11b2e4..3d8fecf88b 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.cpp
+++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp
@@ -14,14 +14,10 @@
#include <dlfcn.h>
-#if defined(QQNXGLCONTEXT_DEBUG)
-#define qGLContextDebug qDebug
-#else
-#define qGLContextDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaGLContext, "qt.qpa.glcontext");
+
static QEGLPlatformContext::Flags makeFlags()
{
QEGLPlatformContext::Flags result = {};
@@ -51,13 +47,13 @@ EGLSurface QQnxGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface
bool QQnxGLContext::makeCurrent(QPlatformSurface *surface)
{
- qGLContextDebug();
+ qCDebug(lcQpaGLContext) << Q_FUNC_INFO;
return QEGLPlatformContext::makeCurrent(surface);
}
void QQnxGLContext::swapBuffers(QPlatformSurface *surface)
{
- qGLContextDebug();
+ qCDebug(lcQpaGLContext) << Q_FUNC_INFO;
QEGLPlatformContext::swapBuffers(surface);
diff --git a/src/plugins/platforms/qnx/qqnxglobal.cpp b/src/plugins/platforms/qnx/qqnxglobal.cpp
index 85642b44b3..9cfc328e8f 100644
--- a/src/plugins/platforms/qnx/qqnxglobal.cpp
+++ b/src/plugins/platforms/qnx/qqnxglobal.cpp
@@ -15,6 +15,8 @@ void qScreenCheckError(int rc, const char *funcInfo, const char *message, bool c
}
if (Q_UNLIKELY(rc)) {
+ qCDebug(lcQpaQnx, "%s - Screen: %s - Error: %s (%i)", funcInfo, message, strerror(errno), errno);
+
if (Q_UNLIKELY(critical))
qCritical("%s - Screen: %s - Error: %s (%i)", funcInfo, message, strerror(errno), errno);
else
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
index a1063444d1..cd41ebb8c2 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
@@ -25,17 +25,7 @@
#include <process.h>
#include <sys/keycodes.h>
-#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG)
-#define qInputContextIMFRequestDebug qDebug
-#else
-#define qInputContextIMFRequestDebug QT_NO_QDEBUG_MACRO
-#endif
-
-#if defined(QQNXINPUTCONTEXT_DEBUG)
-#define qInputContextDebug qDebug
-#else
-#define qInputContextDebug QT_NO_QDEBUG_MACRO
-#endif
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
static QQnxInputContext *sInputContextInstance;
static QColor sSelectedColor(0,0xb8,0,85);
@@ -161,7 +151,7 @@ static int32_t ic_begin_batch_edit(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static int32_t ic_commit_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfCommitText);
event.ct.text = text;
@@ -176,7 +166,7 @@ static int32_t ic_commit_text(input_session_t *ic, spannable_string_t *text, int
// See comment at beginning of namespace declaration for general information
static int32_t ic_delete_surrounding_text(input_session_t *ic, int32_t left_length, int32_t right_length)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfDeleteSurroundingText);
event.dst.left_length = left_length;
@@ -200,7 +190,7 @@ static int32_t ic_end_batch_edit(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static int32_t ic_finish_composing_text(input_session_t *ic)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfFinishComposingText);
event.fct.result = -1;
@@ -213,7 +203,7 @@ static int32_t ic_finish_composing_text(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static int32_t ic_get_cursor_position(input_session_t *ic)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfGetCursorPosition);
event.gcp.result = -1;
@@ -226,7 +216,7 @@ static int32_t ic_get_cursor_position(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static spannable_string_t *ic_get_text_after_cursor(input_session_t *ic, int32_t n, int32_t flags)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfGetTextAfterCursor);
event.gtac.n = n;
@@ -241,7 +231,7 @@ static spannable_string_t *ic_get_text_after_cursor(input_session_t *ic, int32_t
// See comment at beginning of namespace declaration for general information
static spannable_string_t *ic_get_text_before_cursor(input_session_t *ic, int32_t n, int32_t flags)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfGetTextBeforeCursor);
event.gtac.n = n;
@@ -256,7 +246,7 @@ static spannable_string_t *ic_get_text_before_cursor(input_session_t *ic, int32_
// See comment at beginning of namespace declaration for general information
static int32_t ic_send_event(input_session_t *ic, event_t *event)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest imfEvent(ic, ImfSendEvent);
imfEvent.sae.event = event;
@@ -270,7 +260,7 @@ static int32_t ic_send_event(input_session_t *ic, event_t *event)
// See comment at beginning of namespace declaration for general information
static int32_t ic_send_async_event(input_session_t *ic, event_t *event)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
// There's no difference from our point of view between ic_send_event & ic_send_async_event
QQnxImfRequest imfEvent(ic, ImfSendEvent);
@@ -285,7 +275,7 @@ static int32_t ic_send_async_event(input_session_t *ic, event_t *event)
// See comment at beginning of namespace declaration for general information
static int32_t ic_set_composing_region(input_session_t *ic, int32_t start, int32_t end)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfSetComposingRegion);
event.scr.start = start;
@@ -301,7 +291,7 @@ static int32_t ic_set_composing_region(input_session_t *ic, int32_t start, int32
// See comment at beginning of namespace declaration for general information
static int32_t ic_set_composing_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfSetComposingText);
event.sct.text = text;
@@ -316,7 +306,7 @@ static int32_t ic_set_composing_text(input_session_t *ic, spannable_string_t *te
// See comment at beginning of namespace declaration for general information
static int32_t ic_is_text_selected(input_session_t* ic, int32_t* pIsSelected)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfIsTextSelected);
event.its.pIsSelected = pIsSelected;
@@ -330,7 +320,7 @@ static int32_t ic_is_text_selected(input_session_t* ic, int32_t* pIsSelected)
// See comment at beginning of namespace declaration for general information
static int32_t ic_is_all_text_selected(input_session_t* ic, int32_t* pIsSelected)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfIsAllTextSelected);
event.its.pIsSelected = pIsSelected;
@@ -466,7 +456,7 @@ initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType,
static spannable_string_t *toSpannableString(const QString &text)
{
- qInputContextDebug() << text;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text:" << text;
spannable_string_t *pString = static_cast<spannable_string_t *>(malloc(sizeof(spannable_string_t)));
pString->str = static_cast<wchar_t *>(malloc(sizeof(wchar_t) * text.length() + 1));
@@ -540,7 +530,7 @@ QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVir
m_integration(integration),
m_virtualKeyboard(keyboard)
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
if (!imfAvailable())
return;
@@ -563,7 +553,7 @@ QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVir
QQnxInputContext::~QQnxInputContext()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
Q_ASSERT(sInputContextInstance == this);
sInputContextInstance = nullptr;
@@ -638,7 +628,7 @@ void QQnxInputContext::processImfEvent(QQnxImfRequest *imfEvent)
bool QQnxInputContext::filterEvent( const QEvent *event )
{
- qInputContextDebug() << event;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << event;
switch (event->type()) {
case QEvent::CloseSoftwareInputPanel:
@@ -661,19 +651,19 @@ QRectF QQnxInputContext::keyboardRect() const
void QQnxInputContext::reset()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
endComposition();
}
void QQnxInputContext::commit()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
endComposition();
}
void QQnxInputContext::update(Qt::InputMethodQueries queries)
{
- qInputContextDebug() << queries;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Queries:" << queries;
if (queries & Qt::ImCursorPosition) {
int lastCaret = m_caretPosition;
@@ -685,7 +675,8 @@ void QQnxInputContext::update(Qt::InputMethodQueries queries)
initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED, sizeof(caretEvent));
caretEvent.old_pos = lastCaret;
caretEvent.new_pos = m_caretPosition;
- qInputContextDebug("ictrl_dispatch_event caret changed %d %d", lastCaret, m_caretPosition);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_event caret changed %d %d", lastCaret, m_caretPosition);
+
p_ictrl_dispatch_event(&caretEvent.event);
}
}
@@ -693,7 +684,7 @@ void QQnxInputContext::update(Qt::InputMethodQueries queries)
void QQnxInputContext::closeSession()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
if (!imfAvailable())
return;
@@ -715,7 +706,7 @@ bool QQnxInputContext::openSession()
closeSession();
sInputSession = p_ictrl_open_session(&ic_funcs);
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
return sInputSession != 0;
}
@@ -739,7 +730,7 @@ bool QQnxInputContext::hasSelectedText()
bool QQnxInputContext::dispatchRequestSoftwareInputPanel()
{
- qInputContextDebug() << "requesting keyboard" << m_inputPanelVisible;
+ qCDebug(lcQpaInputMethods) << "Requesting keyboard" << m_inputPanelVisible;
m_virtualKeyboard.showKeyboard();
return true;
@@ -747,7 +738,7 @@ bool QQnxInputContext::dispatchRequestSoftwareInputPanel()
bool QQnxInputContext::dispatchCloseSoftwareInputPanel()
{
- qInputContextDebug() << "hiding keyboard" << m_inputPanelVisible;
+ qCDebug(lcQpaInputMethods) << "Hiding keyboard" << m_inputPanelVisible;
m_virtualKeyboard.hideKeyboard();
return true;
@@ -793,7 +784,7 @@ bool QQnxInputContext::dispatchFocusGainEvent(int inputHints)
focusEvent.style |= IMF_EMAIL_TYPE;
}
- qInputContextDebug() << "ictrl_dispatch_event focus gain style:" << focusEvent.style;
+ qCDebug(lcQpaInputMethods) << "ictrl_dispatch_event focus gain style:" << focusEvent.style;
p_ictrl_dispatch_event((event_t *)&focusEvent);
@@ -803,7 +794,7 @@ bool QQnxInputContext::dispatchFocusGainEvent(int inputHints)
void QQnxInputContext::dispatchFocusLossEvent()
{
if (hasSession()) {
- qInputContextDebug("ictrl_dispatch_event focus lost");
+ qCDebug(lcQpaInputMethods) << "ictrl_dispatch_event focus lost";
focus_event_t focusEvent;
initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, FOCUS_LOST, sizeof(focusEvent));
@@ -878,7 +869,7 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
navigation_event_t navEvent;
initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key, sizeof(navEvent));
navEvent.magnitude = 1;
- qInputContextDebug("ictrl_dispatch_even navigation %d", key);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even navigation %d", key);
p_ictrl_dispatch_event(&navEvent.event);
}
} else {
@@ -891,7 +882,8 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
keyEvent.sequence_id = sequenceId;
p_ictrl_dispatch_event(&keyEvent.event);
- qInputContextDebug("ictrl_dispatch_even key %d", key);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even key %d", key);
+
}
return true;
@@ -907,7 +899,7 @@ void QQnxInputContext::updateCursorPosition()
QCoreApplication::sendEvent(input, &query);
m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
- qInputContextDebug("%d", m_caretPosition);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even key %d", key);
}
void QQnxInputContext::endComposition()
@@ -920,7 +912,7 @@ void QQnxInputContext::endComposition()
if (hasSession()) {
action_event_t actionEvent;
initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION, sizeof(actionEvent));
- qInputContextDebug("ictrl_dispatch_even end composition");
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even end composition");
p_ictrl_dispatch_event(&actionEvent.event);
}
}
@@ -937,7 +929,7 @@ void QQnxInputContext::updateComposition(spannable_string_t *text, int32_t new_c
m_composingText = QString::fromWCharArray(text->str, text->length);
m_isComposing = true;
- qInputContextDebug() << m_composingText << new_cursor_position;
+ qCDebug(lcQpaInputMethods) << "Text =" << m_composingText << "Cursor position =" << new_cursor_position;
QList<QInputMethodEvent::Attribute> attributes;
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
@@ -967,7 +959,7 @@ void QQnxInputContext::updateComposition(spannable_string_t *text, int32_t new_c
format.setFontUnderline(true);
if (highlightColor.isValid())
format.setBackground(QBrush(highlightColor));
- qInputContextDebug() << " attrib: " << underline << highlightColor << text->spans[i].start << text->spans[i].end;
+ qCDebug(lcQpaInputMethods) << "attrib: " << underline << highlightColor << text->spans[i].start << text->spans[i].end;
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, text->spans[i].start,
text->spans[i].end - text->spans[i].start + 1, QVariant(format)));
@@ -986,7 +978,7 @@ void QQnxInputContext::finishComposingText()
QObject *input = qGuiApp->focusObject();
if (input) {
- qInputContextDebug() << m_composingText;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << m_composingText;
QInputMethodEvent event;
event.setCommitString(m_composingText);
@@ -1051,13 +1043,13 @@ int32_t QQnxInputContext::processEvent(event_t *event)
int32_t result = -1;
switch (event->event_type) {
case EVENT_SPELL_CHECK: {
- qInputContextDebug("EVENT_SPELL_CHECK");
+ qCDebug(lcQpaInputMethods) << "EVENT_SPELL_CHECK";
result = handleSpellCheck(reinterpret_cast<spell_check_event_t *>(event));
break;
}
case EVENT_NAVIGATION: {
- qInputContextDebug("EVENT_NAVIGATION");
+ qCDebug(lcQpaInputMethods) << "EVENT_NAVIGATION";
int key = event->event_id == NAVIGATE_UP ? KEYCODE_UP :
event->event_id == NAVIGATE_DOWN ? KEYCODE_DOWN :
@@ -1080,7 +1072,7 @@ int32_t QQnxInputContext::processEvent(event_t *event)
int flags = KEY_SYM_VALID | KEY_CAP_VALID;
if (event->event_id == IMF_KEY_DOWN)
flags |= KEY_DOWN;
- qInputContextDebug("EVENT_KEY %d %d", flags, keySym);
+ qCDebug(lcQpaInputMethods, "EVENT_KEY %d %d", flags, keySym);
QQnxScreenEventHandler::injectKeyboardEvent(flags, keySym, modifiers, 0, keyCap);
result = 0;
break;
@@ -1120,7 +1112,7 @@ int32_t QQnxInputContext::onCommitText(spannable_string_t *text, int32_t new_cur
int32_t QQnxInputContext::onDeleteSurroundingText(int32_t left_length, int32_t right_length)
{
- qInputContextDebug("L: %d R: %d", int(left_length), int(right_length));
+ qCDebug(lcQpaInputMethods, "L: %d R: %d", int(left_length), int(right_length));
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1151,7 +1143,7 @@ int32_t QQnxInputContext::onFinishComposingText()
int32_t QQnxInputContext::onGetCursorPosition()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1165,7 +1157,7 @@ int32_t QQnxInputContext::onGetCursorPosition()
spannable_string_t *QQnxInputContext::onGetTextAfterCursor(int32_t n, int32_t flags)
{
Q_UNUSED(flags);
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1182,7 +1174,7 @@ spannable_string_t *QQnxInputContext::onGetTextAfterCursor(int32_t n, int32_t fl
spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(int32_t n, int32_t flags)
{
Q_UNUSED(flags);
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1201,7 +1193,7 @@ spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(int32_t n, int32_t f
int32_t QQnxInputContext::onSendEvent(event_t *event)
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
return processEvent(event);
}
@@ -1217,7 +1209,7 @@ int32_t QQnxInputContext::onSetComposingRegion(int32_t start, int32_t end)
QString text = query.value(Qt::ImSurroundingText).toString();
m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
- qInputContextDebug() << text;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << text;
m_isUpdatingText = true;
@@ -1260,7 +1252,7 @@ int32_t QQnxInputContext::onIsTextSelected(int32_t* pIsSelected)
{
*pIsSelected = hasSelectedText();
- qInputContextDebug() << *pIsSelected;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << *pIsSelected;
return 0;
}
@@ -1276,20 +1268,20 @@ int32_t QQnxInputContext::onIsAllTextSelected(int32_t* pIsSelected)
*pIsSelected = query.value(Qt::ImSurroundingText).toString().length() == query.value(Qt::ImCurrentSelection).toString().length();
- qInputContextDebug() << *pIsSelected;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << *pIsSelected;
return 0;
}
void QQnxInputContext::showInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
dispatchRequestSoftwareInputPanel();
}
void QQnxInputContext::hideInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
dispatchCloseSoftwareInputPanel();
}
@@ -1305,7 +1297,7 @@ QLocale QQnxInputContext::locale() const
void QQnxInputContext::keyboardVisibilityChanged(bool visible)
{
- qInputContextDebug() << "visible=" << visible;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "visible=" << visible;
if (m_inputPanelVisible != visible) {
m_inputPanelVisible = visible;
emitInputPanelVisibleChanged();
@@ -1314,7 +1306,7 @@ void QQnxInputContext::keyboardVisibilityChanged(bool visible)
void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
{
- qInputContextDebug() << "locale=" << locale;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "locale=" << locale;
if (m_inputPanelLocale != locale) {
m_inputPanelLocale = locale;
emitLocaleChanged();
@@ -1323,7 +1315,7 @@ void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
void QQnxInputContext::setHighlightColor(int index, const QColor &color)
{
- qInputContextDebug() << "setHighlightColor" << index << color << qGuiApp->focusObject();
+ qCDebug(lcQpaInputMethods) << "setHighlightColor" << index << color << qGuiApp->focusObject();
if (!sInputContextInstance)
return;
@@ -1342,7 +1334,7 @@ void QQnxInputContext::setHighlightColor(int index, const QColor &color)
void QQnxInputContext::setFocusObject(QObject *object)
{
- qInputContextDebug() << "input item=" << object;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "input item=" << object;
// Ensure the colors are reset if we've a change in focus object
setHighlightColor(-1, QColor());
@@ -1372,7 +1364,7 @@ void QQnxInputContext::setFocusObject(QObject *object)
bool QQnxInputContext::checkSpelling(const QString &text, void *context, void (*spellCheckDone)(void *context, const QString &text, const QList<int> &indices))
{
- qInputContextDebug() << "text" << text;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << text;
if (!imfAvailable())
return false;
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
index 2a4e5b509b..7789b2830a 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
@@ -10,14 +10,10 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QInputMethodEvent>
-#if defined(QQNXINPUTCONTEXT_DEBUG)
-#define qInputContextDebug qDebug
-#else
-#define qInputContextDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
+
QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVirtualKeyboard &keyboard) :
QPlatformInputContext(),
m_inputPanelVisible(false),
@@ -58,13 +54,13 @@ bool QQnxInputContext::filterEvent( const QEvent *event )
if (event->type() == QEvent::CloseSoftwareInputPanel) {
m_virtualKeyboard.hideKeyboard();
- qInputContextDebug("hiding virtual keyboard");
+ qCDebug(lcQpaInputMethods) << "hiding virtual keyboard";
return false;
}
if (event->type() == QEvent::RequestSoftwareInputPanel) {
m_virtualKeyboard.showKeyboard();
- qInputContextDebug("requesting virtual keyboard");
+ qCDebug(lcQpaInputMethods) << "requesting virtual keyboard";
return false;
}
@@ -91,13 +87,13 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
void QQnxInputContext::showInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
m_virtualKeyboard.showKeyboard();
}
void QQnxInputContext::hideInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
m_virtualKeyboard.hideKeyboard();
}
@@ -118,7 +114,7 @@ void QQnxInputContext::keyboardHeightChanged()
void QQnxInputContext::keyboardVisibilityChanged(bool visible)
{
- qInputContextDebug() << "visible=" << visible;
+ qCDebug(lcQpaInputMethods) << "visible=" << visible;
if (m_inputPanelVisible != visible) {
m_inputPanelVisible = visible;
emitInputPanelVisibleChanged();
@@ -127,7 +123,7 @@ void QQnxInputContext::keyboardVisibilityChanged(bool visible)
void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
{
- qInputContextDebug() << "locale=" << locale;
+ qCDebug(lcQpaInputMethods) << "locale=" << locale;
if (m_inputPanelLocale != locale) {
m_inputPanelLocale = locale;
emitLocaleChanged();
@@ -136,7 +132,7 @@ void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
void QQnxInputContext::setFocusObject(QObject *object)
{
- qInputContextDebug() << "input item=" << object;
+ qCDebug(lcQpaInputMethods) << "input item=" << object;;
if (!inputMethodAccepted()) {
if (m_inputPanelVisible)
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index 310d5d4c8a..b308c956f2 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -49,6 +49,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qrhibackingstore_p.h>
#if !defined(QT_NO_OPENGL)
#include "qqnxglcontext.h"
@@ -64,14 +65,10 @@
#include <QtCore/QFile>
#include <errno.h>
-#if defined(QQNXINTEGRATION_DEBUG)
-#define qIntegrationDebug qDebug
-#else
-#define qIntegrationDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+// Q_LOGGING_CATEGORY(lcQpaQnx, "qt.qpa.qnx");
+
using namespace Qt::StringLiterals;
QQnxIntegration *QQnxIntegration::ms_instance;
@@ -144,7 +141,7 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
{
ms_instance = this;
m_options = parseOptions(paramList);
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Open connection to QNX composition manager
if (screen_create_context(&m_screenContext, getContextCapabilities(paramList))) {
@@ -221,7 +218,7 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
QQnxIntegration::~QQnxIntegration()
{
- qIntegrationDebug("platform plugin shutdown begin");
+ qCDebug(lcQpaQnx) << "Platform plugin shutdown begin";
delete m_nativeInterface;
#if QT_CONFIG(draganddrop)
@@ -278,12 +275,12 @@ QQnxIntegration::~QQnxIntegration()
ms_instance = nullptr;
- qIntegrationDebug("platform plugin shutdown end");
+ qCDebug(lcQpaQnx) << "Platform plugin shutdown end";
}
bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
switch (cap) {
case MultipleWindows:
case ForeignWindows:
@@ -314,7 +311,7 @@ QPlatformWindow *QQnxIntegration::createForeignWindow(QWindow *window, WId nativ
QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QSurface::SurfaceType surfaceType = window->surfaceType();
const bool needRootWindow = options() & RootWindow;
switch (surfaceType) {
@@ -332,14 +329,25 @@ QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const
{
- qIntegrationDebug();
- return new QQnxRasterBackingStore(window);
+ QSurface::SurfaceType surfaceType = window->surfaceType();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO << surfaceType;
+ switch (surfaceType) {
+ case QSurface::RasterSurface:
+ return new QQnxRasterBackingStore(window);
+#if !defined(QT_NO_OPENGL)
+ // Return a QRhiBackingStore for non-raster surface windows
+ case QSurface::OpenGLSurface:
+ return new QRhiBackingStore(window);
+#endif
+ default:
+ return nullptr;
+ }
}
#if !defined(QT_NO_OPENGL)
QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Get color channel sizes from window format
QSurfaceFormat format = context->format();
@@ -398,7 +406,7 @@ QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLCont
#if QT_CONFIG(qqnx_pps)
QPlatformInputContext *QQnxIntegration::inputContext() const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
if (m_qpaInputContext)
return m_qpaInputContext;
return m_inputContext;
@@ -407,7 +415,7 @@ QPlatformInputContext *QQnxIntegration::inputContext() const
void QQnxIntegration::moveToScreen(QWindow *window, int screen)
{
- qIntegrationDebug() << "w =" << window << ", s =" << screen;
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO << "w =" << window << ", s =" << screen;
// get platform window used by widget
QQnxWindow *platformWindow = static_cast<QQnxWindow *>(window->handle());
@@ -421,7 +429,7 @@ void QQnxIntegration::moveToScreen(QWindow *window, int screen)
QAbstractEventDispatcher *QQnxIntegration::createEventDispatcher() const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// We transfer ownersip of the event-dispatcher to QtCoreApplication
QAbstractEventDispatcher *eventDispatcher = m_eventDispatcher;
@@ -438,7 +446,7 @@ QPlatformNativeInterface *QQnxIntegration::nativeInterface() const
#if !defined(QT_NO_CLIPBOARD)
QPlatformClipboard *QQnxIntegration::clipboard() const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
#if QT_CONFIG(qqnx_pps)
if (!m_clipboard)
@@ -457,7 +465,7 @@ QPlatformDrag *QQnxIntegration::drag() const
QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
if ((hint == ShowIsFullScreen) && (m_options & FullScreenApplication))
return true;
@@ -471,7 +479,7 @@ QPlatformServices * QQnxIntegration::services() const
QWindow *QQnxIntegration::window(screen_window_t qnxWindow) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
return m_windowMapper.value(qnxWindow, 0);
@@ -479,7 +487,7 @@ QWindow *QQnxIntegration::window(screen_window_t qnxWindow) const
void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
m_windowMapper.insert(qnxWindow, window);
@@ -487,7 +495,7 @@ void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
void QQnxIntegration::removeWindow(screen_window_t qnxWindow)
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
m_windowMapper.remove(qnxWindow);
@@ -596,7 +604,7 @@ QList<screen_display_t *> QQnxIntegration::sortDisplays(screen_display_t *availa
void QQnxIntegration::createDisplays()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Query number of displays
int displayCount = 0;
int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT,
@@ -626,11 +634,12 @@ void QQnxIntegration::createDisplays()
Q_SCREEN_CHECKERROR(result, "Failed to query display attachment");
if (!isAttached) {
- qIntegrationDebug("Skipping non-attached display %d", i);
+ qCDebug(lcQpaQnx) << "Skipping non-attached display " << i;
continue;
}
- qIntegrationDebug("Creating screen for display %d", i);
+ qCDebug(lcQpaQnx) << "Creating screen for display " << i;
+
createDisplay(*orderedDisplays[i], /*isPrimary=*/false);
} // of displays iteration
}
@@ -664,7 +673,8 @@ void QQnxIntegration::removeDisplay(QQnxScreen *screen)
void QQnxIntegration::destroyDisplays()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
+
Q_FOREACH (QQnxScreen *screen, m_screens) {
QWindowSystemInterface::handleScreenRemoved(screen);
}
@@ -715,7 +725,7 @@ bool QQnxIntegration::supportsNavigatorEvents() const
#if QT_CONFIG(opengl)
void QQnxIntegration::createEglDisplay()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Initialize connection to EGL
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -729,7 +739,7 @@ void QQnxIntegration::createEglDisplay()
void QQnxIntegration::destroyEglDisplay()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Close connection to EGL
eglTerminate(m_eglDisplay);
diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h
index f126300aed..8a78d54ceb 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.h
+++ b/src/plugins/platforms/qnx/qqnxintegration.h
@@ -10,6 +10,7 @@
#include <QtCore/qmutex.h>
#include <screen/screen.h>
+#include <QtCore/QLoggingCategory>
#if QT_CONFIG(opengl)
#include <EGL/egl.h>
@@ -17,6 +18,9 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnx);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaGLContext);
+
class QQnxScreenEventThread;
class QQnxFileDialogHelper;
class QQnxNativeInterface;
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
index cee86a68a0..7580e560aa 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
@@ -10,11 +10,7 @@
#include <QGuiApplication>
#include <qpa/qwindowsysteminterface.h>
-#if defined(QQNXNAVIGATOREVENTHANDLER_DEBUG)
-#define qNavigatorEventHandlerDebug qDebug
-#else
-#define qNavigatorEventHandlerDebug QT_NO_QDEBUG_MACRO
-#endif
+Q_LOGGING_CATEGORY(lcQpaQnxNavigatorEvents, "qt.qpa.qnx.navigator.events");
QT_BEGIN_NAMESPACE
@@ -27,20 +23,20 @@ bool QQnxNavigatorEventHandler::handleOrientationCheck(int angle)
{
// reply to navigator that (any) orientation is acceptable
// TODO: check if top window flags prohibit orientation change
- qNavigatorEventHandlerDebug("angle=%d", angle);
+ qCDebug(lcQpaQnxNavigatorEvents, "angle=%d", angle);
return true;
}
void QQnxNavigatorEventHandler::handleOrientationChange(int angle)
{
// update screen geometry and reply to navigator that we're ready
- qNavigatorEventHandlerDebug("angle=%d", angle);
+ qCDebug(lcQpaQnxNavigatorEvents, "angle=%d", angle);
emit rotationChanged(angle);
}
void QQnxNavigatorEventHandler::handleSwipeDown()
{
- qNavigatorEventHandlerDebug();
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO;
Q_EMIT swipeDown();
}
@@ -48,25 +44,25 @@ void QQnxNavigatorEventHandler::handleSwipeDown()
void QQnxNavigatorEventHandler::handleExit()
{
// shutdown everything
- qNavigatorEventHandlerDebug();
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO;
QCoreApplication::quit();
}
void QQnxNavigatorEventHandler::handleWindowGroupActivated(const QByteArray &id)
{
- qNavigatorEventHandlerDebug() << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << id;
Q_EMIT windowGroupActivated(id);
}
void QQnxNavigatorEventHandler::handleWindowGroupDeactivated(const QByteArray &id)
{
- qNavigatorEventHandlerDebug() << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << id;
Q_EMIT windowGroupDeactivated(id);
}
void QQnxNavigatorEventHandler::handleWindowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
{
- qNavigatorEventHandlerDebug() << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << id;
Q_EMIT windowGroupStateChanged(id, state);
}
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
index 342b6c3ef6..826c9a0ff9 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
@@ -5,9 +5,12 @@
#define QQNXNAVIGATOREVENTHANDLER_H
#include <QObject>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxNavigatorEvents);
+
class QQnxNavigatorEventHandler : public QObject
{
Q_OBJECT
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
index 8024214e69..44c71dad52 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
@@ -17,14 +17,10 @@
#include <sys/types.h>
#include <sys/stat.h>
-#if defined(QQNXNAVIGATOREVENTNOTIFIER_DEBUG)
-#define qNavigatorEventNotifierDebug qDebug
-#else
-#define qNavigatorEventNotifierDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+// Q_LOGGING_CATEGORY(lcQpaQnxNavigatorEvents, "qt.qpa.qnx.navigator.events");
+
const char *QQnxNavigatorEventNotifier::navigatorControlPath = "/pps/services/navigator/control";
const size_t QQnxNavigatorEventNotifier::ppsBufferSize = 4096;
@@ -44,18 +40,18 @@ QQnxNavigatorEventNotifier::~QQnxNavigatorEventNotifier()
if (m_fd != -1)
close(m_fd);
- qNavigatorEventNotifierDebug("navigator event notifier stopped");
+ qCDebug(lcQpaQnxNavigatorEvents) << "Navigator event notifier stopped";
}
void QQnxNavigatorEventNotifier::start()
{
- qNavigatorEventNotifierDebug("navigator event notifier started");
+ qCDebug(lcQpaQnxNavigatorEvents) << "Navigator event notifier started";
// open connection to navigator
errno = 0;
m_fd = open(navigatorControlPath, O_RDWR);
if (m_fd == -1) {
- qNavigatorEventNotifierDebug("failed to open navigator pps: %s", strerror(errno));
+ qCDebug(lcQpaQnxNavigatorEvents, "Failed to open navigator pps: %s", strerror(errno));
return;
}
@@ -65,7 +61,7 @@ void QQnxNavigatorEventNotifier::start()
void QQnxNavigatorEventNotifier::parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id)
{
- qNavigatorEventNotifierDebug() << "data=" << ppsData;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "data=" << ppsData;
// tokenize pps data into lines
QList<QByteArray> lines = ppsData.split('\n');
@@ -79,7 +75,7 @@ void QQnxNavigatorEventNotifier::parsePPS(const QByteArray &ppsData, QByteArray
// tokenize current attribute
const QByteArray &attr = lines.at(i);
- qNavigatorEventNotifierDebug() << "attr=" << attr;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "attr=" << attr;
int firstColon = attr.indexOf(':');
if (firstColon == -1) {
@@ -96,8 +92,7 @@ void QQnxNavigatorEventNotifier::parsePPS(const QByteArray &ppsData, QByteArray
QByteArray key = attr.left(firstColon);
QByteArray value = attr.mid(secondColon + 1);
- qNavigatorEventNotifierDebug() << "key=" << key;
- qNavigatorEventNotifierDebug() << "val=" << value;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "key =" << key << "value =" << value;
// save attribute value
if (key == "msg")
@@ -124,7 +119,7 @@ void QQnxNavigatorEventNotifier::replyPPS(const QByteArray &res, const QByteArra
}
ppsData += "\n";
- qNavigatorEventNotifierDebug() << "reply=" << ppsData;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "reply=" << ppsData;
// send pps message to navigator
errno = 0;
@@ -135,7 +130,7 @@ void QQnxNavigatorEventNotifier::replyPPS(const QByteArray &res, const QByteArra
void QQnxNavigatorEventNotifier::handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id)
{
- qNavigatorEventNotifierDebug() << "msg=" << msg << ", dat=" << dat << ", id=" << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "msg=" << msg << ", dat=" << dat << ", id=" << id;
// check message type
if (msg == "orientationCheck") {
@@ -159,7 +154,7 @@ void QQnxNavigatorEventNotifier::handleMessage(const QByteArray &msg, const QByt
void QQnxNavigatorEventNotifier::readData()
{
- qNavigatorEventNotifierDebug("reading navigator data");
+ qCDebug(lcQpaQnxNavigatorEvents) << "Reading navigator data";
// allocate buffer for pps data
char buffer[ppsBufferSize];
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
index c945f3e98a..3a2fee0afb 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
@@ -8,12 +8,6 @@
#include <QByteArray>
#include <private/qcore_unix_p.h>
-#if defined(QQNXNAVIGATOR_DEBUG)
-#define qNavigatorDebug qDebug
-#else
-#define qNavigatorDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
const char *QQnxNavigatorPps::navigatorControlPath = "/pps/services/navigator/control";
@@ -45,7 +39,7 @@ bool QQnxNavigatorPps::openPpsConnection()
return false;
}
- qNavigatorDebug("successfully connected to Navigator. fd=%d", m_fd);
+ qCDebug(lcQpaQnxNavigator) << "successfully connected to Navigator. fd=" << m_fd;
return true;
}
@@ -67,7 +61,7 @@ bool QQnxNavigatorPps::sendPpsMessage(const QByteArray &message, const QByteArra
ppsMessage += "\n";
- qNavigatorDebug() << "sending PPS message:\n" << ppsMessage;
+ qCDebug(lcQpaQnxNavigator) << "sending PPS message:\n" << ppsMessage;
// send pps message to navigator
errno = 0;
@@ -89,7 +83,7 @@ bool QQnxNavigatorPps::sendPpsMessage(const QByteArray &message, const QByteArra
// ensure data is null terminated
buffer[bytes] = '\0';
- qNavigatorDebug() << "received PPS message:\n" << buffer;
+ qCDebug(lcQpaQnxNavigator) << "received PPS message:\n" << buffer;
// process received message
QByteArray ppsData(buffer);
@@ -108,7 +102,7 @@ bool QQnxNavigatorPps::sendPpsMessage(const QByteArray &message, const QByteArra
void QQnxNavigatorPps::parsePPS(const QByteArray &ppsData, QHash<QByteArray, QByteArray> &messageFields)
{
- qNavigatorDebug() << "data=" << ppsData;
+ qCDebug(lcQpaQnxNavigator) << "data=" << ppsData;
// tokenize pps data into lines
QList<QByteArray> lines = ppsData.split('\n');
@@ -123,7 +117,7 @@ void QQnxNavigatorPps::parsePPS(const QByteArray &ppsData, QHash<QByteArray, QBy
// tokenize current attribute
const QByteArray &attr = lines.at(i);
- qNavigatorDebug() << "attr=" << attr;
+ qCDebug(lcQpaQnxNavigator) << "attr=" << attr;
int firstColon = attr.indexOf(':');
if (firstColon == -1) {
@@ -140,8 +134,7 @@ void QQnxNavigatorPps::parsePPS(const QByteArray &ppsData, QHash<QByteArray, QBy
QByteArray key = attr.left(firstColon);
QByteArray value = attr.mid(secondColon + 1);
- qNavigatorDebug() << "key=" << key;
- qNavigatorDebug() << "val=" << value;
+ qCDebug(lcQpaQnxNavigator) << "key=" << key << "value=" << value;
messageFields[key] = value;
}
}
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.h b/src/plugins/platforms/qnx/qqnxnavigatorpps.h
index cbe0f99621..889b9f62eb 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.h
@@ -5,9 +5,12 @@
#define QQNXNAVIGATORPPS_H
#include "qqnxabstractnavigator.h"
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxNavigator);
+
template <typename K, typename V> class QHash;
class QQnxNavigatorPps : public QQnxAbstractNavigator
diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
index cf80e44f84..b94c056a79 100644
--- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
@@ -10,12 +10,6 @@
#include <errno.h>
-#if defined(QQNXRASTERBACKINGSTORE_DEBUG)
-#define qRasterBackingStoreDebug qDebug
-#else
-#define qRasterBackingStoreDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
QQnxRasterBackingStore::QQnxRasterBackingStore(QWindow *window)
@@ -23,14 +17,14 @@ QQnxRasterBackingStore::QQnxRasterBackingStore(QWindow *window)
m_needsPosting(false),
m_scrolled(false)
{
- qRasterBackingStoreDebug() << "w =" << window;
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window;
m_window = window;
}
QQnxRasterBackingStore::~QQnxRasterBackingStore()
{
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
}
QPaintDevice *QQnxRasterBackingStore::paintDevice()
@@ -45,7 +39,7 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion &region, const
{
Q_UNUSED(offset);
- qRasterBackingStoreDebug() << "w =" << this->window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << this->window();
// Sometimes this method is called even though there is nothing to be
// flushed (posted in "screen" parlance), for instance, after an expose
@@ -67,7 +61,7 @@ void QQnxRasterBackingStore::resize(const QSize &size, const QRegion &staticCont
{
Q_UNUSED(size);
Q_UNUSED(staticContents);
- qRasterBackingStoreDebug() << "w =" << window() << ", s =" << size;
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window() << ", s =" << size;
// NOTE: defer resizing window buffers until next paint as
// resize() can be called multiple times before a paint occurs
@@ -75,7 +69,7 @@ void QQnxRasterBackingStore::resize(const QSize &size, const QRegion &staticCont
bool QQnxRasterBackingStore::scroll(const QRegion &area, int dx, int dy)
{
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
m_needsPosting = true;
@@ -91,7 +85,7 @@ void QQnxRasterBackingStore::beginPaint(const QRegion &region)
{
Q_UNUSED(region);
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
m_needsPosting = true;
platformWindow()->adjustBufferSize();
@@ -119,7 +113,7 @@ void QQnxRasterBackingStore::beginPaint(const QRegion &region)
void QQnxRasterBackingStore::endPaint()
{
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
}
QQnxRasterWindow *QQnxRasterBackingStore::platformWindow() const
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
index fb7a1d3fd3..303c9e7c06 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
@@ -10,12 +10,6 @@
#include <errno.h>
-#if defined(QQNXRASTERWINDOW_DEBUG)
-#define qRasterWindowDebug qDebug
-#else
-#define qRasterWindowDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context, bool needRootWindow) :
@@ -61,7 +55,7 @@ void QQnxRasterWindow::post(const QRegion &dirty)
// Check if render buffer exists and something was rendered
if (m_currentBufferIndex != -1 && !dirty.isEmpty()) {
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
QQnxBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
// Copy unmodified region from old render buffer to new render buffer;
@@ -94,14 +88,14 @@ void QQnxRasterWindow::post(const QRegion &dirty)
void QQnxRasterWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
{
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
blitPreviousToCurrent(region, dx, dy, flush);
m_scrolled += region;
}
QQnxBuffer &QQnxRasterWindow::renderBuffer()
{
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
// Check if render buffer is invalid
if (m_currentBufferIndex == -1) {
@@ -162,7 +156,7 @@ void QQnxRasterWindow::resetBuffers()
void QQnxRasterWindow::blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush)
{
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
// Abort if previous buffer is invalid or if nothing to copy
if (m_previousBufferIndex == -1 || region.isEmpty())
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index 9d689da991..f2c3b3847d 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -15,12 +15,6 @@
#include <errno.h>
-#if defined(QQNXSCREEN_DEBUG)
-#define qScreenDebug qDebug
-#else
-#define qScreenDebug QT_NO_QDEBUG_MACRO
-#endif
-
#if defined(QQNX_PHYSICAL_SCREEN_WIDTH) && QQNX_PHYSICAL_SCREEN_WIDTH > 0 \
&& defined(QQNX_PHYSICAL_SCREEN_HEIGHT) && QQNX_PHYSICAL_SCREEN_HEIGHT > 0
#define QQNX_PHYSICAL_SCREEN_SIZE_DEFINED
@@ -34,6 +28,8 @@ static const int MAX_UNDERLAY_ZORDER = -1;
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen");
+
static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
int val[2];
@@ -46,9 +42,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
if (val[0] > 0 && val[1] > 0)
return QSize(val[0], val[1]);
- qScreenDebug("QQnxScreen: screen_get_display_property_iv() reported an invalid "
- "physical screen size (%dx%d). Falling back to QQNX_PHYSICAL_SCREEN_SIZE "
- "environment variable.", val[0], val[1]);
+ qCDebug(lcQpaScreen, "QQnxScreen: screen_get_display_property_iv() reported an invalid "
+ "physical screen size (%dx%d). Falling back to QQNX_PHYSICAL_SCREEN_SIZE "
+ "environment variable.", val[0], val[1]);
const QString envPhySizeStr = qgetenv("QQNX_PHYSICAL_SCREEN_SIZE");
if (!envPhySizeStr.isEmpty()) {
@@ -90,7 +86,7 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display,
m_coverWindow(0),
m_cursor(new QQnxCursor())
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
// Cache initial orientation of this display
int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION,
&m_initialRotation);
@@ -127,7 +123,7 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display,
QQnxScreen::~QQnxScreen()
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->setScreen(0);
@@ -236,7 +232,7 @@ QPixmap QQnxScreen::grabWindow(WId window, int x, int y, int width, int height)
static int defaultDepth()
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
static int defaultDepth = 0;
if (defaultDepth == 0) {
// check if display depth was specified in environment variable;
@@ -250,7 +246,7 @@ static int defaultDepth()
QRect QQnxScreen::availableGeometry() const
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
// available geometry = total geometry - keyboard
return QRect(m_currentGeometry.x(), m_currentGeometry.y(),
m_currentGeometry.width(), m_currentGeometry.height() - m_keyboardHeight);
@@ -270,12 +266,12 @@ qreal QQnxScreen::refreshRate() const
qWarning("QQnxScreen: Failed to query screen mode. Using default value of 60Hz");
return 60.0;
}
- qScreenDebug("screen mode:\n"
- " width = %u\n"
- " height = %u\n"
- " refresh = %u\n"
- " interlaced = %u",
- uint(displayMode.width), uint(displayMode.height), uint(displayMode.refresh), uint(displayMode.interlaced));
+ qCDebug(lcQpaScreen, "screen mode:\n"
+ " width = %u\n"
+ " height = %u\n"
+ " refresh = %u\n"
+ " interlaced = %u",
+ uint(displayMode.width), uint(displayMode.height), uint(displayMode.refresh), uint(displayMode.interlaced));
return static_cast<qreal>(displayMode.refresh);
}
@@ -309,7 +305,7 @@ Qt::ScreenOrientation QQnxScreen::orientation() const
else
orient = Qt::InvertedLandscapeOrientation;
}
- qScreenDebug() << "orientation =" << orient;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Orientation =" << orient;
return orient;
}
@@ -333,7 +329,7 @@ static bool isOrthogonal(int angle1, int angle2)
void QQnxScreen::setRotation(int rotation)
{
- qScreenDebug("orientation = %d", rotation);
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "orientation =" << rotation;
// Check if rotation changed
// We only want to rotate if we are the primary screen
if (m_currentRotation != rotation && isPrimaryScreen()) {
@@ -354,7 +350,7 @@ void QQnxScreen::setRotation(int rotation)
// Resize root window if we've rotated 90 or 270 from previous orientation
if (isOrthogonal(m_currentRotation, rotation)) {
- qScreenDebug() << "resize, size =" << m_currentGeometry.size();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "resize, size =" << m_currentGeometry.size();
if (rootWindow())
rootWindow()->setGeometry(QRect(QPoint(0,0), m_currentGeometry.size()));
@@ -501,7 +497,7 @@ QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle) const
void QQnxScreen::addWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (m_childWindows.contains(window))
return;
@@ -524,7 +520,7 @@ void QQnxScreen::addWindow(QQnxWindow *window)
void QQnxScreen::removeWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (window != m_coverWindow) {
const int numWindowsRemoved = m_childWindows.removeAll(window);
@@ -539,7 +535,7 @@ void QQnxScreen::removeWindow(QQnxWindow *window)
void QQnxScreen::raiseWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (window != m_coverWindow) {
removeWindow(window);
@@ -549,7 +545,7 @@ void QQnxScreen::raiseWindow(QQnxWindow *window)
void QQnxScreen::lowerWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (window != m_coverWindow) {
removeWindow(window);
@@ -559,7 +555,7 @@ void QQnxScreen::lowerWindow(QQnxWindow *window)
void QQnxScreen::updateHierarchy()
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
QList<QQnxWindow*>::const_iterator it;
int result;
@@ -709,7 +705,7 @@ void QQnxScreen::windowClosed(void *window)
void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
if (!rootWindow() || id != rootWindow()->groupName())
return;
@@ -724,7 +720,7 @@ void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState s
void QQnxScreen::activateWindowGroup(const QByteArray &id)
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
if (!rootWindow() || id != rootWindow()->groupName())
return;
@@ -743,7 +739,7 @@ void QQnxScreen::activateWindowGroup(const QByteArray &id)
void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
if (!rootWindow() || id != rootWindow()->groupName())
return;
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index f988b42ab4..17b282bdc1 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -30,6 +30,10 @@ const int SCREEN_PROPERTY_SYM = SCREEN_PROPERTY_KEY_SYM;
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenEvents);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenBuffer);
+
class QQnxWindow;
class QQnxScreen : public QObject, public QPlatformScreen
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index e93a38f62c..6d923bc3a8 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -19,11 +19,7 @@
#include <errno.h>
#include <sys/keycodes.h>
-#if defined(QQNXSCREENEVENT_DEBUG)
-#define qScreenEventDebug qDebug
-#else
-#define qScreenEventDebug QT_NO_QDEBUG_MACRO
-#endif
+Q_LOGGING_CATEGORY(lcQpaScreenEvents, "qt.qpa.screen.events");
static int qtKey(int virtualKey, QChar::Category category)
{
@@ -197,7 +193,7 @@ bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
default:
// event ignored
- qScreenEventDebug("unknown event %d", qnxType);
+ qCDebug(lcQpaScreenEvents) << Q_FUNC_INFO << "Unknown event" << qnxType;
return false;
}
@@ -235,7 +231,7 @@ void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifie
QWindowSystemInterface::handleExtendedKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod,
scan, virtualKey, modifiers, keyStr, flags & KEY_REPEAT);
- qScreenEventDebug() << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
+ qCDebug(lcQpaScreenEvents) << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
}
void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread)
@@ -364,12 +360,12 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
- qScreenEventDebug() << "Qt leave, w=" << wOld;
+ qCDebug(lcQpaScreenEvents) << "Qt leave, w=" << wOld;
}
if (w) {
QWindowSystemInterface::handleEnterEvent(w);
- qScreenEventDebug() << "Qt enter, w=" << w;
+ qCDebug(lcQpaScreenEvents) << "Qt enter, w=" << w;
}
}
@@ -412,8 +408,8 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice, localPoint,
globalPoint, buttons, Qt::NoButton,
QEvent::MouseMove);
- qScreenEventDebug() << "Qt mouse move, w=" << w << ", (" << localPoint.x() << ","
- << localPoint.y() << "), b=" << static_cast<int>(buttons);
+ qCDebug(lcQpaScreenEvents) << "Qt mouse move, w=" << w << ", (" << localPoint.x() << ","
+ << localPoint.y() << "), b=" << static_cast<int>(buttons);
}
if (m_lastButtonState != buttons) {
@@ -428,8 +424,8 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
localPoint, globalPoint, buttons,
button, QEvent::MouseButtonRelease);
- qScreenEventDebug() << "Qt mouse release, w=" << w << ", (" << localPoint.x()
- << "," << localPoint.y() << "), b=" << button;
+ qCDebug(lcQpaScreenEvents) << "Qt mouse release, w=" << w << ", (" << localPoint.x()
+ << "," << localPoint.y() << "), b=" << button;
}
}
@@ -443,8 +439,8 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
localPoint, globalPoint, buttons,
button, QEvent::MouseButtonPress);
- qScreenEventDebug() << "Qt mouse press, w=" << w << ", (" << localPoint.x()
- << "," << localPoint.y() << "), b=" << button;
+ qCDebug(lcQpaScreenEvents) << "Qt mouse press, w=" << w << ", (" << localPoint.x()
+ << "," << localPoint.y() << "), b=" << button;
}
}
}
@@ -455,7 +451,7 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QPoint angleDelta(0, wheelDelta);
QWindowSystemInterface::handleWheelEvent(w, timestamp, m_mouseDevice, localPoint,
globalPoint, QPoint(), angleDelta);
- qScreenEventDebug() << "Qt wheel, w=" << w << ", (" << localPoint.x() << ","
+ qCDebug(lcQpaScreenEvents) << "Qt wheel, w=" << w << ", (" << localPoint.x() << ","
<< localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
}
}
@@ -513,12 +509,12 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
- qScreenEventDebug() << "Qt leave, w=" << wOld;
+ qCDebug(lcQpaScreenEvents) << "Qt leave, w=" << wOld;
}
if (w) {
QWindowSystemInterface::handleEnterEvent(w);
- qScreenEventDebug() << "Qt enter, w=" << w;
+ qCDebug(lcQpaScreenEvents) << "Qt enter, w=" << w;
}
}
m_lastMouseWindow = qnxWindow;
@@ -585,9 +581,9 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
// inject event into Qt
QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList);
- qScreenEventDebug() << "Qt touch, w =" << w
- << ", p=" << m_touchPoints[touchId].area.topLeft()
- << ", t=" << type;
+ qCDebug(lcQpaScreenEvents) << "Qt touch, w =" << w
+ << ", p=" << m_touchPoints[touchId].area.topLeft()
+ << ", t=" << type;
}
}
}
@@ -631,7 +627,8 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
return;
}
- qScreenEventDebug() << "display attachment is now:" << isAttached;
+ qCDebug(lcQpaScreenEvents) << "display attachment is now:" << isAttached;
+
QQnxScreen *screen = m_qnxIntegration->screenForNative(nativeDisplay);
if (!screen) {
@@ -641,7 +638,7 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
if (val[0] == 0 && val[1] == 0) //If screen size is invalid, wait for the next event
return;
- qScreenEventDebug("creating new QQnxScreen for newly attached display");
+ qCDebug(lcQpaScreenEvents) << "Creating new QQnxScreen for newly attached display";
m_qnxIntegration->createDisplay(nativeDisplay, false /* not primary, we assume */);
}
} else if (!isAttached) {
@@ -654,7 +651,7 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
if (!screen->isPrimaryScreen()) {
// libscreen display is deactivated, let's remove the QQnxScreen / QScreen
- qScreenEventDebug("removing display");
+ qCDebug(lcQpaScreenEvents) << "Removing display";
m_qnxIntegration->removeDisplay(screen);
}
}
@@ -691,7 +688,7 @@ void QQnxScreenEventHandler::handlePropertyEvent(screen_event_t event)
break;
default:
// event ignored
- qScreenEventDebug() << "Ignore property event for property: " << property;
+ qCDebug(lcQpaScreenEvents) << "Ignore property event for property: " << property;
}
}
@@ -734,7 +731,7 @@ void QQnxScreenEventHandler::handleGeometryPropertyEvent(screen_window_t window)
QWindowSystemInterface::handleGeometryChange(qtWindow, rect);
}
- qScreenEventDebug() << qtWindow << "moved to" << rect;
+ qCDebug(lcQpaScreenEvents) << qtWindow << "moved to" << rect;
}
void QQnxScreenEventHandler::timerEvent(QTimerEvent *event)
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
index d27186af9e..ba3579aaf7 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
@@ -5,11 +5,14 @@
#define QQNXSCREENEVENTHANDLER_H
#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/QLoggingCategory>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenEvents);
+
class QQnxIntegration;
class QQnxScreenEventFilter;
class QQnxScreenEventThread;
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
index 69997e4ba0..6b4ffc3962 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
@@ -14,12 +14,6 @@
#include <cctype>
-#if defined(QQNXSCREENEVENTTHREAD_DEBUG)
-#define qScreenEventThreadDebug qDebug
-#else
-#define qScreenEventThreadDebug QT_NO_QDEBUG_MACRO
-#endif
-
static const int c_screenCode = _PULSE_CODE_MINAVAIL + 0;
static const int c_armCode = _PULSE_CODE_MINAVAIL + 1;
static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2;
@@ -74,7 +68,7 @@ QQnxScreenEventThread::~QQnxScreenEventThread()
void QQnxScreenEventThread::run()
{
- qScreenEventThreadDebug("screen event thread started");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread started";
while (1) {
struct _pulse msg;
@@ -90,7 +84,7 @@ void QQnxScreenEventThread::run()
qWarning() << "MsgReceive error" << strerror(errno);
}
- qScreenEventThreadDebug("screen event thread stopped");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread stopped";
}
void QQnxScreenEventThread::armEventsPending(int count)
@@ -134,10 +128,10 @@ void QQnxScreenEventThread::shutdown()
{
MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_quitCode, 0);
- qScreenEventThreadDebug("screen event thread shutdown begin");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread shutdown begin";
// block until thread terminates
wait();
- qScreenEventThreadDebug("screen event thread shutdown end");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread shutdown end";
}
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
index b4650de315..5eceacef95 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
@@ -18,14 +18,10 @@
#include <sys/types.h>
#include <unistd.h>
-#if defined(QQNXVIRTUALKEYBOARD_DEBUG)
-#define qVirtualKeyboardDebug qDebug
-#else
-#define qVirtualKeyboardDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaQnxVirtualKeyboard, "qt.qpa.qnx.virtualkeyboard");
+
const char *QQnxVirtualKeyboardPps::ms_PPSPath = "/pps/services/input/control";
const size_t QQnxVirtualKeyboardPps::ms_bufferSize = 2048;
@@ -45,7 +41,7 @@ QQnxVirtualKeyboardPps::~QQnxVirtualKeyboardPps()
void QQnxVirtualKeyboardPps::start()
{
- qVirtualKeyboardDebug("starting keyboard event processing");
+ qCDebug(lcQpaQnxVirtualKeyboard) << "Starting keyboard event processing";
if (!connect())
return;
}
@@ -90,8 +86,8 @@ bool QQnxVirtualKeyboardPps::connect()
m_fd = ::open(ms_PPSPath, O_RDWR);
if (m_fd == -1)
{
- qVirtualKeyboardDebug() << "Unable to open" << ms_PPSPath
- << ':' << strerror(errno);
+ qCDebug(lcQpaQnxVirtualKeyboard) << "Unable to open" << ms_PPSPath
+ << ':' << strerror(errno);
close();
return false;
}
@@ -128,7 +124,7 @@ void QQnxVirtualKeyboardPps::ppsDataReady()
{
qint64 nread = qt_safe_read(m_fd, m_buffer, ms_bufferSize - 1);
- qVirtualKeyboardDebug("keyboardMessage size: %lld", nread);
+ qCDebug(lcQpaQnxVirtualKeyboard, "keyboardMessage size: %lld", nread);
if (nread < 0){
connect(); // reconnect
return;
@@ -167,7 +163,7 @@ void QQnxVirtualKeyboardPps::ppsDataReady()
else if (strcmp(value, "info") == 0)
handleKeyboardInfoMessage();
else if (strcmp(value, "connect") == 0)
- qVirtualKeyboardDebug("Unhandled command 'connect'");
+ qCDebug(lcQpaQnxVirtualKeyboard, "Unhandled command 'connect'");
else
qCritical("QQnxVirtualKeyboard: Unexpected keyboard PPS msg value: %s", value ? value : "[null]");
} else if (pps_decoder_get_string(m_decoder, "res", &value) == PPS_DECODER_OK) {
@@ -194,12 +190,12 @@ void QQnxVirtualKeyboardPps::handleKeyboardInfoMessage()
}
setHeight(newHeight);
- qVirtualKeyboardDebug("size=%d", newHeight);
+ qCDebug(lcQpaQnxVirtualKeyboard, "size=%d", newHeight);
}
bool QQnxVirtualKeyboardPps::showKeyboard()
{
- qVirtualKeyboardDebug();
+ qCDebug(lcQpaQnxVirtualKeyboard) << Q_FUNC_INFO;
if (!prepareToSend())
return false;
@@ -221,7 +217,7 @@ bool QQnxVirtualKeyboardPps::showKeyboard()
bool QQnxVirtualKeyboardPps::hideKeyboard()
{
- qVirtualKeyboardDebug();
+ qCDebug(lcQpaQnxVirtualKeyboard) << Q_FUNC_INFO;
if (!prepareToSend())
return false;
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
index 88af284db3..8f1d390760 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
@@ -5,11 +5,13 @@
#define VIRTUALKEYBOARDPPS_H
#include "qqnxabstractvirtualkeyboard.h"
+#include <QtCore/QLoggingCategory>
#include <sys/pps.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxVirtualKeyboard);
class QSocketNotifier;
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index eed45227f6..3384932a8b 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -21,14 +21,10 @@
#include <errno.h>
-#if defined(QQNXWINDOW_DEBUG)
-#define qWindowDebug qDebug
-#else
-#define qWindowDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+
#define DECLARE_DEBUG_VAR(variable) \
static bool debug_ ## variable() \
{ static bool value = qgetenv("QNX_SCREEN_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
@@ -125,7 +121,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
m_windowState(Qt::WindowNoState),
m_firstActivateHandled(false)
{
- qWindowDebug() << "window =" << window << ", size =" << window->size();
+ qCDebug(lcQpaWindow) << "window =" << window << ", size =" << window->size();
QQnxScreen *platformScreen = static_cast<QQnxScreen *>(window->screen()->handle());
@@ -195,13 +191,13 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
bool ok = false;
int pipeline = pipelineValue.toInt(&ok);
if (ok) {
- qWindowDebug() << "Set pipeline value to" << pipeline;
+ qCDebug(lcQpaWindow) << "Set pipeline value to" << pipeline;
Q_SCREEN_CHECKERROR(
screen_set_window_property_iv(m_window, SCREEN_PROPERTY_PIPELINE, &pipeline),
"Failed to set window pipeline");
} else {
- qWindowDebug() << "Invalid pipeline value:" << pipelineValue;
+ qCDebug(lcQpaWindow) << "Invalid pipeline value:" << pipelineValue;
}
}
@@ -231,7 +227,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
if (debug > 0) {
Q_SCREEN_CHECKERROR(screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_DEBUG, &debug),
"Could not set SCREEN_PROPERTY_DEBUG");
- qWindowDebug() << "window SCREEN_PROPERTY_DEBUG= " << debug;
+ qCDebug(lcQpaWindow) << "window SCREEN_PROPERTY_DEBUG= " << debug;
}
}
@@ -248,7 +244,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_
, m_parentGroupName(256, 0)
, m_isTopLevel(false)
{
- qWindowDebug() << "window =" << window << ", size =" << window->size();
+ qCDebug(lcQpaWindow) << "window =" << window << ", size =" << window->size();
collectWindowGroup();
@@ -269,7 +265,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_
QQnxWindow::~QQnxWindow()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << "window =" << window();
// Qt should have already deleted the children before deleting the parent.
Q_ASSERT(m_childWindows.size() == 0);
@@ -305,9 +301,9 @@ void QQnxWindow::setGeometry(const QRect &rect)
void QQnxWindow::setGeometryHelper(const QRect &rect)
{
- qWindowDebug() << "window =" << window()
- << ", (" << rect.x() << "," << rect.y()
- << "," << rect.width() << "," << rect.height() << ")";
+ qCDebug(lcQpaWindow) << "window =" << window()
+ << ", (" << rect.x() << "," << rect.y()
+ << "," << rect.width() << "," << rect.height() << ")";
// Call base class method
QPlatformWindow::setGeometry(rect);
@@ -335,7 +331,7 @@ void QQnxWindow::setGeometryHelper(const QRect &rect)
void QQnxWindow::setVisible(bool visible)
{
- qWindowDebug() << "window =" << window() << "visible =" << visible;
+ qCDebug(lcQpaWindow) << "window =" << window() << "visible =" << visible;
if (m_visible == visible || window()->type() == Qt::Desktop)
return;
@@ -374,7 +370,7 @@ void QQnxWindow::setVisible(bool visible)
void QQnxWindow::updateVisibility(bool parentVisible)
{
- qWindowDebug() << "parentVisible =" << parentVisible << "window =" << window();
+ qCDebug(lcQpaWindow) << "parentVisible =" << parentVisible << "window =" << window();
// Set window visibility
int val = (m_visible && parentVisible) ? 1 : 0;
Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val),
@@ -386,7 +382,7 @@ void QQnxWindow::updateVisibility(bool parentVisible)
void QQnxWindow::setOpacity(qreal level)
{
- qWindowDebug() << "window =" << window() << "opacity =" << level;
+ qCDebug(lcQpaWindow) << "window =" << window() << "opacity =" << level;
// Set window global alpha
int val = (int)(level * 255);
Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val),
@@ -397,7 +393,7 @@ void QQnxWindow::setOpacity(qreal level)
void QQnxWindow::setExposed(bool exposed)
{
- qWindowDebug() << "window =" << window() << "expose =" << exposed;
+ qCDebug(lcQpaWindow) << "window =" << window() << "expose =" << exposed;
if (m_exposed != exposed) {
m_exposed = exposed;
@@ -412,7 +408,7 @@ bool QQnxWindow::isExposed() const
void QQnxWindow::setBufferSize(const QSize &size)
{
- qWindowDebug() << "window =" << window() << "size =" << size;
+ qCDebug(lcQpaWindow) << "window =" << window() << "size =" << size;
// libscreen fails when creating empty buffers
const QSize nonEmptySize = size.isEmpty() ? QSize(1, 1) : size;
@@ -479,7 +475,7 @@ void QQnxWindow::setBufferSize(const QSize &size)
void QQnxWindow::setScreen(QQnxScreen *platformScreen)
{
- qWindowDebug() << "window =" << window() << "platformScreen =" << platformScreen;
+ qCDebug(lcQpaWindow) << "window =" << window() << "platformScreen =" << platformScreen;
if (platformScreen == 0) { // The screen has been destroyed
m_screen = 0;
@@ -493,7 +489,7 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
return;
if (m_screen) {
- qWindowDebug("Moving window to different screen");
+ qCDebug(lcQpaWindow) << "Moving window to different screen";
m_screen->removeWindow(this);
if ((QQnxIntegration::instance()->options() & QQnxIntegration::RootWindow)) {
@@ -524,7 +520,7 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
void QQnxWindow::removeFromParent()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window =" << window();
// Remove from old Hierarchy position
if (m_parentWindow) {
if (Q_UNLIKELY(!m_parentWindow->m_childWindows.removeAll(this)))
@@ -538,7 +534,7 @@ void QQnxWindow::removeFromParent()
void QQnxWindow::setParent(const QPlatformWindow *window)
{
- qWindowDebug() << "window =" << this->window() << "platformWindow =" << window;
+ qCDebug(lcQpaWindow) << "window =" << this->window() << "platformWindow =" << window;
// Cast away the const, we need to modify the hierarchy.
QQnxWindow* const newParent = static_cast<QQnxWindow*>(const_cast<QPlatformWindow*>(window));
@@ -570,7 +566,7 @@ void QQnxWindow::setParent(const QPlatformWindow *window)
void QQnxWindow::raise()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window =" << window();
if (m_parentWindow) {
m_parentWindow->m_childWindows.removeAll(this);
@@ -584,7 +580,7 @@ void QQnxWindow::raise()
void QQnxWindow::lower()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window =" << window();
if (m_parentWindow) {
m_parentWindow->m_childWindows.removeAll(this);
@@ -698,7 +694,7 @@ void QQnxWindow::setFocus(screen_window_t newFocusWindow)
void QQnxWindow::setWindowState(Qt::WindowStates state)
{
- qWindowDebug() << "state =" << state;
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "state =" << state;
// Prevent two calls with Qt::WindowFullScreen from changing m_unmaximizedGeometry
if (m_windowState == state)
@@ -713,7 +709,7 @@ void QQnxWindow::setWindowState(Qt::WindowStates state)
void QQnxWindow::propagateSizeHints()
{
// nothing to do; silence base class warning
- qWindowDebug("ignored");
+ // qWindowDebug("ignored");
}
QPlatformScreen *QQnxWindow::screen() const
@@ -742,7 +738,7 @@ void QQnxWindow::minimize()
void QQnxWindow::setRotation(int rotation)
{
- qWindowDebug() << "angle =" << rotation;
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "angle =" << rotation;
Q_SCREEN_CHECKERROR(
screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation),
"Failed to set window rotation");
@@ -818,7 +814,7 @@ void QQnxWindow::joinWindowGroup(const QByteArray &groupName)
{
bool changed = false;
- qWindowDebug() << "group:" << groupName;
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "group:" << groupName;
// screen has this annoying habit of generating a CLOSE/CREATE when the owner context of
// the parent group moves a foreign window to another group that it also owns. The
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index d302f22415..013ea342e4 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -8,6 +8,7 @@
#include "qqnxabstractcover.h"
#include <QtCore/QScopedPointer>
+#include <QtCore/QLoggingCategory>
#if !defined(QT_NO_OPENGL)
#include <EGL/egl.h>
@@ -17,6 +18,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow);
+
// all surfaces double buffered
#define MAX_BUFFER_COUNT 2
diff --git a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
index 719e5c45e6..406487f1e9 100644
--- a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
+++ b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
@@ -6,7 +6,7 @@ qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
qt_internal_add_plugin(QVkKhrDisplayIntegrationPlugin
OUTPUT_NAME qvkkhrdisplay
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vkkhrdisplay
+ DEFAULT_IF "vkkhrdisplay" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qvkkhrdisplayintegration.cpp qvkkhrdisplayintegration.h
diff --git a/src/plugins/platforms/vnc/CMakeLists.txt b/src/plugins/platforms/vnc/CMakeLists.txt
index 25cb399bd0..34370807ae 100644
--- a/src/plugins/platforms/vnc/CMakeLists.txt
+++ b/src/plugins/platforms/vnc/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QVncIntegrationPlugin
OUTPUT_NAME qvnc
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vnc
+ DEFAULT_IF "vnc" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qvnc.cpp qvnc_p.h
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index 185b921a4f..775946aaf9 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -7,9 +7,8 @@
qt_internal_add_plugin(QWasmIntegrationPlugin
OUTPUT_NAME qwasm
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES wasm
+ DEFAULT_IF "wasm" IN_LIST QT_QPA_PLATFORMS
PLUGIN_TYPE platforms
- STATIC
SOURCES
main.cpp
qwasmaccessibility.cpp qwasmaccessibility.h
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
index bbc0ac68ab..8027dd8fa9 100644
--- a/src/plugins/platforms/wasm/qtloader.js
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -23,7 +23,8 @@
* - fontDpi: number
* Specifies font DPI for the instance
* - onLoaded: () => void
- * Called when the module has loaded.
+ * Called when the module has loaded, at the point in time where any loading placeholder
+ * should be hidden and the application window should be shown.
* - entryFunction: (emscriptenConfig: object) => Promise<EmscriptenModule>
* Qt always uses emscripten's MODULARIZE option. This is the MODULARIZE entry function.
* - module: Promise<WebAssembly.Module>
@@ -172,9 +173,14 @@ async function qtLoad(config)
config.preRun = [];
config.preRun.push(qtPreRun);
+ const originalOnRuntimeInitialized = config.onRuntimeInitialized;
+ config.onRuntimeInitialized = () => {
+ originalOnRuntimeInitialized?.();
+ config.qt.onLoaded?.();
+ }
+
const originalLocateFile = config.locateFile;
- config.locateFile = filename =>
- {
+ config.locateFile = filename => {
const originalLocatedFilename = originalLocateFile ? originalLocateFile(filename) : filename;
if (originalLocatedFilename.startsWith('libQt6'))
return `${config.qt.qtdir}/lib/${originalLocatedFilename}`;
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
index ddf8140c48..0490b2bfe0 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -361,10 +361,14 @@ QList<QWasmWindow *> QWasmScreen::allWindows()
{
QList<QWasmWindow *> windows;
for (auto *child : childStack()) {
- QWindowList list = child->window()->findChildren<QWindow *>(Qt::FindChildrenRecursively);
- std::transform(
- list.begin(), list.end(), std::back_inserter(windows),
- [](const QWindow *window) { return static_cast<QWasmWindow *>(window->handle()); });
+ const QWindowList list = child->window()->findChildren<QWindow *>(Qt::FindChildrenRecursively);
+ for (auto child : list) {
+ auto handle = child->handle();
+ if (handle) {
+ auto wnd = static_cast<QWasmWindow *>(handle);
+ windows.push_back(wnd);
+ }
+ }
windows.push_back(child);
}
return windows;
diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt
index 4b92317978..8cd84e208b 100644
--- a/src/plugins/platforms/windows/CMakeLists.txt
+++ b/src/plugins/platforms/windows/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QWindowsIntegrationPlugin
OUTPUT_NAME qwindows
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES windows
+ DEFAULT_IF "windows" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qtwindowsglobal.h
diff --git a/src/plugins/platforms/windows/qwindowsapplication.cpp b/src/plugins/platforms/windows/qwindowsapplication.cpp
index 60cbf1f7ba..42e34ac99f 100644
--- a/src/plugins/platforms/windows/qwindowsapplication.cpp
+++ b/src/plugins/platforms/windows/qwindowsapplication.cpp
@@ -72,11 +72,6 @@ bool QWindowsApplication::setWinTabEnabled(bool enabled)
return enabled ? ctx->initTablet() : ctx->disposeTablet();
}
-bool QWindowsApplication::isDarkMode() const
-{
- return QWindowsContext::isDarkMode();
-}
-
QWindowsApplication::DarkModeHandling QWindowsApplication::darkModeHandling() const
{
return m_darkModeHandling;
diff --git a/src/plugins/platforms/windows/qwindowsapplication.h b/src/plugins/platforms/windows/qwindowsapplication.h
index efacd74e18..0918df91af 100644
--- a/src/plugins/platforms/windows/qwindowsapplication.h
+++ b/src/plugins/platforms/windows/qwindowsapplication.h
@@ -24,7 +24,6 @@ public:
bool isWinTabEnabled() const override;
bool setWinTabEnabled(bool enabled) override;
- bool isDarkMode() const override;
DarkModeHandling darkModeHandling() const override;
void setDarkModeHandling(DarkModeHandling handling) override;
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index c85c44d949..8c0261d568 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -154,11 +154,9 @@ struct QWindowsContextPrivate {
bool m_asyncExpose = false;
HPOWERNOTIFY m_powerNotification = nullptr;
HWND m_powerDummyWindow = nullptr;
- static bool m_darkMode;
static bool m_v2DpiAware;
};
-bool QWindowsContextPrivate::m_darkMode = false;
bool QWindowsContextPrivate::m_v2DpiAware = false;
QWindowsContextPrivate::QWindowsContextPrivate()
@@ -172,7 +170,6 @@ QWindowsContextPrivate::QWindowsContextPrivate()
m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
m_keyMapper.setUseRTLExtensions(true);
}
- m_darkMode = QWindowsTheme::queryDarkMode();
if (FAILED(m_oleInitializeResult)) {
qWarning() << "QWindowsContext: OleInitialize() failed: "
<< QSystemError::windowsComString(m_oleInitializeResult);
@@ -204,6 +201,8 @@ QWindowsContext::~QWindowsContext()
if (d->m_powerDummyWindow)
DestroyWindow(d->m_powerDummyWindow);
+ d->m_screenManager.destroyWindow();
+
unregisterWindowClasses();
if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) {
#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
@@ -464,11 +463,6 @@ bool QWindowsContext::setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwarenes
return true;
}
-bool QWindowsContext::isDarkMode()
-{
- return QWindowsContextPrivate::m_darkMode;
-}
-
QWindowsContext *QWindowsContext::instance()
{
return m_instance;
@@ -1093,21 +1087,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
// Only refresh the window theme if the user changes the personalize settings.
if ((wParam == 0) && (lParam != 0) // lParam sometimes may be NULL.
&& (wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0)) {
- const bool darkMode = QWindowsTheme::queryDarkMode();
- const bool darkModeChanged = darkMode != QWindowsContextPrivate::m_darkMode;
- QWindowsContextPrivate::m_darkMode = darkMode;
- auto integration = QWindowsIntegration::instance();
- integration->updateApplicationBadge();
- if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle)) {
- QWindowsTheme::instance()->refresh();
- QWindowSystemInterface::handleThemeChange();
- }
- if (darkModeChanged) {
- if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames)) {
- for (QWindowsWindow *w : d->m_windows)
- w->setDarkBorder(QWindowsContextPrivate::m_darkMode);
- }
- }
+ QWindowsTheme::handleSettingsChanged();
}
return d->m_screenManager.handleScreenChanges();
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 1089224433..0539a22afc 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -120,8 +120,6 @@ public:
static QtWindows::DpiAwareness processDpiAwareness();
static QtWindows::DpiAwareness windowDpiAwareness(HWND hwnd);
- static bool isDarkMode();
-
void setDetectAltGrModifier(bool a);
// Returns a combination of SystemInfoFlags
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 6415c9ac50..aa6be266da 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -625,12 +625,16 @@ void QWindowsIntegration::setApplicationBadge(qint64 number)
// We prefer the native BadgeUpdater API, that allows us to set a number directly,
// but it requires that the application has a package identity, and also doesn't
// seem to work in all cases on < Windows 11.
- if (isWindows11 && qt_win_hasPackageIdentity()) {
- using namespace winrt::Windows::UI::Notifications;
- auto badgeXml = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
- badgeXml.SelectSingleNode(L"//badge/@value").NodeValue(winrt::box_value(winrt::to_hstring(number)));
- BadgeUpdateManager::CreateBadgeUpdaterForApplication().Update(BadgeNotification(badgeXml));
- return;
+ QT_TRY {
+ if (isWindows11 && qt_win_hasPackageIdentity()) {
+ using namespace winrt::Windows::UI::Notifications;
+ auto badgeXml = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
+ badgeXml.SelectSingleNode(L"//badge/@value").NodeValue(winrt::box_value(winrt::to_hstring(number)));
+ BadgeUpdateManager::CreateBadgeUpdaterForApplication().Update(BadgeNotification(badgeXml));
+ return;
+ }
+ } QT_CATCH(...) {
+ // fall back to win32 implementation
}
#endif
@@ -642,7 +646,8 @@ void QWindowsIntegration::setApplicationBadge(qint64 number)
return;
}
- const bool isDarkMode = QWindowsContext::isDarkMode();
+ const bool isDarkMode = QWindowsTheme::instance()->colorScheme()
+ == Qt::ColorScheme::Dark;
QColor badgeColor;
QColor textColor;
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index a50f9fd4b0..1f22fb4f60 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -698,11 +698,15 @@ void QWindowsScreenManager::initialize()
handleScreenChanges();
}
-QWindowsScreenManager::~QWindowsScreenManager()
+void QWindowsScreenManager::destroyWindow()
{
+ qCDebug(lcQpaScreen) << "Destroying display change observer" << m_displayChangeObserver;
DestroyWindow(m_displayChangeObserver);
+ m_displayChangeObserver = nullptr;
}
+QWindowsScreenManager::~QWindowsScreenManager() = default;
+
bool QWindowsScreenManager::isSingleScreen()
{
return QWindowsContext::instance()->screenManager().screens().size() < 2;
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 0467ab2a0c..ea6a29efe3 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -105,6 +105,7 @@ public:
QWindowsScreenManager();
void initialize();
+ void destroyWindow();
~QWindowsScreenManager();
void clearScreens();
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index b0b6672487..b6017c7692 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -13,6 +13,7 @@
# include "qwindowssystemtrayicon.h"
#endif
#include "qwindowsscreen.h"
+#include "qwindowswindow.h"
#include <commctrl.h>
#include <objbase.h>
#include <commoncontrols.h>
@@ -258,7 +259,7 @@ static QColor placeHolderColor(QColor textColor)
This is used when the theme is light mode, and when the theme is dark but the
application doesn't support dark mode. In the latter case, we need to check.
*/
-static void populateLightSystemBasePalette(QPalette &result)
+void QWindowsTheme::populateLightSystemBasePalette(QPalette &result)
{
const QColor background = getSysColor(COLOR_BTNFACE);
const QColor textColor = getSysColor(COLOR_WINDOWTEXT);
@@ -298,8 +299,11 @@ static void populateLightSystemBasePalette(QPalette &result)
result.setColor(QPalette::Midlight, result.button().color().lighter(110));
}
-static void populateDarkSystemBasePalette(QPalette &result)
+void QWindowsTheme::populateDarkSystemBasePalette(QPalette &result)
{
+ QColor foreground, background,
+ accent, accentDark, accentDarker, accentDarkest,
+ accentLight, accentLighter, accentLightest;
#if QT_CONFIG(cpp_winrt)
using namespace winrt::Windows::UI::ViewManagement;
const auto settings = UISettings();
@@ -307,32 +311,37 @@ static void populateDarkSystemBasePalette(QPalette &result)
// We have to craft a palette from these colors. The settings.UIElementColor(UIElementType) API
// returns the old system colors, not the dark mode colors. If the background is black (which it
// usually), then override it with a dark gray instead so that we can go up and down the lightness.
- const QColor foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground));
- const QColor background = [&settings]() -> QColor {
- auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background));
- if (systemBackground == Qt::black)
- systemBackground = QColor(0x1E, 0x1E, 0x1E);
- return systemBackground;
- }();
-
- const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
- const QColor accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1));
- const QColor accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2));
- const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
- const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
- const QColor accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2));
- const QColor accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3));
-#else
- const QColor foreground = Qt::white;
- const QColor background = QColor(0x1E, 0x1E, 0x1E);
- const QColor accent = qt_accentColor(AccentColorNormal);
- const QColor accentDark = accent.darker(120);
- const QColor accentDarker = accentDark.darker(120);
- const QColor accentDarkest = accentDarker.darker(120);
- const QColor accentLight = accent.lighter(120);
- const QColor accentLighter = accentLight.lighter(120);
- const QColor accentLightest = accentLighter.lighter(120);
+ if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) {
+ // the system is actually running in dark mode, so UISettings will give us dark colors
+ foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground));
+ background = [&settings]() -> QColor {
+ auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background));
+ if (systemBackground == Qt::black)
+ systemBackground = QColor(0x1E, 0x1E, 0x1E);
+ return systemBackground;
+ }();
+
+ accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
+ accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1));
+ accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2));
+ accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
+ accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
+ accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2));
+ accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3));
+ } else
#endif
+ {
+ // If the system is running in light mode, then we need to make up our own dark palette
+ foreground = Qt::white;
+ background = QColor(0x1E, 0x1E, 0x1E);
+ accent = qt_accentColor(AccentColorNormal);
+ accentDark = accent.darker(120);
+ accentDarker = accentDark.darker(120);
+ accentDarkest = accentDarker.darker(120);
+ accentLight = accent.lighter(120);
+ accentLighter = accentLight.lighter(120);
+ accentLightest = accentLighter.lighter(120);
+ }
const QColor linkColor = accent;
const QColor buttonColor = background.lighter(200);
@@ -451,6 +460,7 @@ QWindowsTheme *QWindowsTheme::m_instance = nullptr;
QWindowsTheme::QWindowsTheme()
{
m_instance = this;
+ s_colorScheme = QWindowsTheme::queryColorScheme();
std::fill(m_fonts, m_fonts + NFonts, nullptr);
std::fill(m_palettes, m_palettes + NPalettes, nullptr);
refresh();
@@ -540,9 +550,43 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
Qt::ColorScheme QWindowsTheme::colorScheme() const
{
+ return QWindowsTheme::effectiveColorScheme();
+}
+
+Qt::ColorScheme QWindowsTheme::effectiveColorScheme()
+{
if (queryHighContrast())
return Qt::ColorScheme::Unknown;
- return QWindowsContext::isDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
+ if (s_colorSchemeOverride != Qt::ColorScheme::Unknown)
+ return s_colorSchemeOverride;
+ if (s_colorScheme != Qt::ColorScheme::Unknown)
+ return s_colorScheme;
+ return queryColorScheme();
+}
+
+void QWindowsTheme::requestColorScheme(Qt::ColorScheme scheme)
+{
+ s_colorSchemeOverride = scheme;
+ handleSettingsChanged();
+}
+
+void QWindowsTheme::handleSettingsChanged()
+{
+ const auto oldColorScheme = s_colorScheme;
+ s_colorScheme = Qt::ColorScheme::Unknown; // make effectiveColorScheme() query registry
+ const auto newColorScheme = effectiveColorScheme();
+ const bool colorSchemeChanged = newColorScheme != oldColorScheme;
+ s_colorScheme = newColorScheme;
+ auto integration = QWindowsIntegration::instance();
+ integration->updateApplicationBadge();
+ if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle)) {
+ QWindowsTheme::instance()->refresh();
+ QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
+ }
+ if (colorSchemeChanged) {
+ for (QWindowsWindow *w : std::as_const(QWindowsContext::instance()->windows()))
+ w->setDarkBorder(s_colorScheme == Qt::ColorScheme::Dark);
+ }
}
void QWindowsTheme::clearPalettes()
@@ -556,10 +600,10 @@ void QWindowsTheme::refreshPalettes()
if (!QGuiApplication::desktopSettingsAware())
return;
const bool light =
- !QWindowsContext::isDarkMode()
+ effectiveColorScheme() != Qt::ColorScheme::Dark
|| !QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle);
clearPalettes();
- m_palettes[SystemPalette] = new QPalette(QWindowsTheme::systemPalette(light ? Qt::ColorScheme::Light : Qt::ColorScheme::Dark));
+ m_palettes[SystemPalette] = new QPalette(QWindowsTheme::systemPalette(s_colorScheme));
m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
@@ -577,15 +621,15 @@ QPalette QWindowsTheme::systemPalette(Qt::ColorScheme colorScheme)
QPalette result = standardPalette();
switch (colorScheme) {
+ case Qt::ColorScheme::Unknown:
+ // when a high-contrast theme is active or when we fail to read, assume light
+ Q_FALLTHROUGH();
case Qt::ColorScheme::Light:
populateLightSystemBasePalette(result);
break;
case Qt::ColorScheme::Dark:
populateDarkSystemBasePalette(result);
break;
- default:
- qFatal("Unknown color scheme");
- break;
}
if (result.window() != result.base()) {
@@ -1091,14 +1135,14 @@ bool QWindowsTheme::useNativeMenus()
return result;
}
-bool QWindowsTheme::queryDarkMode()
+Qt::ColorScheme QWindowsTheme::queryColorScheme()
{
- if (queryHighContrast()) {
- return false;
- }
+ if (queryHighContrast())
+ return Qt::ColorScheme::Unknown;
+
const auto setting = QWinRegistryKey(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)")
.dwordValue(L"AppsUseLightTheme");
- return setting.second && setting.first == 0;
+ return setting.second && setting.first == 0 ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
}
bool QWindowsTheme::queryHighContrast()
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index bc16a9619e..96ae6197b4 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -32,6 +32,10 @@ public:
QVariant themeHint(ThemeHint) const override;
Qt::ColorScheme colorScheme() const override;
+ void requestColorScheme(Qt::ColorScheme scheme) override;
+ Qt::ColorScheme requestedColorScheme() const { return s_colorSchemeOverride; }
+
+ static void handleSettingsChanged();
const QPalette *palette(Palette type = SystemPalette) const override
{ return m_palettes[type]; }
@@ -54,8 +58,6 @@ public:
void showPlatformMenuBar() override;
static bool useNativeMenus();
- static bool queryDarkMode();
- static bool queryHighContrast();
void refreshFonts();
void refresh();
@@ -70,7 +72,17 @@ private:
void clearFonts();
void refreshIconPixmapSizes();
+ static void populateLightSystemBasePalette(QPalette &result);
+ static void populateDarkSystemBasePalette(QPalette &result);
+
+ static Qt::ColorScheme queryColorScheme();
+ static Qt::ColorScheme effectiveColorScheme();
+ static bool queryHighContrast();
+
static QWindowsTheme *m_instance;
+ static inline Qt::ColorScheme s_colorScheme = Qt::ColorScheme::Unknown;
+ static inline Qt::ColorScheme s_colorSchemeOverride = Qt::ColorScheme::Unknown;
+
QPalette *m_palettes[NPalettes];
QFont *m_fonts[NFonts];
QList<QSize> m_fileIconSizes;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index c54da57ffe..ee0b88ba54 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -5,6 +5,7 @@
#include "qwindowswindow.h"
#include "qwindowscontext.h"
+#include "qwindowstheme.h"
#if QT_CONFIG(draganddrop)
# include "qwindowsdrag.h"
#endif
@@ -849,10 +850,17 @@ static inline bool shouldApplyDarkFrame(const QWindow *w)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
return false;
- // the application has explicitly opted out of dark frames
+
+ // the user of the application has explicitly opted out of dark frames
if (!QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames))
return false;
+ // the application explicitly overrides the color scheme
+ if (const auto requestedColorScheme = QWindowsTheme::instance()->requestedColorScheme();
+ requestedColorScheme != Qt::ColorScheme::Unknown) {
+ return requestedColorScheme == Qt::ColorScheme::Dark;
+ }
+
// if the application supports a dark border, and the palette is dark (window background color
// is darker than the text), then turn dark-border support on, otherwise use a light border.
auto *dWindow = QWindowPrivate::get(const_cast<QWindow*>(w));
@@ -929,7 +937,7 @@ QWindowsWindowData
return result;
}
- if (QWindowsContext::isDarkMode() && shouldApplyDarkFrame(w))
+ if (QWindowsTheme::instance()->colorScheme() == Qt::ColorScheme::Dark && shouldApplyDarkFrame(w))
QWindowsWindow::setDarkBorderToWindow(result.hwnd, true);
if (mirrorParentWidth != 0) {
@@ -2689,7 +2697,7 @@ bool QWindowsWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::ApplicationPaletteChange:
- setDarkBorder(QWindowsContext::isDarkMode());
+ setDarkBorder(QWindowsTheme::instance()->colorScheme() == Qt::ColorScheme::Dark);
break;
case QEvent::WindowBlocked: // Blocked by another modal window.
setEnabled(false);
@@ -3285,17 +3293,6 @@ enum : WORD {
DwmwaUseImmersiveDarkModeBefore20h1 = 19
};
-static bool queryDarkBorder(HWND hwnd)
-{
- BOOL result = FALSE;
- const bool ok =
- SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &result, sizeof(result)))
- || SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &result, sizeof(result)));
- if (!ok)
- qCWarning(lcQpaWindow, "%s: Unable to retrieve dark window border setting.", __FUNCTION__);
- return result == TRUE;
-}
-
bool QWindowsWindow::setDarkBorderToWindow(HWND hwnd, bool d)
{
const BOOL darkBorder = d ? TRUE : FALSE;
@@ -3311,8 +3308,6 @@ void QWindowsWindow::setDarkBorder(bool d)
{
// respect explicit opt-out and incompatible palettes or styles
d = d && shouldApplyDarkFrame(window());
- if (queryDarkBorder(m_data.hwnd) == d)
- return;
setDarkBorderToWindow(m_data.hwnd, d);
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
index 1abb412ccd..5892493281 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
@@ -127,6 +127,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
return;
switch (event->type()) {
+ case QAccessible::Announcement:
+ QWindowsUiaMainProvider::raiseNotification(static_cast<QAccessibleAnnouncementEvent *>(event));
+ break;
case QAccessible::Focus:
QWindowsUiaMainProvider::notifyFocusChange(event);
break;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index 95ddbcced6..b8f2d0eadd 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -204,6 +204,24 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
}
}
+void QWindowsUiaMainProvider::raiseNotification(QAccessibleAnnouncementEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
+ BSTR message = bStrFromQString(event->message());
+ QAccessible::AnnouncementPriority prio = event->priority();
+ NotificationProcessing processing = (prio == QAccessible::AnnouncementPriority::Assertive)
+ ? NotificationProcessing_ImportantAll
+ : NotificationProcessing_All;
+ BSTR activityId = bStrFromQString(QString::fromLatin1(""));
+ UiaRaiseNotificationEvent(provider, NotificationKind_Other, processing, message, activityId);
+
+ ::SysFreeString(message);
+ ::SysFreeString(activityId);
+ }
+ }
+}
+
HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
{
HRESULT result = QComObject::QueryInterface(iid, iface);
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
index 99db0ed318..b24f4a6cc3 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
@@ -34,6 +34,7 @@ public:
static void notifyNameChange(QAccessibleEvent *event);
static void notifySelectionChange(QAccessibleEvent *event);
static void notifyTextChange(QAccessibleEvent *event);
+ static void raiseNotification(QAccessibleAnnouncementEvent *event);
// IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
index 1593a07202..6954a881d0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
@@ -69,6 +69,14 @@ HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *pProvider, EVE
return func.invoke(pProvider, id);
}
+HRESULT WINAPI UiaRaiseNotificationEvent(
+ IRawElementProviderSimple *pProvider, NotificationKind notificationKind,
+ NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaRaiseNotificationEvent));
+ return func.invoke(pProvider, notificationKind, notificationProcessing, displayString, activityId);
+}
+
#endif // defined(__MINGW32__) || defined(__MINGW64__)
#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/xcb/CMakeLists.txt b/src/plugins/platforms/xcb/CMakeLists.txt
index e8fb442dd4..96758e7181 100644
--- a/src/plugins/platforms/xcb/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/CMakeLists.txt
@@ -164,7 +164,7 @@ endif()
qt_internal_add_plugin(QXcbIntegrationPlugin
OUTPUT_NAME qxcb
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES xcb
+ DEFAULT_IF "xcb" IN_LIST QT_QPA_PLATFORMS
SOURCES
qxcbmain.cpp
DEFINES
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
index 28361e250d..f6eed5e227 100644
--- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
@@ -118,6 +118,7 @@ static void initDA(XSQLDA *sqlda)
default:
// not supported - do not bind.
sqlda->sqlvar[i].sqldata = 0;
+ qCWarning(lcIbase, "initDA: unknown sqltype: %d", sqlda->sqlvar[i].sqltype & ~1);
break;
}
if (sqlda->sqlvar[i].sqltype & 1) {
@@ -208,8 +209,10 @@ static QMetaType::Type qIBaseTypeName2(int iType, bool hasScale)
case SQL_BOOLEAN:
return QMetaType::Bool;
default:
- return QMetaType::UnknownType;
+ break;
}
+ qCWarning(lcIbase, "qIBaseTypeName: unknown datatype: %d", iType);
+ return QMetaType::UnknownType;
}
static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
@@ -403,6 +406,42 @@ protected:
int size() override;
int numRowsAffected() override;
QSqlRecord record() const override;
+
+ template<typename T>
+ QVariant applyScale(T val, int scale) const
+ {
+ if (scale >= 0)
+ return QVariant(val);
+
+ switch (numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ return QVariant(qint32(val * pow(10.0, scale)));
+ case QSql::LowPrecisionInt64:
+ return QVariant(qint64(val * pow(10.0, scale)));
+ case QSql::LowPrecisionDouble:
+ return QVariant(double(val * pow(10.0, scale)));
+ case QSql::HighPrecision: {
+ const bool negative = val < 0;
+ QString number;
+ if constexpr (std::is_signed_v<T> || negative)
+ number = QString::number(qAbs(val));
+ else
+ number = QString::number(val);
+ auto len = number.size();
+ scale *= -1;
+ if (scale >= len) {
+ number = QString(scale - len + 1, u'0') + number;
+ len = number.size();
+ }
+ const auto sepPos = len - scale;
+ number = number.left(sepPos) + u'.' + number.mid(sepPos);
+ if (negative)
+ number = u'-' + number;
+ return QVariant(number);
+ }
+ }
+ return QVariant(val);
+ }
};
class QIBaseResultPrivate: public QSqlCachedResultPrivate
@@ -1236,27 +1275,27 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
// pascal strings - a short with a length information followed by the data
row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
break;
- case SQL_INT64:
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = *(qint64*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale);
- else
- row[idx] = QVariant(*(qint64*)buf);
+ case SQL_INT64: {
+ Q_ASSERT(d->sqlda->sqlvar[i].sqllen == sizeof(qint64));
+ const auto val = *(qint64 *)buf;
+ const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ row[idx] = applyScale(val, scale);
break;
+ }
case SQL_LONG:
- if (d->sqlda->sqlvar[i].sqllen == 4)
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = QVariant(*(qint32*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
- else
- row[idx] = QVariant(*(qint32*)buf);
- else
+ if (d->sqlda->sqlvar[i].sqllen == 4) {
+ const auto val = *(qint32 *)buf;
+ const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ row[idx] = applyScale(val, scale);
+ } else
row[idx] = QVariant(*(qint64*)buf);
break;
- case SQL_SHORT:
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = QVariant(long((*(short*)buf)) * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
- else
- row[idx] = QVariant(int((*(short*)buf)));
+ case SQL_SHORT: {
+ const auto val = *(short *)buf;
+ const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ row[idx] = applyScale(val, scale);
break;
+ }
case SQL_FLOAT:
row[idx] = QVariant(double((*(float*)buf)));
break;
@@ -1291,30 +1330,11 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
#endif
default:
// unknown type - don't even try to fetch
+ qCWarning(lcIbase, "gotoNext: unknown sqltype: %d",
+ d->sqlda->sqlvar[i].sqltype & ~1);
row[idx] = QVariant();
break;
}
- if (d->sqlda->sqlvar[i].sqlscale < 0) {
- QVariant v = row[idx];
- switch(numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- if (v.convert(QMetaType(QMetaType::Int)))
- row[idx]=v;
- break;
- case QSql::LowPrecisionInt64:
- if (v.convert(QMetaType(QMetaType::LongLong)))
- row[idx]=v;
- break;
- case QSql::LowPrecisionDouble:
- if (v.convert(QMetaType(QMetaType::Double)))
- row[idx]=v;
- break;
- case QSql::HighPrecision:
- if (v.convert(QMetaType(QMetaType::QString)))
- row[idx]=v;
- break;
- }
- }
}
return true;
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
index 51efdc24a0..8b886396f8 100644
--- a/src/plugins/styles/modernwindows/qwindows11style.cpp
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -434,12 +434,21 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
#if QT_CONFIG(combobox)
case CC_ComboBox:
if (const QStyleOptionComboBox *combobox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
- QBrush fillColor = state & State_MouseOver && !(state & State_HasFocus) ? QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]) : option->palette.brush(QPalette::Base);
+ QBrush fillColor = combobox->palette.brush(QPalette::Base);
QRectF rect = option->rect.adjusted(2,2,-2,-2);
painter->setBrush(fillColor);
painter->setPen(Qt::NoPen);
painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ // In case the QComboBox is hovered overdraw the background with a alpha mask to
+ // highlight the QComboBox.
+ if (state & State_MouseOver) {
+ fillColor = QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+
rect.adjust(0.5,0.5,-0.5,-0.5);
painter->setBrush(Qt::NoBrush);
painter->setPen(highContrastTheme == true ? combobox->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
@@ -905,12 +914,20 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
if (widget && widget->objectName() == "qt_spinbox_lineedit")
break;
if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
- QBrush fillColor = state & State_MouseOver && !(state & State_HasFocus) ? QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]) : option->palette.brush(QPalette::Base);
- painter->setBrush(fillColor);
- painter->setPen(Qt::NoPen);
QRectF frameRect = option->rect;
frameRect.adjust(0.5,0.5,-0.5,-0.5);
+ QBrush fillColor = option->palette.brush(QPalette::Base);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ // In case the QLineEdit is hovered overdraw the background with a alpha mask to
+ // highlight the QLineEdit.
+ if (state & State_MouseOver && !(state & State_HasFocus)) {
+ fillColor = QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
if (panel->lineWidth > 0)
proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
}
@@ -1104,7 +1121,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
rect.translate(shiftX, shiftY);
painter->setFont(toolbutton->font);
const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
- if (toolbutton->state & State_Raised)
+ if (toolbutton->state & State_Raised || toolbutton->palette.isBrushSet(QPalette::Current, QPalette::ButtonText))
painter->setPen(QPen(toolbutton->palette.buttonText().color()));
else
painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
@@ -1158,7 +1175,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
}
tr.translate(shiftX, shiftY);
const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
- if (toolbutton->state & State_Raised)
+ if (toolbutton->state & State_Raised || toolbutton->palette.isBrushSet(QPalette::Current, QPalette::ButtonText))
painter->setPen(QPen(toolbutton->palette.buttonText().color()));
else
painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
@@ -1207,75 +1224,72 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
break;
case QStyle::CE_ProgressBarGroove:{
if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
- if (const QProgressBar* bar = qobject_cast<const QProgressBar*>(widget)) {
- QRect rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
- QPointF center = rect.center();
- if (bar->orientation() & Qt::Horizontal) {
- rect.setHeight(1);
- rect.moveTop(center.y());
- } else {
- rect.setWidth(1);
- rect.moveLeft(center.x());
- }
- painter->setPen(Qt::NoPen);
- painter->setBrush(Qt::gray);
- painter->drawRect(rect);
+ QRect rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
+ QPointF center = rect.center();
+ if (progbaropt->state & QStyle::State_Horizontal) {
+ rect.setHeight(1);
+ rect.moveTop(center.y());
+ } else {
+ rect.setWidth(1);
+ rect.moveLeft(center.x());
}
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(Qt::gray);
+ painter->drawRect(rect);
}
break;
}
case QStyle::CE_ProgressBarContents:
if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
- if (const QProgressBar* bar = qobject_cast<const QProgressBar*>(widget)) {
- const qreal progressBarThickness = 3;
- const qreal progressBarHalfThickness = progressBarThickness / 2.0;
- QRectF rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
- QRectF originalRect = rect;
- QPointF center = rect.center();
- bool isIndeterminate = progbaropt->maximum == 0 && progbaropt->minimum == 0;
- float fillPercentage = 0;
- const qreal offset = (bar->orientation() == Qt::Horizontal && int(rect.height()) % 2 == 0)
- || (bar->orientation() == Qt::Vertical && int(rect.width()) % 2 == 0) ? 0.5 : 0.0;
-
- if (!isIndeterminate) {
- fillPercentage = ((float(progbaropt->progress) - float(progbaropt->minimum)) / (float(progbaropt->maximum) - float(progbaropt->minimum)));
- if (bar->orientation() == Qt::Horizontal) {
- rect.setHeight(progressBarThickness);
- rect.moveTop(center.y() - progressBarHalfThickness - offset);
- rect.setWidth(rect.width() * fillPercentage);
- } else {
- float oldHeight = rect.height();
- rect.setWidth(progressBarThickness);
- rect.moveLeft(center.x() - progressBarHalfThickness - offset);
- rect.moveTop(oldHeight * (1.0f - fillPercentage));
- rect.setHeight(oldHeight * fillPercentage);
- }
+ const qreal progressBarThickness = 3;
+ const qreal progressBarHalfThickness = progressBarThickness / 2.0;
+ QRectF rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
+ QRectF originalRect = rect;
+ QPointF center = rect.center();
+ bool isIndeterminate = progbaropt->maximum == 0 && progbaropt->minimum == 0;
+ float fillPercentage = 0;
+ const Qt::Orientation orientation = (progbaropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
+ const qreal offset = (orientation == Qt::Horizontal && int(rect.height()) % 2 == 0)
+ || (orientation == Qt::Vertical && int(rect.width()) % 2 == 0) ? 0.5 : 0.0;
+
+ if (!isIndeterminate) {
+ fillPercentage = ((float(progbaropt->progress) - float(progbaropt->minimum)) / (float(progbaropt->maximum) - float(progbaropt->minimum)));
+ if (orientation == Qt::Horizontal) {
+ rect.setHeight(progressBarThickness);
+ rect.moveTop(center.y() - progressBarHalfThickness - offset);
+ rect.setWidth(rect.width() * fillPercentage);
} else {
- auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
- fillPercentage = (elapsedTime.time_since_epoch().count() % 5000)/(5000.0f*0.75);
- if (bar->orientation() == Qt::Horizontal) {
- float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.width(), float(rect.width()));
- float barEnd = qMin(fillPercentage * rect.width(), float(rect.width()));
- rect = QRect(QPoint(rect.left() + barBegin, rect.top()), QPoint(rect.left() + barEnd, rect.bottom()));
- rect.setHeight(progressBarThickness);
- rect.moveTop(center.y() - progressBarHalfThickness - offset);
- } else {
- float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.height(), float(rect.height()));
- float barEnd = qMin(fillPercentage * rect.height(), float(rect.height()));
- rect = QRect(QPoint(rect.left(), rect.bottom() - barEnd), QPoint(rect.right(), rect.bottom() - barBegin));
- rect.setWidth(progressBarThickness);
- rect.moveLeft(center.x() - progressBarHalfThickness - offset);
- }
- const_cast<QWidget*>(widget)->update();
+ float oldHeight = rect.height();
+ rect.setWidth(progressBarThickness);
+ rect.moveLeft(center.x() - progressBarHalfThickness - offset);
+ rect.moveTop(oldHeight * (1.0f - fillPercentage));
+ rect.setHeight(oldHeight * fillPercentage);
}
- if (progbaropt->invertedAppearance && bar->orientation() == Qt::Horizontal)
- rect.moveLeft(originalRect.width() * (1.0 - fillPercentage));
- else if (progbaropt->invertedAppearance && bar->orientation() == Qt::Vertical)
- rect.moveBottom(originalRect.height() * fillPercentage);
- painter->setPen(Qt::NoPen);
- painter->setBrush(progbaropt->palette.accent());
- painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ } else {
+ auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
+ fillPercentage = (elapsedTime.time_since_epoch().count() % 5000)/(5000.0f*0.75);
+ if (orientation == Qt::Horizontal) {
+ float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.width(), float(rect.width()));
+ float barEnd = qMin(fillPercentage * rect.width(), float(rect.width()));
+ rect = QRect(QPoint(rect.left() + barBegin, rect.top()), QPoint(rect.left() + barEnd, rect.bottom()));
+ rect.setHeight(progressBarThickness);
+ rect.moveTop(center.y() - progressBarHalfThickness - offset);
+ } else {
+ float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.height(), float(rect.height()));
+ float barEnd = qMin(fillPercentage * rect.height(), float(rect.height()));
+ rect = QRect(QPoint(rect.left(), rect.bottom() - barEnd), QPoint(rect.right(), rect.bottom() - barBegin));
+ rect.setWidth(progressBarThickness);
+ rect.moveLeft(center.x() - progressBarHalfThickness - offset);
+ }
+ const_cast<QWidget*>(widget)->update();
}
+ if (progbaropt->invertedAppearance && orientation == Qt::Horizontal)
+ rect.moveLeft(originalRect.width() * (1.0 - fillPercentage));
+ else if (progbaropt->invertedAppearance && orientation == Qt::Vertical)
+ rect.moveBottom(originalRect.height() * fillPercentage);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(progbaropt->palette.accent());
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
}
break;
case QStyle::CE_ProgressBarLabel:
@@ -1364,13 +1378,15 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
} else {
QRectF rect = btn->rect.marginsRemoved(QMargins(2,2,2,2));
painter->setPen(Qt::NoPen);
- if (flags & (State_Sunken))
- painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(120) : WINUI3Colors[colorSchemeIndex][controlFillTertiary]);
- else if (flags & State_MouseOver)
- painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(110) : WINUI3Colors[colorSchemeIndex][controlFillSecondary]);
- else
- painter->setBrush(flags & State_On ? option->palette.accent() : option->palette.button());
+ painter->setBrush(flags & State_On ? option->palette.accent() : option->palette.button());
painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ if (flags.testFlags(State_Sunken | State_MouseOver)) {
+ if (flags & (State_Sunken))
+ painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(120) : WINUI3Colors[colorSchemeIndex][controlFillTertiary]);
+ else if (flags & State_MouseOver)
+ painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(110) : WINUI3Colors[colorSchemeIndex][controlFillSecondary]);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
rect.adjust(0.5,0.5,-0.5,-0.5);
painter->setBrush(Qt::NoBrush);
@@ -1578,7 +1594,13 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
break;
case CE_HeaderSection: {
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(header->palette.button());
+ painter->drawRect(header->rect);
+
painter->setPen(highContrastTheme == true ? header->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->setBrush(Qt::NoBrush);
+
if (header->position == QStyleOptionHeader::OnlyOneSection) {
break;
}
@@ -1629,7 +1651,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
if ((vopt->state & State_Selected || vopt->state & State_MouseOver) && !(isTreeView && vopt->state & State_MouseOver) && vopt->showDecorationSelected) {
painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
- QWidget *editorWidget = view->indexWidget(view->currentIndex());
+ QWidget *editorWidget = view ? view->indexWidget(view->currentIndex()) : nullptr;
if (editorWidget) {
QPalette pal = editorWidget->palette();
QColor editorBgColor = vopt->backgroundBrush == Qt::NoBrush ? vopt->palette.color(widget->backgroundRole()) : vopt->backgroundBrush.color();
@@ -1682,7 +1704,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
painter->setPen(QPen(option->palette.buttonText().color()));
- if (!view->isPersistentEditorOpen(vopt->index))
+ if (!view || !view->isPersistentEditorOpen(vopt->index))
d->viewItemDrawText(painter, vopt, textRect);
if (vopt->state & State_Selected
&& (vopt->viewItemPosition == QStyleOptionViewItem::Beginning
@@ -1716,6 +1738,10 @@ int QWindows11Style::styleHint(StyleHint hint, const QStyleOption *opt,
return 0;
case QStyle::SH_ItemView_ShowDecorationSelected:
return 1;
+ case QStyle::SH_Slider_AbsoluteSetButtons:
+ return Qt::LeftButton;
+ case QStyle::SH_Slider_PageSetButtons:
+ return 0;
default:
return QWindowsVistaStyle::styleHint(hint, opt, widget, returnData);
}
@@ -2014,17 +2040,19 @@ void QWindows11Style::polish(QWidget* widget)
QLineEdit *le = cb->lineEdit();
le->setFrame(false);
}
+ } else if (widget->inherits("QAbstractButton") || widget->inherits("QToolButton")) {
+ widget->setAutoFillBackground(false);
} else if (qobject_cast<QGraphicsView *>(widget) && !qobject_cast<QTextEdit *>(widget)) {
QPalette pal = widget->palette();
pal.setColor(QPalette::Base, pal.window().color());
widget->setPalette(pal);
} else if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
scrollarea && !qobject_cast<QMdiArea *>(widget)) {
- QPalette pal = widget->palette();
- QColor backgroundColor = widget->palette().base().color();
- backgroundColor.setAlpha(255);
- pal.setColor(scrollarea->viewport()->backgroundRole(), backgroundColor);
+ QPalette pal = scrollarea->viewport()->palette();
+ const QPalette originalPalette = pal;
+ pal.setColor(scrollarea->viewport()->backgroundRole(), Qt::transparent);
scrollarea->viewport()->setPalette(pal);
+ scrollarea->viewport()->setProperty("_q_original_background_palette", originalPalette);
} else if (qobject_cast<QCommandLinkButton *>(widget)) {
widget->setProperty("_qt_usingVistaStyle",false);
QPalette pal = widget->palette();
@@ -2034,53 +2062,50 @@ void QWindows11Style::polish(QWidget* widget)
}
}
+void QWindows11Style::unpolish(QWidget *widget)
+{
+ QWindowsVistaStyle::unpolish(widget);
+ if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
+ scrollarea && !qobject_cast<QMdiArea *>(widget)) {
+ const QPalette pal = scrollarea->viewport()->property("_q_original_background_palette").value<QPalette>();
+ scrollarea->viewport()->setPalette(pal);
+ scrollarea->viewport()->setProperty("_q_original_background_palette", QVariant());
+ }
+}
/*
The colors for Windows 11 are taken from the official WinUI3 Figma style at
https://www.figma.com/community/file/1159947337437047524
*/
+#define SET_IF_UNRESOLVED(GROUP, ROLE, VALUE) \
+ if (!result.isBrushSet(QPalette::Inactive, ROLE) || styleSheetChanged) \
+ result.setColor(GROUP, ROLE, VALUE)
+
static void populateLightSystemBasePalette(QPalette &result)
{
static QString oldStyleSheet;
const bool styleSheetChanged = oldStyleSheet != qApp->styleSheet();
- QPalette standardPalette = QApplication::palette();
const QColor textColor = QColor(0x00,0x00,0x00,0xE4);
-
const QColor btnFace = QColor(0xFF,0xFF,0xFF,0xB3);
const QColor btnHighlight = result.accent().color();
const QColor btnColor = result.button().color();
- if (standardPalette.color(QPalette::Highlight) == result.color(QPalette::Highlight) || styleSheetChanged)
- result.setColor(QPalette::Highlight, btnHighlight);
- if (standardPalette.color(QPalette::WindowText) == result.color(QPalette::WindowText) || styleSheetChanged)
- result.setColor(QPalette::WindowText, textColor);
- if (standardPalette.color(QPalette::Button) == result.color(QPalette::Button) || styleSheetChanged)
- result.setColor(QPalette::Button, btnFace);
- if (standardPalette.color(QPalette::Light) == result.color(QPalette::Light) || styleSheetChanged)
- result.setColor(QPalette::Light, btnColor.lighter(150));
- if (standardPalette.color(QPalette::Dark) == result.color(QPalette::Dark) || styleSheetChanged)
- result.setColor(QPalette::Dark, btnColor.darker(200));
- if (standardPalette.color(QPalette::Mid) == result.color(QPalette::Mid) || styleSheetChanged)
- result.setColor(QPalette::Mid, btnColor.darker(150));
- if (standardPalette.color(QPalette::Text) == result.color(QPalette::Text) || styleSheetChanged)
- result.setColor(QPalette::Text, textColor);
- if (standardPalette.color(QPalette::BrightText) != result.color(QPalette::BrightText) || styleSheetChanged)
- result.setColor(QPalette::BrightText, btnHighlight);
- if (standardPalette.color(QPalette::Base) == result.color(QPalette::Base) || styleSheetChanged)
- result.setColor(QPalette::Base, btnFace);
- if (standardPalette.color(QPalette::Window) == result.color(QPalette::Window) || styleSheetChanged)
- result.setColor(QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF));
- if (standardPalette.color(QPalette::ButtonText) == result.color(QPalette::ButtonText) || styleSheetChanged)
- result.setColor(QPalette::ButtonText, textColor);
- if (standardPalette.color(QPalette::Midlight) == result.color(QPalette::Midlight) || styleSheetChanged)
- result.setColor(QPalette::Midlight, btnColor.lighter(125));
- if (standardPalette.color(QPalette::Shadow) == result.color(QPalette::Shadow) || styleSheetChanged)
- result.setColor(QPalette::Shadow, Qt::black);
- if (standardPalette.color(QPalette::ToolTipBase) == result.color(QPalette::ToolTipBase) || styleSheetChanged)
- result.setColor(QPalette::ToolTipBase, result.window().color());
- if (standardPalette.color(QPalette::ToolTipText) == result.color(QPalette::ToolTipText) || styleSheetChanged)
- result.setColor(QPalette::ToolTipText, result.windowText().color());
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Highlight, btnHighlight);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::WindowText, textColor);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Button, btnFace);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Light, btnColor.lighter(150));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Dark, btnColor.darker(200));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Mid, btnColor.darker(150));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Text, textColor);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::BrightText, btnHighlight);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Base, btnFace);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::ButtonText, textColor);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Midlight, btnColor.lighter(125));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Shadow, Qt::black);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::ToolTipBase, result.window().color());
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::ToolTipText, result.windowText().color());
if (result.midlight() == result.button())
result.setColor(QPalette::Midlight, btnColor.lighter(110));
@@ -2090,35 +2115,30 @@ static void populateLightSystemBasePalette(QPalette &result)
/*!
\internal
*/
-void QWindows11Style::polish(QPalette& pal)
+void QWindows11Style::polish(QPalette& result)
{
- highContrastTheme = QGuiApplicationPrivate::colorScheme() == Qt::ColorScheme::Unknown;
- colorSchemeIndex = QGuiApplicationPrivate::colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
+ highContrastTheme = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Unknown;
+ colorSchemeIndex = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
if (!highContrastTheme && colorSchemeIndex == 0)
- populateLightSystemBasePalette(pal);
-
- if (standardPalette().color(QPalette::Inactive, QPalette::Button) == pal.color(QPalette::Inactive, QPalette::Button))
- pal.setColor(QPalette::Inactive, QPalette::Button, pal.button().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::Window) == pal.color(QPalette::Inactive, QPalette::Window))
- pal.setColor(QPalette::Inactive, QPalette::Window, pal.window().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::Light) == pal.color(QPalette::Inactive, QPalette::Light))
- pal.setColor(QPalette::Inactive, QPalette::Light, pal.light().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::Dark) == pal.color(QPalette::Inactive, QPalette::Dark))
- pal.setColor(QPalette::Inactive, QPalette::Dark, pal.dark().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::Accent) == pal.color(QPalette::Inactive, QPalette::Accent))
- pal.setColor(QPalette::Inactive, QPalette::Accent, pal.accent().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::Highlight) == pal.color(QPalette::Inactive, QPalette::Highlight))
- pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.highlight().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::HighlightedText) == pal.color(QPalette::Inactive, QPalette::HighlightedText))
- pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.highlightedText().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::Text) == pal.color(QPalette::Inactive, QPalette::Text))
- pal.setColor(QPalette::Inactive, QPalette::Text, pal.text().color());
- if (standardPalette().color(QPalette::Inactive, QPalette::WindowText) == pal.color(QPalette::Inactive, QPalette::WindowText))
- pal.setColor(QPalette::Inactive, QPalette::WindowText, pal.windowText().color());
+ populateLightSystemBasePalette(result);
+
+ const bool styleSheetChanged = false; // so the macro works
+
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Button, result.button().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Window, result.window().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Light, result.light().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Dark, result.dark().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Accent, result.accent().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Highlight, result.highlight().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::HighlightedText, result.highlightedText().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Text, result.text().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::WindowText, result.windowText().color());
if (highContrastTheme)
- pal.setColor(QPalette::Active, QPalette::HighlightedText, pal.windowText().color());
+ result.setColor(QPalette::Active, QPalette::HighlightedText, result.windowText().color());
}
+#undef SET_IF_UNRESOLVED
+
QT_END_NAMESPACE
diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h
index 90e368f1ea..9c54afd967 100644
--- a/src/plugins/styles/modernwindows/qwindows11style_p.h
+++ b/src/plugins/styles/modernwindows/qwindows11style_p.h
@@ -48,6 +48,7 @@ public:
int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr,
const QWidget *widget = nullptr) const override;
void polish(QPalette &pal) override;
+ void unpolish(QWidget *widget) override;
protected:
QWindows11Style(QWindows11StylePrivate &dd);
private:
diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
index 1df134b629..beee1d6f31 100644
--- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
@@ -4755,7 +4755,7 @@ void QWindowsVistaStyle::polish(QPalette &pal)
{
Q_D(QWindowsVistaStyle);
- if (QGuiApplicationPrivate::colorScheme() == Qt::ColorScheme::Dark) {
+ if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
// System runs in dark mode, but the Vista style cannot use a dark palette.
// Overwrite with the light system palette.
using QWindowsApplication = QNativeInterface::Private::QWindowsApplication;
diff --git a/src/printsupport/dialogs/qpagesetupdialog_win.cpp b/src/printsupport/dialogs/qpagesetupdialog_win.cpp
index 0f3011a638..1d2fdc98b7 100644
--- a/src/printsupport/dialogs/qpagesetupdialog_win.cpp
+++ b/src/printsupport/dialogs/qpagesetupdialog_win.cpp
@@ -123,10 +123,10 @@ int QPageSetupDialog::exec()
pageSize = QPageSize(unitSize, layout.units() == QPageLayout::Inch
? QPageSize::Inch : QPageSize::Millimeter);
}
- layout.setPageSize(pageSize);
+ layout.setPageSize(pageSize, layout.minimumMargins());
const QMarginsF margins(psd.rtMargin.left, psd.rtMargin.top, psd.rtMargin.right, psd.rtMargin.bottom);
- layout.setMargins(margins / multiplier);
+ layout.setMargins(margins / multiplier, QPageLayout::OutOfBoundsPolicy::Clamp);
d->printer->setPageLayout(layout);
// copy from our temp DEVMODE struct
diff --git a/src/printsupport/kernel/qprintengine_pdf.cpp b/src/printsupport/kernel/qprintengine_pdf.cpp
index 9dec15ae5b..3e50247186 100644
--- a/src/printsupport/kernel/qprintengine_pdf.cpp
+++ b/src/printsupport/kernel/qprintengine_pdf.cpp
@@ -184,7 +184,8 @@ void QPdfPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
Q_ASSERT(margins.size() == 4);
d->m_pageLayout.setUnits(QPageLayout::Point);
d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
- margins.at(2).toReal(), margins.at(3).toReal()));
+ margins.at(2).toReal(), margins.at(3).toReal()),
+ QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageSize: {
@@ -196,7 +197,7 @@ void QPdfPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
case PPK_QPageMargins: {
QPair<QMarginsF, QPageLayout::Unit> pair = qvariant_cast<QPair<QMarginsF, QPageLayout::Unit> >(value);
d->m_pageLayout.setUnits(pair.second);
- d->m_pageLayout.setMargins(pair.first);
+ d->m_pageLayout.setMargins(pair.first, QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageLayout: {
diff --git a/src/printsupport/platform/macos/qprintengine_mac.mm b/src/printsupport/platform/macos/qprintengine_mac.mm
index 1e6ca5ba26..d6eb71f66d 100644
--- a/src/printsupport/platform/macos/qprintengine_mac.mm
+++ b/src/printsupport/platform/macos/qprintengine_mac.mm
@@ -576,7 +576,8 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
QList<QVariant> margins(value.toList());
Q_ASSERT(margins.size() == 4);
d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
- margins.at(2).toReal(), margins.at(3).toReal()));
+ margins.at(2).toReal(), margins.at(3).toReal()),
+ QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageSize:
@@ -585,7 +586,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
case PPK_QPageMargins: {
QPair<QMarginsF, QPageLayout::Unit> pair = value.value<QPair<QMarginsF, QPageLayout::Unit> >();
d->m_pageLayout.setUnits(pair.second);
- d->m_pageLayout.setMargins(pair.first);
+ d->m_pageLayout.setMargins(pair.first, QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageLayout: {
@@ -595,7 +596,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
setProperty(PPK_FullPage, pageLayout.mode() == QPageLayout::FullPageMode);
setProperty(PPK_Orientation, QVariant::fromValue(pageLayout.orientation()));
d->m_pageLayout.setUnits(pageLayout.units());
- d->m_pageLayout.setMargins(pageLayout.margins());
+ d->m_pageLayout.setMargins(pageLayout.margins(), QPageLayout::OutOfBoundsPolicy::Clamp);
}
break;
}
diff --git a/src/printsupport/platform/windows/qprintengine_win.cpp b/src/printsupport/platform/windows/qprintengine_win.cpp
index d11f20dde2..fa8d03a615 100644
--- a/src/printsupport/platform/windows/qprintengine_win.cpp
+++ b/src/printsupport/platform/windows/qprintengine_win.cpp
@@ -1285,7 +1285,8 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
Q_ASSERT(margins.size() == 4);
d->m_pageLayout.setUnits(QPageLayout::Point);
d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
- margins.at(2).toReal(), margins.at(3).toReal()));
+ margins.at(2).toReal(), margins.at(3).toReal()),
+ QPageLayout::OutOfBoundsPolicy::Clamp);
d->updateMetrics();
#ifdef QT_DEBUG_METRICS
qDebug() << "QWin32PrintEngine::setProperty(PPK_PageMargins," << margins << ')';
@@ -1313,7 +1314,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
case PPK_QPageMargins: {
QPair<QMarginsF, QPageLayout::Unit> pair = value.value<QPair<QMarginsF, QPageLayout::Unit> >();
d->m_pageLayout.setUnits(pair.second);
- d->m_pageLayout.setMargins(pair.first);
+ d->m_pageLayout.setMargins(pair.first, QPageLayout::OutOfBoundsPolicy::Clamp);
d->updateMetrics();
#ifdef QT_DEBUG_METRICS
qDebug() << "QWin32PrintEngine::setProperty(PPK_QPageMargins," << pair.first << pair.second << ')';
@@ -1329,7 +1330,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
setProperty(PPK_FullPage, pageLayout.mode() == QPageLayout::FullPageMode);
setProperty(PPK_Orientation, QVariant::fromValue(pageLayout.orientation()));
d->m_pageLayout.setUnits(pageLayout.units());
- d->m_pageLayout.setMargins(pageLayout.margins());
+ d->m_pageLayout.setMargins(pageLayout.margins(), QPageLayout::OutOfBoundsPolicy::Clamp);
d->updateMetrics();
#ifdef QT_DEBUG_METRICS
qDebug() << "QWin32PrintEngine::setProperty(PPK_QPageLayout," << pageLayout << ')';
diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp
index da5c51e770..fdbb16a589 100644
--- a/src/sql/kernel/qsqldatabase.cpp
+++ b/src/sql/kernel/qsqldatabase.cpp
@@ -7,6 +7,7 @@
#include "qcoreapplication.h"
#include "qreadwritelock.h"
#include "qsqldriver.h"
+#include "qsqldriver_p.h"
#include "qsqldriverplugin.h"
#include "qsqlindex.h"
#include "QtCore/qapplicationstatic.h"
@@ -122,7 +123,7 @@ QSqlDatabasePrivate::~QSqlDatabasePrivate()
QtSqlGlobals::~QtSqlGlobals()
{
qDeleteAll(registeredDrivers);
- for (const auto &[k, v] : connections.asKeyValueRange())
+ for (const auto &[k, v] : std::as_const(connections).asKeyValueRange())
QSqlDatabasePrivate::invalidateDb(v, k, false);
}
@@ -282,6 +283,10 @@ void QSqlDatabasePrivate::disable()
QSqlDriver. Alternatively, you can subclass your own database
driver from QSqlDriver. See \l{How to Write Your Own Database
Driver} for more information.
+ A QSqlDatabase instance must only be accessed by the thread it
+ was created in. Therefore you have to make sure to create them
+ in the correct context. Alternatively you can change the context
+ with QSqlDatabase::moveToThread().
Create a connection (i.e., an instance of QSqlDatabase) by calling
one of the static addDatabase() functions, where you specify
@@ -1333,6 +1338,50 @@ QSql::NumericalPrecisionPolicy QSqlDatabase::numericalPrecisionPolicy() const
return d->precisionPolicy;
}
+/*!
+ \since 6.8
+
+ Changes the thread affinity for QSqlDatabase and its associated driver.
+ This function returns \c true when the function succeeds. Event processing
+ will continue in the \a targetThread.
+
+ During this operation you have to make sure that there is no QSqlQuery
+ bound to this instance otherwise the QSqlDatabase will not be moved to
+ the given thread and the function returns \c false.
+
+ Since the associated driver is derived from QObject, all constraints for
+ moving a QObject to another thread also apply to this function.
+
+ \sa QObject::moveToThread(), {Threads and the SQL Module}
+*/
+bool QSqlDatabase::moveToThread(QThread *targetThread)
+{
+ if (auto drv = driver()) {
+ if (drv != QSqlDatabasePrivate::shared_null()->driver) {
+ // two instances are alive - the one here and the one in dbDict()
+ if (d->ref.loadRelaxed() > 2) {
+ qWarning("QSqlDatabasePrivate::moveToThread: connection '%ls' is still in use "
+ "in the current thread.", qUtf16Printable(d->connName));
+ return false;
+ }
+ return drv->moveToThread(targetThread);
+ }
+ }
+ return false;
+}
+
+/*!
+ \since 6.8
+
+ Returns a pointer to the associated QThread instance.
+*/
+QThread *QSqlDatabase::currentThread() const
+{
+ if (auto drv = driver())
+ return drv->thread();
+ return nullptr;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QSqlDatabase &d)
diff --git a/src/sql/kernel/qsqldatabase.h b/src/sql/kernel/qsqldatabase.h
index 10019c7d5c..5059dbba83 100644
--- a/src/sql/kernel/qsqldatabase.h
+++ b/src/sql/kernel/qsqldatabase.h
@@ -18,6 +18,7 @@ class QSqlIndex;
class QSqlRecord;
class QSqlQuery;
class QSqlDatabasePrivate;
+class QThread;
class Q_SQL_EXPORT QSqlDriverCreatorBase
{
@@ -80,6 +81,8 @@ public:
QString connectionName() const;
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ bool moveToThread(QThread *targetThread);
+ QThread *currentThread() const;
QSqlDriver* driver() const;
diff --git a/src/sql/kernel/qsqlindex.cpp b/src/sql/kernel/qsqlindex.cpp
index 26553155cc..15ee489928 100644
--- a/src/sql/kernel/qsqlindex.cpp
+++ b/src/sql/kernel/qsqlindex.cpp
@@ -149,24 +149,6 @@ void QSqlIndex::setDescending(int i, bool desc)
sorts[i] = desc;
}
-/*! \internal
-
- Creates a string representing the field number \a i using prefix \a
- prefix. If \a verbose is true, ASC or DESC is included in the field
- description if the field is sorted in ASCending or DESCending order.
-*/
-
-QString QSqlIndex::createField(int i, const QString& prefix, bool verbose) const
-{
- QString f;
- if (!prefix.isEmpty())
- f += prefix + u'.';
- f += field(i).name();
- if (verbose)
- f += u' ' + QString((isDescending(i) ? "DESC"_L1 : "ASC"_L1));
- return f;
-}
-
/*!
\property QSqlIndex::cursorName
\since 6.8
diff --git a/src/sql/kernel/qsqlindex.h b/src/sql/kernel/qsqlindex.h
index 409cb463e3..3d5d95b373 100644
--- a/src/sql/kernel/qsqlindex.h
+++ b/src/sql/kernel/qsqlindex.h
@@ -47,7 +47,6 @@ public:
void setDescending(int i, bool desc);
private:
- QString createField(int i, const QString& prefix, bool verbose) const;
// ### Qt7: move to d-ptr
QString cursor;
QString nm;
diff --git a/src/testlib/CMakeLists.txt b/src/testlib/CMakeLists.txt
index 2c33883c96..e956a47cf1 100644
--- a/src/testlib/CMakeLists.txt
+++ b/src/testlib/CMakeLists.txt
@@ -13,6 +13,7 @@ qt_internal_add_module(Test
EXCEPTIONS
SOURCES
3rdparty/cycle_p.h
+ removed_api.cpp # keep first
qabstracttestlogger.cpp qabstracttestlogger_p.h
qasciikey.cpp
qbenchmark.cpp qbenchmark.h qbenchmark_p.h
@@ -56,6 +57,7 @@ qt_internal_add_module(Test
qtestsystem.h
qtesttable.cpp qtesttable_p.h
qtesttouch.h
+ qtesttostring.h
qtestwheel.h
qttestglobal.h
qxmltestlogger.cpp qxmltestlogger_p.h
@@ -70,6 +72,8 @@ qt_internal_add_module(Test
QT_NO_MESSAGELOGCONTEXT
LIBRARIES
Qt::CorePrivate
+ NO_PCH_SOURCES
+ removed_api.cpp
PUBLIC_LIBRARIES
Qt::Core
PRIVATE_MODULE_INTERFACE
diff --git a/src/testlib/doc/src/qttestlib-manual.qdoc b/src/testlib/doc/src/qttestlib-manual.qdoc
index 9f650496bb..1b6f534045 100644
--- a/src/testlib/doc/src/qttestlib-manual.qdoc
+++ b/src/testlib/doc/src/qttestlib-manual.qdoc
@@ -589,7 +589,5 @@
\li \l {Chapter 6: Skipping Tests with QSKIP}{Skipping Tests}
\endlist
- \note You can build and execute the tests from each chapter using the
- available source code, which is linked to at the end of each chapter.
*/
diff --git a/src/testlib/qcomparisontesthelper_p.h b/src/testlib/qcomparisontesthelper_p.h
index b422fc4049..afeb1088c4 100644
--- a/src/testlib/qcomparisontesthelper_p.h
+++ b/src/testlib/qcomparisontesthelper_p.h
@@ -167,7 +167,8 @@ void testAllComparisonOperatorsCompile()
Basic testing of equality operators.
The helper function tests {in}equality operators (== and !=) for the \a lhs
- operand of type \c {LeftType} and the \a rhs operand of type \c {RightType}.
+ operand of type \c {LeftType} and the \a rhs operand of type \c {RightType},
+ plus the reverse order of the operands.
The \a expectedEqual parameter is an expected result for \c {operator==()}.
@@ -187,10 +188,8 @@ void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual)
{
CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, ==, expectedEqual);
CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, !=, !expectedEqual);
- if constexpr (!std::is_same_v<LeftType, RightType>) {
- CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==, expectedEqual);
- CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=, !expectedEqual);
- }
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==, expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=, !expectedEqual);
}
/*!
@@ -199,7 +198,8 @@ void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual)
The helper function tests all six relation and equality operators
(==, !=, <, >, <=, >=) for the \a lhs operand of type \c {LeftType} and
- the \a rhs operand of type \c {RightType}.
+ the \a rhs operand of type \c {RightType} and all six for the reverse
+ order of the operands.
If compiled in C++20 mode, also checks \c {operator<=>()} if that is
implemented.
@@ -283,7 +283,6 @@ void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expect
}
#endif
- if constexpr (!std::is_same_v<LeftType, RightType>) {
CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==,
!expectedUnordered && expectedEqual);
CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=,
@@ -319,7 +318,6 @@ void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expect
!expectedUnordered && (expectedEqual || expectedLess));
}
#endif
- }
}
#ifdef __cpp_lib_three_way_comparison
diff --git a/src/testlib/qsignalspy.cpp b/src/testlib/qsignalspy.cpp
index 13c34c7751..116ce87c3e 100644
--- a/src/testlib/qsignalspy.cpp
+++ b/src/testlib/qsignalspy.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsignalspy.h"
@@ -110,10 +110,6 @@ QT_BEGIN_NAMESPACE
Returns the normalized signal the spy is currently listening to.
*/
-/*! \fn int QSignalSpy::qt_metacall(QMetaObject::Call call, int id, void **a)
- \internal
-*/
-
/*! \fn bool QSignalSpy::wait(int timeout)
\since 5.0
@@ -127,7 +123,7 @@ QT_BEGIN_NAMESPACE
otherwise returns \c false.
*/
-/*! \fn bool QSignalSpy::wait(std::chrono::milliseconds timeout)
+/*!
\since 6.6
Starts an event loop that runs until the given signal is received
@@ -146,5 +142,176 @@ QT_BEGIN_NAMESPACE
spy.wait(2s);
\endcode
*/
+bool QSignalSpy::wait(std::chrono::milliseconds timeout)
+{
+ QMutexLocker locker(&m_mutex);
+ Q_ASSERT(!m_waiting);
+ const qsizetype origCount = size();
+ m_waiting = true;
+ locker.unlock();
+
+ m_loop.enterLoop(timeout);
+
+ locker.relock();
+ m_waiting = false;
+ return size() > origCount;
+}
+
+static bool isSignalMetaMethodValid(QMetaMethod signal)
+{
+ if (!signal.isValid()) {
+ qWarning("QSignalSpy: Null signal is not valid");
+ return false;
+ }
+
+ if (signal.methodType() != QMetaMethod::Signal) {
+ qWarning("QSignalSpy: Not a signal: '%s'", signal.methodSignature().constData());
+ return false;
+ }
+
+ return true;
+}
+
+static bool isObjectValid(const QObject *object)
+{
+ const bool valid = !!object;
+
+ if (!valid)
+ qWarning("QSignalSpy: Cannot spy on a null object");
+
+ return valid;
+}
+
+QSignalSpy::ObjectSignal QSignalSpy::verify(const QObject *obj, const char *aSignal)
+{
+ if (!isObjectValid(obj))
+ return {};
+
+ if (!aSignal) {
+ qWarning("QSignalSpy: Null signal name is not valid");
+ return {};
+ }
+
+ if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
+ qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
+ return {};
+ }
+
+ const QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
+ const QMetaObject * const mo = obj->metaObject();
+ const int sigIndex = mo->indexOfMethod(ba.constData());
+ if (sigIndex < 0) {
+ qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
+ return {};
+ }
+
+ return verify(obj, mo->method(sigIndex));
+}
+
+QSignalSpy::ObjectSignal QSignalSpy::verify(const QObject *obj, QMetaMethod signal)
+{
+ if (isObjectValid(obj) && isSignalMetaMethodValid(signal))
+ return {obj, signal};
+ else
+ return {};
+}
+
+static QList<int> makeArgs(QMetaMethod member, const QObject *obj)
+{
+ QList<int> result;
+ result.reserve(member.parameterCount());
+ for (int i = 0; i < member.parameterCount(); ++i) {
+ QMetaType tp = member.parameterMetaType(i);
+ if (!tp.isValid() && obj) {
+ void *argv[] = { &tp, &i };
+ QMetaObject::metacall(const_cast<QObject*>(obj),
+ QMetaObject::RegisterMethodArgumentMetaType,
+ member.methodIndex(), argv);
+ }
+ if (!tp.isValid()) {
+ qWarning("QSignalSpy: Unable to handle parameter '%s' of type '%s' of method '%s',"
+ " use qRegisterMetaType to register it.",
+ member.parameterNames().at(i).constData(),
+ member.parameterTypes().at(i).constData(),
+ member.name().constData());
+ }
+ result.append(tp.id());
+ }
+ return result;
+}
+
+class QSignalSpyPrivate : public QObject
+{
+ QSignalSpy * const q;
+public:
+ explicit QSignalSpyPrivate(QSignalSpy *qq) : q(qq) {}
+
+ int qt_metacall(QMetaObject::Call call, int methodId, void **a) override;
+};
+
+QSignalSpy::QSignalSpy(ObjectSignal os)
+ : sig(os.sig.methodSignature()),
+ args(os.obj ? makeArgs(os.sig, os.obj) : QList<int>{})
+{
+ if (!os.obj)
+ return;
+
+ auto i = std::make_unique<QSignalSpyPrivate>(this);
+
+ const auto signalIndex = os.sig.methodIndex();
+ const auto slotIndex = QObject::staticMetaObject.methodCount();
+ if (!QMetaObject::connect(os.obj, signalIndex,
+ i.get(), slotIndex, Qt::DirectConnection)) {
+ qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
+ return;
+ }
+
+ d_ptr = std::move(i);
+}
+
+/*!
+ Destructor.
+*/
+QSignalSpy::~QSignalSpy()
+ = default;
+
+void QSignalSpy::appendArgs(void **a)
+{
+ QList<QVariant> list;
+ list.reserve(args.size());
+ for (qsizetype i = 0; i < args.size(); ++i) {
+ const QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
+ if (type == QMetaType::QVariant)
+ list << *reinterpret_cast<QVariant *>(a[i + 1]);
+ else
+ list << QVariant(QMetaType(type), a[i + 1]);
+ }
+ QMutexLocker locker(&m_mutex);
+ append(std::move(list));
+
+ if (m_waiting) {
+ locker.unlock();
+ m_loop.exitLoop();
+ }
+}
+
+/*!
+ \reimp
+ \internal
+*/
+int QSignalSpyPrivate::qt_metacall(QMetaObject::Call call, int methodId, void **a)
+{
+ methodId = QObject::qt_metacall(call, methodId, a);
+ if (methodId < 0)
+ return methodId;
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ if (methodId == 0) {
+ q->appendArgs(a);
+ }
+ --methodId;
+ }
+ return methodId;
+}
QT_END_NAMESPACE
diff --git a/src/testlib/qsignalspy.h b/src/testlib/qsignalspy.h
index 7809ac3f71..b8df2a4deb 100644
--- a/src/testlib/qsignalspy.h
+++ b/src/testlib/qsignalspy.h
@@ -6,56 +6,29 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qlist.h>
-#include <QtCore/qobject.h>
#include <QtCore/qmetaobject.h>
#include <QtTest/qtesteventloop.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmutex.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QVariant;
-
-class QSignalSpy: public QObject, public QList<QList<QVariant> >
+class QSignalSpyPrivate;
+class QSignalSpy : public QList<QList<QVariant> >
{
struct ObjectSignal {
const QObject *obj;
QMetaMethod sig;
};
-
+ friend class QSignalSpyPrivate;
+ std::unique_ptr<QSignalSpyPrivate> d_ptr;
public:
explicit QSignalSpy(const QObject *obj, const char *aSignal)
: QSignalSpy(verify(obj, aSignal)) {}
-
-private:
- static ObjectSignal verify(const QObject *obj, const char *aSignal)
- {
- if (!isObjectValid(obj))
- return {};
-
- if (!aSignal) {
- qWarning("QSignalSpy: Null signal name is not valid");
- return {};
- }
-
- if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
- qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
- return {};
- }
-
- const QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
- const QMetaObject * const mo = obj->metaObject();
- const int sigIndex = mo->indexOfMethod(ba.constData());
- if (sigIndex < 0) {
- qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
- return {};
- }
-
- return verify(obj, mo->method(sigIndex));
- }
-
-public:
#ifdef Q_QDOC
template <typename PointerToMemberFunction>
QSignalSpy(const QObject *object, PointerToMemberFunction signal);
@@ -64,158 +37,34 @@ public:
QSignalSpy(const typename QtPrivate::FunctionPointer<Func>::Object *obj, Func signal0)
: QSignalSpy(verify(obj, QMetaMethod::fromSignal(signal0))) {}
#endif // Q_QDOC
-
QSignalSpy(const QObject *obj, QMetaMethod signal)
: QSignalSpy(verify(obj, signal)) {}
+ Q_TESTLIB_EXPORT ~QSignalSpy();
-private:
- static ObjectSignal verify(const QObject *obj, QMetaMethod signal)
- {
- if (isObjectValid(obj) && isSignalMetaMethodValid(signal))
- return {obj, signal};
- else
- return {};
- }
-
-public:
- inline bool isValid() const { return !sig.isEmpty(); }
+ bool isValid() const noexcept { return d_ptr != nullptr; }
inline QByteArray signal() const { return sig; }
bool wait(int timeout)
{ return wait(std::chrono::milliseconds{timeout}); }
- bool wait(std::chrono::milliseconds timeout = std::chrono::seconds{5})
- {
- QMutexLocker locker(&m_mutex);
- Q_ASSERT(!m_waiting);
- const qsizetype origCount = size();
- m_waiting = true;
- locker.unlock();
-
- m_loop.enterLoop(timeout);
-
- locker.relock();
- m_waiting = false;
- return size() > origCount;
- }
-
- int qt_metacall(QMetaObject::Call call, int methodId, void **a) override
- {
- methodId = QObject::qt_metacall(call, methodId, a);
- if (methodId < 0)
- return methodId;
-
- if (call == QMetaObject::InvokeMetaMethod) {
- if (methodId == 0) {
- appendArgs(a);
- }
- --methodId;
- }
- return methodId;
- }
+ Q_TESTLIB_EXPORT bool wait(std::chrono::milliseconds timeout = std::chrono::seconds{5});
private:
- explicit QSignalSpy(ObjectSignal os)
- {
- if (!os.obj)
- return;
- initArgs(os.sig, os.obj);
- if (!connectToSignal(os.obj, os.sig.methodIndex()))
- return;
-
- sig = os.sig.methodSignature();
- }
-
- bool connectToSignal(const QObject *sender, int sigIndex)
- {
- static const int memberOffset = QObject::staticMetaObject.methodCount();
- const bool connected = QMetaObject::connect(
- sender, sigIndex, this, memberOffset, Qt::DirectConnection, nullptr);
-
- if (!connected)
- qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
-
- return connected;
- }
-
- static bool isSignalMetaMethodValid(const QMetaMethod &signal)
- {
- if (!signal.isValid()) {
- qWarning("QSignalSpy: Null signal is not valid");
- return false;
- }
-
- if (signal.methodType() != QMetaMethod::Signal) {
- qWarning("QSignalSpy: Not a signal: '%s'", signal.methodSignature().constData());
- return false;
- }
-
- return true;
- }
-
- static bool isObjectValid(const QObject *object)
- {
- const bool valid = !!object;
-
- if (!valid)
- qWarning("QSignalSpy: Cannot spy on a null object");
-
- return valid;
- }
-
- void initArgs(const QMetaMethod &member, const QObject *obj)
- {
- QMutexLocker locker(&m_mutex);
- args.reserve(member.parameterCount());
- for (int i = 0; i < member.parameterCount(); ++i) {
- QMetaType tp = member.parameterMetaType(i);
- if (!tp.isValid() && obj) {
- locker.unlock();
- void *argv[] = { &tp, &i };
- QMetaObject::metacall(const_cast<QObject*>(obj),
- QMetaObject::RegisterMethodArgumentMetaType,
- member.methodIndex(), argv);
- locker.relock();
- }
- if (!tp.isValid()) {
- qWarning("QSignalSpy: Unable to handle parameter '%s' of type '%s' of method '%s',"
- " use qRegisterMetaType to register it.",
- member.parameterNames().at(i).constData(),
- member.parameterTypes().at(i).constData(),
- member.name().constData());
- }
- args << tp.id();
- }
- }
-
- void appendArgs(void **a)
- {
- QMutexLocker locker(&m_mutex);
- QList<QVariant> list;
- list.reserve(args.size());
- for (qsizetype i = 0; i < args.size(); ++i) {
- const QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
- if (type == QMetaType::QVariant)
- list << *reinterpret_cast<QVariant *>(a[i + 1]);
- else
- list << QVariant(QMetaType(type), a[i + 1]);
- }
- append(std::move(list));
-
- if (m_waiting) {
- locker.unlock();
- m_loop.exitLoop();
- }
- }
+ Q_TESTLIB_EXPORT explicit QSignalSpy(ObjectSignal os);
+
+ Q_TESTLIB_EXPORT static ObjectSignal verify(const QObject *obj, QMetaMethod signal);
+ Q_TESTLIB_EXPORT static ObjectSignal verify(const QObject *obj, const char *aSignal);
+
+ Q_TESTLIB_EXPORT void appendArgs(void **a);
// the full, normalized signal name
- QByteArray sig;
+ const QByteArray sig;
// holds the QMetaType types for the argument list of the signal
- QList<int> args;
+ const QList<int> args;
QTestEventLoop m_loop;
bool m_waiting = false;
- QMutex m_mutex; // protects m_waiting, args and the QList base class, between appendArgs() and wait()
+ QMutex m_mutex; // protects m_waiting and the QList base class, between appendArgs() and wait()
};
QT_END_NAMESPACE
diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h
index 99eae8553f..ff3744a48e 100644
--- a/src/testlib/qtest.h
+++ b/src/testlib/qtest.h
@@ -12,34 +12,13 @@
#include <QtTest/qttestglobal.h>
#include <QtTest/qtestcase.h>
#include <QtTest/qtestdata.h>
+#include <QtTest/qtesttostring.h>
#include <QtTest/qbenchmark.h>
-#include <QtCore/qbitarray.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qcborarray.h>
-#include <QtCore/qcborcommon.h>
-#include <QtCore/qcbormap.h>
-#include <QtCore/qcborvalue.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qcborcommon.h>
-#include <QtCore/qdatetime.h>
-#if QT_CONFIG(itemmodel)
-#include <QtCore/qabstractitemmodel.h>
-#endif
-#include <QtCore/qobject.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qurl.h>
-#include <QtCore/quuid.h>
-
#if defined(TESTCASE_LOWDPI)
#include <QtCore/qcoreapplication.h>
#endif
-#include <QtCore/qpoint.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qrect.h>
-
#include <initializer_list>
#include <memory>
@@ -48,358 +27,6 @@ QT_BEGIN_NAMESPACE
namespace QTest
{
-template <> inline char *toString(const QStringView &str)
-{
- return QTest::toPrettyUnicode(str);
-}
-
-template<> inline char *toString(const QString &str)
-{
- return toString(QStringView(str));
-}
-
-template<> inline char *toString(const QLatin1StringView &str)
-{
- return toString(QString(str));
-}
-
-template<> inline char *toString(const QByteArray &ba)
-{
- return QTest::toPrettyCString(ba.constData(), ba.size());
-}
-
-template<> inline char *toString(const QBitArray &ba)
-{
- qsizetype size = ba.size();
- char *str = new char[size + 1];
- for (qsizetype i = 0; i < size; ++i)
- str[i] = "01"[ba.testBit(i)];
- str[size] = '\0';
- return str;
-}
-
-#if QT_CONFIG(datestring)
-template<> inline char *toString(const QTime &time)
-{
- return time.isValid()
- ? qstrdup(qPrintable(time.toString(u"hh:mm:ss.zzz")))
- : qstrdup("Invalid QTime");
-}
-
-template<> inline char *toString(const QDate &date)
-{
- return date.isValid()
- ? qstrdup(qPrintable(date.toString(u"yyyy/MM/dd")))
- : qstrdup("Invalid QDate");
-}
-
-template<> inline char *toString(const QDateTime &dateTime)
-{
- return dateTime.isValid()
- ? qstrdup(qPrintable(dateTime.toString(u"yyyy/MM/dd hh:mm:ss.zzz[t]")))
- : qstrdup("Invalid QDateTime");
-}
-#endif // datestring
-
-template<> inline char *toString(const QCborError &c)
-{
- // use the Q_ENUM formatting
- return toString(c.c);
-}
-
-template<> inline char *toString(const QChar &c)
-{
- const ushort uc = c.unicode();
- if (uc < 128) {
- char msg[32] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
- return qstrdup(msg);
- }
- return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
-}
-
-#if QT_CONFIG(itemmodel)
-template<> inline char *toString(const QModelIndex &idx)
-{
- char msg[128];
- qsnprintf(msg, sizeof(msg), "QModelIndex(%d,%d,%p,%p)", idx.row(), idx.column(), idx.internalPointer(), idx.model());
- return qstrdup(msg);
-}
-#endif
-
-template<> inline char *toString(const QPoint &p)
-{
- char msg[128] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QSize &s)
-{
- char msg[128] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QRect &s)
-{
- char msg[256] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
- s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QPointF &p)
-{
- char msg[64] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QSizeF &s)
-{
- char msg[64] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QRectF &s)
-{
- char msg[256] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
- s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QUrl &uri)
-{
- if (!uri.isValid())
- return qstrdup(qPrintable(QLatin1StringView("Invalid URL: ") + uri.errorString()));
- return qstrdup(uri.toEncoded().constData());
-}
-
-template <> inline char *toString(const QUuid &uuid)
-{
- return qstrdup(uuid.toByteArray().constData());
-}
-
-template<> inline char *toString(const QVariant &v)
-{
- QByteArray vstring("QVariant(");
- if (v.isValid()) {
- QByteArray type(v.typeName());
- if (type.isEmpty()) {
- type = QByteArray::number(v.userType());
- }
- vstring.append(type);
- if (!v.isNull()) {
- vstring.append(',');
- if (v.canConvert<QString>()) {
- vstring.append(v.toString().toLocal8Bit());
- }
- else {
- vstring.append("<value not representable as string>");
- }
- }
- }
- vstring.append(')');
-
- return qstrdup(vstring.constData());
-}
-
-template<> inline char *toString(const QPartialOrdering &o)
-{
- if (o == QPartialOrdering::Less)
- return qstrdup("Less");
- if (o == QPartialOrdering::Equivalent)
- return qstrdup("Equivalent");
- if (o == QPartialOrdering::Greater)
- return qstrdup("Greater");
- if (o == QPartialOrdering::Unordered)
- return qstrdup("Unordered");
- return qstrdup("<invalid>");
-}
-
-namespace Internal {
-struct QCborValueFormatter
-{
- enum { BufferLen = 256 };
- static char *formatSimpleType(QCborSimpleType st)
- {
- char *buf = new char[BufferLen];
- qsnprintf(buf, BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
- return buf;
- }
-
- static char *formatTag(QCborTag tag, const QCborValue &taggedValue)
- {
- QScopedArrayPointer<char> hold(format(taggedValue));
- char *buf = new char[BufferLen];
- qsnprintf(buf, BufferLen, "QCborValue(QCborTag(%llu), %s)", tag, hold.get());
- return buf;
- }
-
- static char *innerFormat(QCborValue::Type t, const char *str)
- {
- static const QMetaEnum typeEnum = []() {
- int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
- return QCborValue::staticMetaObject.enumerator(idx);
- }();
-
- char *buf = new char[BufferLen];
- const char *typeName = typeEnum.valueToKey(t);
- if (typeName)
- qsnprintf(buf, BufferLen, "QCborValue(%s, %s)", typeName, str);
- else
- qsnprintf(buf, BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
- return buf;
- }
-
- template<typename T> static char *format(QCborValue::Type type, const T &t)
- {
- QScopedArrayPointer<char> hold(QTest::toString(t));
- return innerFormat(type, hold.get());
- }
-
- static char *format(const QCborValue &v)
- {
- switch (v.type()) {
- case QCborValue::Integer:
- return format(v.type(), v.toInteger());
- case QCborValue::ByteArray:
- return format(v.type(), v.toByteArray());
- case QCborValue::String:
- return format(v.type(), v.toString());
- case QCborValue::Array:
- return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toArray())).get());
- case QCborValue::Map:
- return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toMap())).get());
- case QCborValue::Tag:
- return formatTag(v.tag(), v.taggedValue());
- case QCborValue::SimpleType:
- break;
- case QCborValue::True:
- return qstrdup("QCborValue(true)");
- case QCborValue::False:
- return qstrdup("QCborValue(false)");
- case QCborValue::Null:
- return qstrdup("QCborValue(nullptr)");
- case QCborValue::Undefined:
- return qstrdup("QCborValue()");
- case QCborValue::Double:
- return format(v.type(), v.toDouble());
- case QCborValue::DateTime:
- case QCborValue::Url:
- case QCborValue::RegularExpression:
- return format(v.type(), v.taggedValue().toString());
- case QCborValue::Uuid:
- return format(v.type(), v.toUuid());
- case QCborValue::Invalid:
- return qstrdup("QCborValue(<invalid>)");
- }
-
- if (v.isSimpleType())
- return formatSimpleType(v.toSimpleType());
- return innerFormat(v.type(), "");
- }
-
- static char *format(const QCborArray &a)
- {
- QByteArray out(1, '[');
- const char *comma = "";
- for (QCborValueConstRef v : a) {
- QScopedArrayPointer<char> s(format(v));
- out += comma;
- out += s.get();
- comma = ", ";
- }
- out += ']';
- return qstrdup(out.constData());
- }
-
- static char *format(const QCborMap &m)
- {
- QByteArray out(1, '{');
- const char *comma = "";
- for (auto pair : m) {
- QScopedArrayPointer<char> key(format(pair.first));
- QScopedArrayPointer<char> value(format(pair.second));
- out += comma;
- out += key.get();
- out += ": ";
- out += value.get();
- comma = ", ";
- }
- out += '}';
- return qstrdup(out.constData());
- }
-};
-}
-
-template<> inline char *toString(const QCborValue &v)
-{
- return Internal::QCborValueFormatter::format(v);
-}
-
-template<> inline char *toString(const QCborValueRef &v)
-{
- return toString(QCborValue(v));
-}
-
-template<> inline char *toString(const QCborArray &a)
-{
- return Internal::QCborValueFormatter::format(a);
-}
-
-template<> inline char *toString(const QCborMap &m)
-{
- return Internal::QCborValueFormatter::format(m);
-}
-
-template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
-{
- QString r;
- QDebug d(&r);
- d.nospace() << qSetRealNumberPrecision(9) << dur;
- if constexpr (Period::num != 1 || Period::den != 1) {
- // include the equivalent value in seconds, in parentheses
- using namespace std::chrono;
- d << " (" << duration_cast<duration<qreal>>(dur).count() << "s)";
- }
- return qstrdup(std::move(r).toUtf8().constData());
-}
-
-template <typename T1, typename T2>
-inline char *toString(const std::pair<T1, T2> &pair)
-{
- const QScopedArrayPointer<char> first(toString(pair.first));
- const QScopedArrayPointer<char> second(toString(pair.second));
- return formatString("std::pair(", ")", 2, first.data(), second.data());
-}
-
-template <typename Tuple, std::size_t... I>
-inline char *tupleToString(const Tuple &tuple, std::index_sequence<I...>) {
- using UP = std::unique_ptr<char[]>;
- // Generate a table of N + 1 elements where N is the number of
- // elements in the tuple.
- // The last element is needed to support the empty tuple use case.
- const UP data[] = {
- UP(toString(std::get<I>(tuple)))..., UP{}
- };
- return formatString("std::tuple(", ")", sizeof...(I), data[I].get()...);
-}
-
-template <class... Types>
-inline char *toString(const std::tuple<Types...> &tuple)
-{
- return tupleToString(tuple, std::make_index_sequence<sizeof...(Types)>{});
-}
-
-inline char *toString(std::nullptr_t)
-{
- return toString(QStringView(u"nullptr"));
-}
-
template<>
inline bool qCompare(QString const &t1, QLatin1StringView const &t2, const char *actual,
const char *expected, const char *file, int line)
diff --git a/src/testlib/qtest_network.h b/src/testlib/qtest_network.h
index 61f80a536c..403a663ae2 100644
--- a/src/testlib/qtest_network.h
+++ b/src/testlib/qtest_network.h
@@ -4,7 +4,7 @@
#ifndef QTEST_NETWORK_H
#define QTEST_NETWORK_H
-#include <QtTest/qtest.h>
+#include <QtTest/qtesttostring.h>
// enable NETWORK features
#ifndef QT_NETWORK_LIB
@@ -43,6 +43,7 @@ inline char *toString<QHostAddress>(const QHostAddress &addr)
return toString(addr.toString());
}
+} // namespace QTest
inline char *toString(QNetworkReply::NetworkError code)
{
@@ -57,7 +58,7 @@ inline char *toString(QNetworkReply::NetworkError code)
inline char *toString(const QNetworkCookie &cookie)
{
- return toString(cookie.toRawForm());
+ return QTest::toString(cookie.toRawForm());
}
inline char *toString(const QList<QNetworkCookie> &list)
@@ -69,11 +70,9 @@ inline char *toString(const QList<QNetworkCookie> &list)
result.chop(2); // remove trailing ", "
}
result.append(')');
- return toString(result);
+ return QTest::toString(result);
}
-} // namespace QTest
-
QT_END_NAMESPACE
#endif
diff --git a/src/testlib/qtest_widgets.h b/src/testlib/qtest_widgets.h
index 2b60d94fd7..90ee3aa6aa 100644
--- a/src/testlib/qtest_widgets.h
+++ b/src/testlib/qtest_widgets.h
@@ -62,15 +62,16 @@ inline QByteArray toString(QSizePolicy sp)
}
} // namespace Internal
+} // namespace QTest
inline char *toString(QSizePolicy::Policy p)
{
- return qstrdup(Internal::toString(p));
+ return qstrdup(QTest::Internal::toString(p));
}
inline char *toString(QSizePolicy::ControlTypes ct)
{
- return qstrdup(Internal::toString(ct).constData());
+ return qstrdup(QTest::Internal::toString(ct).constData());
}
inline char *toString(QSizePolicy::ControlType ct)
@@ -80,11 +81,9 @@ inline char *toString(QSizePolicy::ControlType ct)
inline char *toString(QSizePolicy sp)
{
- return qstrdup(Internal::toString(sp).constData());
+ return qstrdup(QTest::Internal::toString(sp).constData());
}
-} // namespace QTest
-
QT_END_NAMESPACE
#endif
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 42795fade7..5648fedd63 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -1745,14 +1745,33 @@ void TestMethods::invokeTests(QObject *testObject) const
QSignalDumper::endDump();
}
+#if QT_DEPRECATED_SINCE(6, 8)
+static const char *functionRefFormatter(const void *f)
+{
+ auto formatter = static_cast<const qxp::function_ref<const char *()> *>(f);
+ return (*formatter)();
+};
+
bool reportResult(bool success, qxp::function_ref<const char *()> lhs,
qxp::function_ref<const char *()> rhs,
const char *lhsExpr, const char *rhsExpr,
ComparisonOperation op, const char *file, int line)
{
- return QTestResult::reportResult(success, lhs, rhs, lhsExpr, rhsExpr, op, file, line);
+ return QTestResult::reportResult(success, &lhs, &rhs,
+ functionRefFormatter, functionRefFormatter,
+ lhsExpr, rhsExpr, op, file, line);
}
+#endif // QT_DEPRECATED_SINCE(6, 8)
+bool reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void*),
+ const char *(*rhsFormatter)(const void*),
+ const char *lhsExpr, const char *rhsExpr,
+ ComparisonOperation op, const char *file, int line)
+{
+ return QTestResult::reportResult(success, lhs, rhs, lhsFormatter, rhsFormatter,
+ lhsExpr, rhsExpr, op, file, line);
+}
} // namespace QTest
static void initEnvironment()
@@ -2183,6 +2202,19 @@ void QTest::ignoreMessage(QtMsgType type, const QRegularExpression &messagePatte
#endif // QT_CONFIG(regularexpression)
/*!
+ \since 6.8
+ \overload failOnWarning()
+
+ Appends a test failure to the test log if any warning is output.
+
+ \sa failOnWarning()
+*/
+void QTest::failOnWarning()
+{
+ return QTestLog::failOnWarning();
+}
+
+/*!
\since 6.3
\overload failOnWarning()
@@ -2228,7 +2260,17 @@ void QTest::failOnWarning(const char *message)
\code
void FileTest::init()
{
- QTest::failOnWarning(QRegularExpression(".?"));
+ QTest::failOnWarning(
+ QRegularExpression("QFile::.*: File(.*) already open"));
+ }
+ \endcode
+
+ For the common case of failing on \e any warning pass no parameter:
+
+ \code
+ void FileTest::init()
+ {
+ QTest::failOnWarning();
}
\endcode
@@ -2729,6 +2771,7 @@ bool QTest::compare_helper(bool success, const char *failureMsg,
}
#endif // QT_DEPRECATED_SINCE(6, 4)
+#if QT_DEPRECATED_SINCE(6, 8)
/*! \internal
\since 6.4
This function is called by various specializations of QTest::qCompare
@@ -2748,7 +2791,34 @@ bool QTest::compare_helper(bool success, const char *failureMsg,
const char *actual, const char *expected,
const char *file, int line)
{
- return QTestResult::reportResult(success, actualVal, expectedVal, actual, expected,
+ return QTestResult::reportResult(success, &actualVal, &expectedVal,
+ QTest::functionRefFormatter,
+ QTest::functionRefFormatter, actual, expected,
+ QTest::ComparisonOperation::CustomCompare,
+ file, line, failureMsg);
+}
+#endif // QT_DEPRECATED_SINCE(6, 8)
+
+/*! \internal
+ \since 6.8
+ This function is called by various specializations of QTest::qCompare
+ to decide whether to report a failure and to produce verbose test output.
+
+ The \a failureMsg parameter can be \c {nullptr}, in which case a default
+ message will be output if the compare fails. If the comparison succeeds,
+ \a failureMsg will not be output.
+*/
+
+bool QTest::compare_helper(bool success, const char *failureMsg,
+ const void *actualPtr, const void *expectedPtr,
+ const char *(*actualFormatter)(const void *),
+ const char *(*expectedFormatter)(const void *),
+ const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return QTestResult::reportResult(success, actualPtr, expectedPtr,
+ actualFormatter, expectedFormatter,
+ actual, expected,
QTest::ComparisonOperation::CustomCompare,
file, line, failureMsg);
}
@@ -2794,9 +2864,10 @@ static bool floatingCompare(const T &actual, const T &expected)
bool QTest::qCompare(qfloat16 const &t1, qfloat16 const &t2, const char *actual, const char *expected,
const char *file, int line)
{
+ auto formatter = Internal::genericToString<qfloat16>;
return compare_helper(floatingCompare(t1, t2),
"Compared qfloat16s are not the same (fuzzy compare)",
- [&t1] { return toString(t1); }, [&t2] { return toString(t2); },
+ &t1, &t2, formatter, formatter,
actual, expected, file, line);
}
@@ -3061,11 +3132,6 @@ char *QTest::toString(const char *str)
*/
char *QTest::toString(const volatile void *p) // Use volatile to match compare_ptr_helper()
{
- return QTest::toString(const_cast<const void *>(p));
-}
-
-char *QTest::toString(const void *p)
-{
char *msg = new char[128];
qsnprintf(msg, 128, "%p", p);
return msg;
@@ -3118,8 +3184,9 @@ char *QTest::toString(const volatile QObject *vo)
bool QTest::compare_string_helper(const char *t1, const char *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto formatter = Internal::genericToString<const char *>;
return compare_helper(qstrcmp(t1, t2) == 0, "Compared strings are not the same",
- [t1] { return toString(t1); }, [t2] { return toString(t2); },
+ &t1, &t2, formatter, formatter,
actual, expected, file, line);
}
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
index 1a47382304..a855ace6a9 100644
--- a/src/testlib/qtestcase.h
+++ b/src/testlib/qtestcase.h
@@ -5,6 +5,7 @@
#define QTESTCASE_H
#include <QtTest/qttestglobal.h>
+#include <QtTest/qtesttostring.h>
#include <QtCore/qstring.h>
#include <QtCore/qnamespace.h>
@@ -83,24 +84,10 @@ do {\
QTEST_FAIL_ACTION; \
} while (false)
-// A wrapper lambda is introduced to extend the lifetime of lhs and rhs in
-// case they are temporary objects.
-// We also use IILE to prevent potential name clashes and shadowing of variables
-// from user code. A drawback of the approach is that it looks ugly :(
#define QCOMPARE_OP_IMPL(lhs, rhs, op, opId) \
do { \
- if (![](auto &&qt_lhs_arg, auto &&qt_rhs_arg) { \
- /* assumes that op does not actually move from qt_{lhs, rhs}_arg */ \
- return QTest::reportResult(std::forward<decltype(qt_lhs_arg)>(qt_lhs_arg) \
- op \
- std::forward<decltype(qt_rhs_arg)>(qt_rhs_arg), \
- [&qt_lhs_arg] { return QTest::toString(qt_lhs_arg); }, \
- [&qt_rhs_arg] { return QTest::toString(qt_rhs_arg); }, \
- #lhs, #rhs, QTest::ComparisonOperation::opId, \
- __FILE__, __LINE__); \
- }(lhs, rhs)) { \
+ if (!QTest::qCompareOp<QTest::ComparisonOperation::opId>(lhs, rhs, #lhs, #rhs, __FILE__, __LINE__)) \
QTEST_FAIL_ACTION; \
- } \
} while (false)
#define QCOMPARE_EQ(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, ==, Equal)
@@ -239,7 +226,8 @@ do { \
#define QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, op, opId, timeout) \
do { \
- QTRY_IMPL(((computed) op (baseline)), timeout) \
+ using Q_Cmp = QTest::Internal::Compare<QTest::ComparisonOperation::opId>; \
+ QTRY_IMPL(Q_Cmp::compare((computed), (baseline)), timeout) \
QCOMPARE_OP_IMPL(computed, baseline, op, opId); \
} while (false)
@@ -318,9 +306,6 @@ do {\
class QObject;
class QTestData;
-#define QTEST_COMPARE_DECL(KLASS)\
- template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
-
namespace QTest
{
namespace Internal {
@@ -332,49 +317,54 @@ namespace QTest
Q_TESTLIB_EXPORT QString formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual);
- template<typename T> // Output registered enums
- inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
+ template <ComparisonOperation> struct Compare;
+ template <> struct Compare<ComparisonOperation::Equal>
{
- QMetaEnum me = QMetaEnum::fromType<T>();
- return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes
- }
-
- template <typename T>
- inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e)
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) == std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::NotEqual>
{
- return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
- }
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) != std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::LessThan>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) < std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::LessThanOrEqual>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) <= std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::GreaterThan>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) > std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::GreaterThanOrEqual>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) >= std::forward<T2>(rhs); }
+ };
- template <typename T> // Fallback; for built-in types debug streaming must be possible
- inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t)
- {
- char *result = nullptr;
-#ifndef QT_NO_DEBUG_STREAM
- if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) {
- result = qstrdup(QDebug::toString(t).toUtf8().constData());
- } else {
- static_assert(!QMetaTypeId2<T>::IsBuiltIn,
- "Built-in type must implement debug streaming operator "
- "or provide QTest::toString specialization");
- }
-#endif
- return result;
+ template <typename T1> const char *genericToString(const void *arg)
+ {
+ using QTest::toString;
+ return toString(*static_cast<const T1 *>(arg));
}
- template<typename F> // Output QFlags of registered enumerations
- inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+ template <> inline const char *genericToString<char *>(const void *arg)
{
- const QMetaEnum me = QMetaEnum::fromType<F>();
- return qstrdup(me.valueToKeys(int(f.toInt())).constData());
+ using QTest::toString;
+ return toString(static_cast<const char *>(arg));
}
- template <typename F> // Fallback: Output hex value
- inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+ template <typename T> const char *pointerToString(const void *arg)
{
- const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
- char *msg = new char[space];
- qsnprintf(msg, space, "0x%x", unsigned(f.toInt()));
- return msg;
+ using QTest::toString;
+ return toString(static_cast<const T *>(arg));
}
// Exported so Qt Quick Test can also use it for generating backtraces upon crashes.
@@ -382,29 +372,6 @@ namespace QTest
} // namespace Internal
- template<typename T>
- inline char *toString(const T &t)
- {
- return Internal::toString(t);
- }
-
- template <typename T1, typename T2>
- inline char *toString(const std::pair<T1, T2> &pair);
-
- template <class... Types>
- inline char *toString(const std::tuple<Types...> &tuple);
-
- template <typename Rep, typename Period>
- inline char *toString(std::chrono::duration<Rep, Period> duration);
-
- Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
- Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
- Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
- Q_TESTLIB_EXPORT char *toString(const char *);
- Q_TESTLIB_EXPORT char *toString(const volatile void *);
- Q_TESTLIB_EXPORT char *toString(const void *); // ### FIXME: Qt 7: Remove
- Q_TESTLIB_EXPORT char *toString(const volatile QObject *);
-
Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr);
Q_TESTLIB_EXPORT int qRun();
Q_TESTLIB_EXPORT void qCleanup();
@@ -468,6 +435,7 @@ namespace QTest
#if QT_CONFIG(regularexpression)
Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern);
#endif
+ Q_TESTLIB_EXPORT void failOnWarning();
Q_TESTLIB_EXPORT void failOnWarning(const char *message);
#if QT_CONFIG(regularexpression)
Q_TESTLIB_EXPORT void failOnWarning(const QRegularExpression &messagePattern);
@@ -495,10 +463,8 @@ namespace QTest
Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii);
Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key);
- // ### TODO: remove QTestResult::compare() overload that takes char * values
- // when this overload is removed.
#if QT_DEPRECATED_SINCE(6, 4)
- QT_DEPRECATED_VERSION_X_6_4("use an overload that takes function_ref as parameters, "
+ QT_DEPRECATED_VERSION_X_6_4("use an overload that takes a formatter callback, "
"or an overload that takes only failure message, if you "
"do not need to stringify the values")
Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
@@ -506,11 +472,22 @@ namespace QTest
const char *actual, const char *expected,
const char *file, int line);
#endif // QT_DEPRECATED_SINCE(6, 4)
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("use an overload that takes a formatter callback, "
+ "or an overload that takes only failure message, if you "
+ "do not need to stringify the values")
Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
qxp::function_ref<const char*()> actualVal,
qxp::function_ref<const char*()> expectedVal,
const char *actual, const char *expected,
const char *file, int line);
+#endif // QT_DEPRECATED_SINCE(6, 8)
+ Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
+ const void *actualPtr, const void *expectedPtr,
+ const char *(*actualFormatter)(const void *),
+ const char *(*expectedFormatter)(const void *),
+ const char *actual, const char *expected,
+ const char *file, int line);
Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
const char *actual, const char *expected,
const char *file, int line);
@@ -578,81 +555,71 @@ namespace QTest
inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto formatter = Internal::pointerToString<void>;
return compare_helper(t1 == t2, "Compared pointers are not the same",
- [t1] { return toString(t1); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ const_cast<const void *>(t1), const_cast<const void *>(t2),
+ formatter, formatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(const volatile QObject *t1, const volatile QObject *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto formatter = Internal::pointerToString<QObject>;
return compare_helper(t1 == t2, "Compared QObject pointers are not the same",
- [t1] { return toString(t1); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ const_cast<const QObject *>(t1), const_cast<const QObject *>(t2),
+ formatter, formatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(const volatile QObject *t1, std::nullptr_t, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::pointerToString<QObject>;
+ auto rhsFormatter = Internal::genericToString<std::nullptr_t>;
return compare_helper(t1 == nullptr, "Compared QObject pointers are not the same",
- [t1] { return toString(t1); }, [] { return toString(nullptr); },
- actual, expected, file, line);
+ const_cast<const QObject *>(t1), nullptr,
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(std::nullptr_t, const volatile QObject *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::genericToString<std::nullptr_t>;
+ auto rhsFormatter = Internal::pointerToString<QObject>;
return compare_helper(nullptr == t2, "Compared QObject pointers are not the same",
- [] { return toString(nullptr); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ nullptr, const_cast<const QObject *>(t2),
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::pointerToString<void>;
+ auto rhsFormatter = Internal::genericToString<std::nullptr_t>;
return compare_helper(t1 == nullptr, "Compared pointers are not the same",
- [t1] { return toString(t1); }, [] { return toString(nullptr); },
- actual, expected, file, line);
+ const_cast<const void *>(t1), nullptr,
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::genericToString<std::nullptr_t>;
+ auto rhsFormatter = Internal::pointerToString<void>;
return compare_helper(nullptr == t2, "Compared pointers are not the same",
- [] { return toString(nullptr); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ nullptr, const_cast<const void *>(t2),
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
- Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
- const char *expected, const char *file, int line);
-
- Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
-
-#ifndef Q_QDOC
- QTEST_COMPARE_DECL(short)
- QTEST_COMPARE_DECL(ushort)
- QTEST_COMPARE_DECL(int)
- QTEST_COMPARE_DECL(uint)
- QTEST_COMPARE_DECL(long)
- QTEST_COMPARE_DECL(ulong)
- QTEST_COMPARE_DECL(qint64)
- QTEST_COMPARE_DECL(quint64)
-
- QTEST_COMPARE_DECL(float)
- QTEST_COMPARE_DECL(double)
- QTEST_COMPARE_DECL(qfloat16)
- QTEST_COMPARE_DECL(char)
- QTEST_COMPARE_DECL(signed char)
- QTEST_COMPARE_DECL(unsigned char)
- QTEST_COMPARE_DECL(bool)
-#endif
-
template <typename T1, typename T2 = T1>
inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected,
const char *file, int line)
{
+ using D1 = std::decay_t<T1>;
+ using D2 = std::decay_t<T2>;
+ using Internal::genericToString;
return compare_helper(t1 == t2, "Compared values are not the same",
- [&t1] { return toString(t1); }, [&t2] { return toString(t2); },
+ std::addressof(t1), std::addressof(t2),
+ genericToString<D1>, genericToString<D2>,
actual, expected, file, line);
}
@@ -740,13 +707,38 @@ namespace QTest
qMetaTypeId<T>())), actualStr, expected, file, line);
}
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("use the overload without qxp::function_ref")
Q_TESTLIB_EXPORT bool reportResult(bool success, qxp::function_ref<const char*()> lhs,
qxp::function_ref<const char*()> rhs,
const char *lhsExpr, const char *rhsExpr,
ComparisonOperation op, const char *file, int line);
+#endif // QT_DEPRECATED_SINCE(6, 8)
+
+ Q_TESTLIB_EXPORT bool reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void*),
+ const char *(*rhsFormatter)(const void*),
+ const char *lhsExpr, const char *rhsExpr,
+ ComparisonOperation op, const char *file, int line);
+
+ template <ComparisonOperation op, typename T1, typename T2 = T1>
+ inline bool qCompareOp(T1 &&lhs, T2 &&rhs, const char *lhsExpr, const char *rhsExpr,
+ const char *file, int line)
+ {
+ using D1 = std::decay_t<T1>;
+ using D2 = std::decay_t<T2>;
+ using Internal::genericToString;
+ using Comparator = Internal::Compare<op>;
+
+ /* assumes that op does not actually move from lhs and rhs */
+ bool result = Comparator::compare(std::forward<T1>(lhs), std::forward<T2>(rhs));
+ return reportResult(result, std::addressof(lhs), std::addressof(rhs),
+ genericToString<D1>, genericToString<D2>,
+ lhsExpr, rhsExpr, op, file, line);
+
+ }
}
-#undef QTEST_COMPARE_DECL
#define QWARN(msg) QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__)
diff --git a/src/testlib/qtestcase.qdoc b/src/testlib/qtestcase.qdoc
index 973899e4d3..6a067c351f 100644
--- a/src/testlib/qtestcase.qdoc
+++ b/src/testlib/qtestcase.qdoc
@@ -1423,7 +1423,7 @@
*/
/*!
- \fn template<typename T> char *QTest::toString(const T &value)
+ \fn template<typename T, QTest::Internal::is_suitable_type_v<T> = true> char *QTest::toString(const T &value)
Returns a textual representation of \a value. This function is used by
\l QCOMPARE() to output verbose information in case of a test failure.
@@ -1608,7 +1608,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy::ControlType ct)
+ \fn char *toString(QSizePolicy::ControlType ct)
+ \relates QTest
\overload
\since 5.5
@@ -1616,7 +1617,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy::ControlTypes cts)
+ \fn char *toString(QSizePolicy::ControlTypes cts)
+ \relates QTest
\overload
\since 5.5
@@ -1624,7 +1626,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy::Policy p)
+ \fn char *toString(QSizePolicy::Policy p)
+ \relates QTest
\overload
\since 5.5
@@ -1632,7 +1635,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy sp)
+ \fn char *toString(QSizePolicy sp)
+ \relates QTest
\overload
\since 5.5
diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp
index 4b6df54e91..929ccb370b 100644
--- a/src/testlib/qtestlog.cpp
+++ b/src/testlib/qtestlog.cpp
@@ -629,6 +629,11 @@ void QTestLog::ignoreMessage(QtMsgType type, const QRegularExpression &expressio
}
#endif // QT_CONFIG(regularexpression)
+void QTestLog::failOnWarning()
+{
+ QTest::failOnWarningList.push_back({});
+}
+
void QTestLog::failOnWarning(const char *msg)
{
QTest::failOnWarningList.push_back(QString::fromUtf8(msg));
diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h
index f9bbfa158d..ab5fb593d4 100644
--- a/src/testlib/qtestlog_p.h
+++ b/src/testlib/qtestlog_p.h
@@ -71,6 +71,7 @@ public:
#ifndef QT_NO_REGULAREXPRESSION
static void ignoreMessage(QtMsgType type, const QRegularExpression &expression);
#endif
+ static void failOnWarning();
static void failOnWarning(const char *msg);
#ifndef QT_NO_REGULAREXPRESSION
static void failOnWarning(const QRegularExpression &expression);
diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp
index 093e9b58ef..7c5ce9ce54 100644
--- a/src/testlib/qtestresult.cpp
+++ b/src/testlib/qtestresult.cpp
@@ -628,8 +628,9 @@ static const char *failureMessageForOp(QTest::ComparisonOperation op)
Q_UNREACHABLE_RETURN("");
}
-bool QTestResult::reportResult(bool success, qxp::function_ref<const char *()> lhs,
- qxp::function_ref<const char *()> rhs,
+bool QTestResult::reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void*),
+ const char *(*rhsFormatter)(const void*),
const char *lhsExpr, const char *rhsExpr,
QTest::ComparisonOperation op, const char *file, int line,
const char *failureMessage)
@@ -653,8 +654,8 @@ bool QTestResult::reportResult(bool success, qxp::function_ref<const char *()> l
return checkStatement(success, msg, file, line);
}
- const std::unique_ptr<const char[]> lhsPtr{ lhs() };
- const std::unique_ptr<const char[]> rhsPtr{ rhs() };
+ const std::unique_ptr<const char[]> lhsPtr{ lhsFormatter(lhs) };
+ const std::unique_ptr<const char[]> rhsPtr{ rhsFormatter(rhs) };
if (!failureMessage)
failureMessage = failureMessageForOp(op);
diff --git a/src/testlib/qtestresult_p.h b/src/testlib/qtestresult_p.h
index 48c2c34611..e94de64c06 100644
--- a/src/testlib/qtestresult_p.h
+++ b/src/testlib/qtestresult_p.h
@@ -17,7 +17,6 @@
#include <QtTest/qttestglobal.h>
#include <QtCore/qstringfwd.h>
-#include <QtCore/qxpfunctional.h>
#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -102,8 +101,9 @@ public:
static void setCurrentAppName(const char *appName);
static const char *currentAppName();
- static bool reportResult(bool success, qxp::function_ref<const char *()> lhs,
- qxp::function_ref<const char *()> rhs,
+ static bool reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void *),
+ const char *(*rhsFormatter)(const void *),
const char *lhsExpr, const char *rhsExpr,
QTest::ComparisonOperation op, const char *file, int line,
const char *failureMessage = nullptr);
diff --git a/src/testlib/qtesttostring.h b/src/testlib/qtesttostring.h
new file mode 100644
index 0000000000..18262332ba
--- /dev/null
+++ b/src/testlib/qtesttostring.h
@@ -0,0 +1,499 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2024 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTESTTOSTRING_H
+#define QTESTTOSTRING_H
+
+#include <QtTest/qttestglobal.h>
+
+#if QT_CONFIG(itemmodel)
+# include <QtCore/qabstractitemmodel.h>
+#endif
+#include <QtCore/qbitarray.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qcborarray.h>
+#include <QtCore/qcborcommon.h>
+#include <QtCore/qcbormap.h>
+#include <QtCore/qcborvalue.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qurl.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest {
+namespace Internal {
+
+template<typename T> // Output registered enums
+inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
+{
+ QMetaEnum me = QMetaEnum::fromType<T>();
+ return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes
+}
+
+template <typename T>
+inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e)
+{
+ return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
+}
+
+template <typename T> // Fallback; for built-in types debug streaming must be possible
+inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t)
+{
+ char *result = nullptr;
+#ifndef QT_NO_DEBUG_STREAM
+ if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) {
+ result = qstrdup(QDebug::toString(t).toUtf8().constData());
+ } else {
+ static_assert(!QMetaTypeId2<T>::IsBuiltIn,
+ "Built-in type must implement debug streaming operator "
+ "or provide QTest::toString specialization");
+ }
+#endif
+ return result;
+}
+
+template<typename F> // Output QFlags of registered enumerations
+inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+{
+ const QMetaEnum me = QMetaEnum::fromType<F>();
+ return qstrdup(me.valueToKeys(int(f.toInt())).constData());
+}
+
+template <typename F> // Fallback: Output hex value
+inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+{
+ const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
+ char *msg = new char[space];
+ qsnprintf(msg, space, "0x%x", unsigned(f.toInt()));
+ return msg;
+}
+
+template <typename T>
+constexpr bool is_suitable_type_helper_v = std::disjunction_v<std::is_same<T, char>,
+ std::is_same<T, void>,
+ std::is_same<T, QObject>
+ >;
+
+template <typename T>
+using is_suitable_type_v =
+ std::enable_if_t<!(std::is_pointer_v<T>
+ && is_suitable_type_helper_v<
+ std::remove_const_t<std::remove_pointer_t<T>>>),
+ bool>;
+
+} // namespace Internal
+
+Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
+ const char *expected, const char *file, int line);
+Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
+Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
+Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
+Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
+Q_TESTLIB_EXPORT char *toString(const char *);
+Q_TESTLIB_EXPORT char *toString(const volatile void *);
+Q_TESTLIB_EXPORT char *toString(const volatile QObject *);
+
+template<typename T, Internal::is_suitable_type_v<T> = true>
+inline char *toString(const T &t)
+{
+ return Internal::toString(t);
+}
+
+template <typename T1, typename T2>
+inline char *toString(const std::pair<T1, T2> &pair);
+
+template <class... Types>
+inline char *toString(const std::tuple<Types...> &tuple);
+
+template <typename Rep, typename Period>
+inline char *toString(std::chrono::duration<Rep, Period> duration);
+
+#define QTEST_COMPARE_DECL(KLASS)\
+ template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
+#ifndef Q_QDOC
+QTEST_COMPARE_DECL(short)
+QTEST_COMPARE_DECL(ushort)
+QTEST_COMPARE_DECL(int)
+QTEST_COMPARE_DECL(uint)
+QTEST_COMPARE_DECL(long)
+QTEST_COMPARE_DECL(ulong)
+QTEST_COMPARE_DECL(qint64)
+QTEST_COMPARE_DECL(quint64)
+
+QTEST_COMPARE_DECL(float)
+QTEST_COMPARE_DECL(double)
+QTEST_COMPARE_DECL(qfloat16)
+QTEST_COMPARE_DECL(char)
+QTEST_COMPARE_DECL(signed char)
+QTEST_COMPARE_DECL(unsigned char)
+QTEST_COMPARE_DECL(bool)
+#endif
+#undef QTEST_COMPARE_DECL
+
+template <> inline char *toString(const QStringView &str)
+{
+ return QTest::toPrettyUnicode(str);
+}
+
+template<> inline char *toString(const QString &str)
+{
+ return toString(QStringView(str));
+}
+
+template<> inline char *toString(const QLatin1StringView &str)
+{
+ return toString(QString(str));
+}
+
+template<> inline char *toString(const QByteArray &ba)
+{
+ return QTest::toPrettyCString(ba.constData(), ba.size());
+}
+
+template<> inline char *toString(const QBitArray &ba)
+{
+ qsizetype size = ba.size();
+ char *str = new char[size + 1];
+ for (qsizetype i = 0; i < size; ++i)
+ str[i] = "01"[ba.testBit(i)];
+ str[size] = '\0';
+ return str;
+}
+
+#if QT_CONFIG(datestring)
+template<> inline char *toString(const QTime &time)
+{
+ return time.isValid()
+ ? qstrdup(qPrintable(time.toString(u"hh:mm:ss.zzz")))
+ : qstrdup("Invalid QTime");
+}
+
+template<> inline char *toString(const QDate &date)
+{
+ return date.isValid()
+ ? qstrdup(qPrintable(date.toString(u"yyyy/MM/dd")))
+ : qstrdup("Invalid QDate");
+}
+
+template<> inline char *toString(const QDateTime &dateTime)
+{
+ return dateTime.isValid()
+ ? qstrdup(qPrintable(dateTime.toString(u"yyyy/MM/dd hh:mm:ss.zzz[t]")))
+ : qstrdup("Invalid QDateTime");
+}
+#endif // datestring
+
+template<> inline char *toString(const QCborError &c)
+{
+ // use the Q_ENUM formatting
+ return toString(c.c);
+}
+
+template<> inline char *toString(const QChar &c)
+{
+ const ushort uc = c.unicode();
+ if (uc < 128) {
+ char msg[32] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
+ return qstrdup(msg);
+ }
+ return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
+}
+
+#if QT_CONFIG(itemmodel)
+template<> inline char *toString(const QModelIndex &idx)
+{
+ char msg[128];
+ qsnprintf(msg, sizeof(msg), "QModelIndex(%d,%d,%p,%p)", idx.row(), idx.column(), idx.internalPointer(), idx.model());
+ return qstrdup(msg);
+}
+#endif
+
+template<> inline char *toString(const QPoint &p)
+{
+ char msg[128] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QSize &s)
+{
+ char msg[128] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QRect &s)
+{
+ char msg[256] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
+ s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QPointF &p)
+{
+ char msg[64] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QSizeF &s)
+{
+ char msg[64] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QRectF &s)
+{
+ char msg[256] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
+ s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QUrl &uri)
+{
+ if (!uri.isValid())
+ return qstrdup(qPrintable(QLatin1StringView("Invalid URL: ") + uri.errorString()));
+ return qstrdup(uri.toEncoded().constData());
+}
+
+template <> inline char *toString(const QUuid &uuid)
+{
+ return qstrdup(uuid.toByteArray().constData());
+}
+
+template<> inline char *toString(const QVariant &v)
+{
+ QByteArray vstring("QVariant(");
+ if (v.isValid()) {
+ QByteArray type(v.typeName());
+ if (type.isEmpty()) {
+ type = QByteArray::number(v.userType());
+ }
+ vstring.append(type);
+ if (!v.isNull()) {
+ vstring.append(',');
+ if (v.canConvert<QString>()) {
+ vstring.append(v.toString().toLocal8Bit());
+ }
+ else {
+ vstring.append("<value not representable as string>");
+ }
+ }
+ }
+ vstring.append(')');
+
+ return qstrdup(vstring.constData());
+}
+
+template<> inline char *toString(const QPartialOrdering &o)
+{
+ if (o == QPartialOrdering::Less)
+ return qstrdup("Less");
+ if (o == QPartialOrdering::Equivalent)
+ return qstrdup("Equivalent");
+ if (o == QPartialOrdering::Greater)
+ return qstrdup("Greater");
+ if (o == QPartialOrdering::Unordered)
+ return qstrdup("Unordered");
+ return qstrdup("<invalid>");
+}
+
+namespace Internal {
+struct QCborValueFormatter
+{
+ enum { BufferLen = 256 };
+ static char *formatSimpleType(QCborSimpleType st)
+ {
+ char *buf = new char[BufferLen];
+ qsnprintf(buf, BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
+ return buf;
+ }
+
+ static char *formatTag(QCborTag tag, const QCborValue &taggedValue)
+ {
+ QScopedArrayPointer<char> hold(format(taggedValue));
+ char *buf = new char[BufferLen];
+ qsnprintf(buf, BufferLen, "QCborValue(QCborTag(%llu), %s)", tag, hold.get());
+ return buf;
+ }
+
+ static char *innerFormat(QCborValue::Type t, const char *str)
+ {
+ static const QMetaEnum typeEnum = []() {
+ int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
+ return QCborValue::staticMetaObject.enumerator(idx);
+ }();
+
+ char *buf = new char[BufferLen];
+ const char *typeName = typeEnum.valueToKey(t);
+ if (typeName)
+ qsnprintf(buf, BufferLen, "QCborValue(%s, %s)", typeName, str);
+ else
+ qsnprintf(buf, BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
+ return buf;
+ }
+
+ template<typename T> static char *format(QCborValue::Type type, const T &t)
+ {
+ QScopedArrayPointer<char> hold(QTest::toString(t));
+ return innerFormat(type, hold.get());
+ }
+
+ static char *format(const QCborValue &v)
+ {
+ switch (v.type()) {
+ case QCborValue::Integer:
+ return format(v.type(), v.toInteger());
+ case QCborValue::ByteArray:
+ return format(v.type(), v.toByteArray());
+ case QCborValue::String:
+ return format(v.type(), v.toString());
+ case QCborValue::Array:
+ return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toArray())).get());
+ case QCborValue::Map:
+ return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toMap())).get());
+ case QCborValue::Tag:
+ return formatTag(v.tag(), v.taggedValue());
+ case QCborValue::SimpleType:
+ break;
+ case QCborValue::True:
+ return qstrdup("QCborValue(true)");
+ case QCborValue::False:
+ return qstrdup("QCborValue(false)");
+ case QCborValue::Null:
+ return qstrdup("QCborValue(nullptr)");
+ case QCborValue::Undefined:
+ return qstrdup("QCborValue()");
+ case QCborValue::Double:
+ return format(v.type(), v.toDouble());
+ case QCborValue::DateTime:
+ case QCborValue::Url:
+ case QCborValue::RegularExpression:
+ return format(v.type(), v.taggedValue().toString());
+ case QCborValue::Uuid:
+ return format(v.type(), v.toUuid());
+ case QCborValue::Invalid:
+ return qstrdup("QCborValue(<invalid>)");
+ }
+
+ if (v.isSimpleType())
+ return formatSimpleType(v.toSimpleType());
+ return innerFormat(v.type(), "");
+ }
+
+ static char *format(const QCborArray &a)
+ {
+ QByteArray out(1, '[');
+ const char *comma = "";
+ for (QCborValueConstRef v : a) {
+ QScopedArrayPointer<char> s(format(v));
+ out += comma;
+ out += s.get();
+ comma = ", ";
+ }
+ out += ']';
+ return qstrdup(out.constData());
+ }
+
+ static char *format(const QCborMap &m)
+ {
+ QByteArray out(1, '{');
+ const char *comma = "";
+ for (auto pair : m) {
+ QScopedArrayPointer<char> key(format(pair.first));
+ QScopedArrayPointer<char> value(format(pair.second));
+ out += comma;
+ out += key.get();
+ out += ": ";
+ out += value.get();
+ comma = ", ";
+ }
+ out += '}';
+ return qstrdup(out.constData());
+ }
+};
+}
+
+template<> inline char *toString(const QCborValue &v)
+{
+ return Internal::QCborValueFormatter::format(v);
+}
+
+template<> inline char *toString(const QCborValueRef &v)
+{
+ return toString(QCborValue(v));
+}
+
+template<> inline char *toString(const QCborArray &a)
+{
+ return Internal::QCborValueFormatter::format(a);
+}
+
+template<> inline char *toString(const QCborMap &m)
+{
+ return Internal::QCborValueFormatter::format(m);
+}
+
+template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
+{
+ QString r;
+ QDebug d(&r);
+ d.nospace() << qSetRealNumberPrecision(9) << dur;
+ if constexpr (Period::num != 1 || Period::den != 1) {
+ // include the equivalent value in seconds, in parentheses
+ using namespace std::chrono;
+ d << " (" << duration_cast<duration<qreal>>(dur).count() << "s)";
+ }
+ return qstrdup(std::move(r).toUtf8().constData());
+}
+
+template <typename T1, typename T2>
+inline char *toString(const std::pair<T1, T2> &pair)
+{
+ const QScopedArrayPointer<char> first(toString(pair.first));
+ const QScopedArrayPointer<char> second(toString(pair.second));
+ return formatString("std::pair(", ")", 2, first.data(), second.data());
+}
+
+template <typename Tuple, std::size_t... I>
+inline char *tupleToString(const Tuple &tuple, std::index_sequence<I...>) {
+ using UP = std::unique_ptr<char[]>;
+ // Generate a table of N + 1 elements where N is the number of
+ // elements in the tuple.
+ // The last element is needed to support the empty tuple use case.
+ const UP data[] = {
+ UP(toString(std::get<I>(tuple)))..., UP{}
+ };
+ return formatString("std::tuple(", ")", sizeof...(I), data[I].get()...);
+}
+
+template <class... Types>
+inline char *toString(const std::tuple<Types...> &tuple)
+{
+ return tupleToString(tuple, std::make_index_sequence<sizeof...(Types)>{});
+}
+
+inline char *toString(std::nullptr_t)
+{
+ return toString(QStringView(u"nullptr"));
+}
+} // namespace QTest
+
+QT_END_NAMESPACE
+
+#endif // QTESTTOSTRING_H
diff --git a/src/testlib/removed_api.cpp b/src/testlib/removed_api.cpp
new file mode 100644
index 0000000000..00a53735a0
--- /dev/null
+++ b/src/testlib/removed_api.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2024 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_TESTLIB_BUILD_REMOVED_API
+
+#include "qtest.h"
+
+#if QT_TESTLIB_REMOVED_SINCE(6, 8)
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest {
+
+Q_TESTLIB_EXPORT char *toString(const void *p)
+{
+ const volatile void *ptr = p;
+ return toString(ptr);
+}
+
+} // namespace QTest
+
+QT_END_NAMESPACE
+
+// #include "qotherheader.h"
+// implement removed functions from qotherheader.h
+// order sections alphabetically to reduce chances of merge conflicts
+
+#endif // QT_TESTLIB_REMOVED_SINCE(6, 8)
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index 6125b405b5..da5c2c8c77 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -44,15 +44,16 @@ static const bool mustReadOutputAnyway = true; // pclose seems to return the wro
static QStringList dependenciesForDepfile;
-FILE *openProcess(const QString &command)
+auto openProcess(const QString &command)
{
#if defined(Q_OS_WIN32)
QString processedCommand = u'\"' + command + u'\"';
#else
const QString& processedCommand = command;
#endif
-
- return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ);
+ struct Closer { void operator()(FILE *proc) const { if (proc) (void)pclose(proc); } };
+ using UP = std::unique_ptr<FILE, Closer>;
+ return UP{popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ)};
}
struct QtDependency
@@ -104,6 +105,7 @@ struct Options
, installApk(false)
, uninstallApk(false)
, qmlImportScannerBinaryPath()
+ , buildAar(false)
{}
enum DeploymentMechanism
@@ -239,6 +241,7 @@ struct Options
// Override qml import scanner path
QString qmlImportScannerBinaryPath;
bool qmlSkipImportScanning = false;
+ bool buildAar;
};
static const QHash<QByteArray, QByteArray> elfArchitectures = {
@@ -310,23 +313,21 @@ QString fileArchitecture(const Options &options, const QString &path)
readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(path));
- FILE *readElfCommand = openProcess(readElf);
+ auto readElfCommand = openProcess(readElf);
if (!readElfCommand) {
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
return {};
}
char buffer[512];
- while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) {
+ while (fgets(buffer, sizeof(buffer), readElfCommand.get()) != nullptr) {
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
line = line.trimmed();
if (line.startsWith("Arch: ")) {
auto it = elfArchitectures.find(line.mid(6));
- pclose(readElfCommand);
return it != elfArchitectures.constEnd() ? QString::fromLatin1(it.value()) : QString{};
}
}
- pclose(readElfCommand);
return {};
}
@@ -527,6 +528,8 @@ Options parseOptions()
options.protectedAuthenticationPath = true;
} else if (argument.compare("--aux-mode"_L1, Qt::CaseInsensitive) == 0) {
options.auxMode = true;
+ } else if (argument.compare("--build-aar"_L1, Qt::CaseInsensitive) == 0) {
+ options.buildAar = true;
} else if (argument.compare("--qml-importscanner-binary"_L1, Qt::CaseInsensitive) == 0) {
options.qmlImportScannerBinaryPath = arguments.at(++i).trimmed();
} else if (argument.compare("--no-rcc-bundle-cleanup"_L1,
@@ -538,6 +541,23 @@ Options parseOptions()
}
}
+ if (options.buildAar) {
+ if (options.installApk || options.uninstallApk) {
+ fprintf(stderr, "Warning: Skipping %s, AAR packages are not installable.\n",
+ options.uninstallApk ? "--reinstall" : "--install");
+ options.installApk = false;
+ options.uninstallApk = false;
+ }
+ if (options.buildAAB) {
+ fprintf(stderr, "Warning: Skipping -aab as --build-aar is present.\n");
+ options.buildAAB = false;
+ }
+ if (!options.keyStore.isEmpty()) {
+ fprintf(stderr, "Warning: Skipping --sign, signing AAR packages is not supported.\n");
+ options.keyStore.clear();
+ }
+ }
+
if (options.buildDirectory.isEmpty() && !options.depFilePath.isEmpty())
options.helpRequested = true;
@@ -645,6 +665,9 @@ Optional arguments:
--apk <path/where/to/copy/the/apk>: Path where to copy the built apk.
+ --build-aar: Build an AAR package. This option skips --aab, --install,
+ --reinstall, and --sign options if they are provided.
+
--qml-importscanner-binary <path/to/qmlimportscanner>: Override the
default qmlimportscanner binary path. By default the
qmlimportscanner binary is located using the Qt directory
@@ -732,18 +755,72 @@ bool copyFileIfNewer(const QString &sourceFileName,
return true;
}
-QString cleanPackageName(QString packageName)
+struct GradleBuildConfigs {
+ QString appNamespace;
+ bool setsLegacyPackaging = false;
+ bool usesIntegerCompileSdkVersion = false;
+};
+
+GradleBuildConfigs gradleBuildConfigs(const QString &path)
+{
+ GradleBuildConfigs configs;
+
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly))
+ return configs;
+
+ auto isComment = [](const QByteArray &trimmed) {
+ return trimmed.startsWith("//") || trimmed.startsWith('*') || trimmed.startsWith("/*");
+ };
+
+ auto extractValue = [](const QByteArray &trimmed) {
+ int idx = trimmed.indexOf('=');
+
+ if (idx == -1)
+ idx = trimmed.indexOf(' ');
+
+ if (idx > -1)
+ return trimmed.mid(idx + 1).trimmed();
+
+ return QByteArray();
+ };
+
+ const auto lines = file.readAll().split('\n');
+ for (const auto &line : lines) {
+ const QByteArray trimmedLine = line.trimmed();
+ if (isComment(trimmedLine))
+ continue;
+ if (trimmedLine.contains("useLegacyPackaging")) {
+ configs.setsLegacyPackaging = true;
+ } else if (trimmedLine.contains("compileSdkVersion androidCompileSdkVersion.toInteger()")) {
+ configs.usesIntegerCompileSdkVersion = true;
+ } else if (trimmedLine.contains("namespace")) {
+ configs.appNamespace = QString::fromUtf8(extractValue(trimmedLine));
+ }
+ }
+
+ return configs;
+}
+
+QString cleanPackageName(QString packageName, bool *cleaned = nullptr)
{
auto isLegalChar = [] (QChar c) -> bool {
ushort ch = c.unicode();
return (ch >= '0' && ch <= '9') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') ||
- ch == '.';
+ ch == '.' || ch == '_';
};
+
+ if (cleaned)
+ *cleaned = false;
+
for (QChar &c : packageName) {
- if (!isLegalChar(c))
+ if (!isLegalChar(c)) {
c = u'_';
+ if (cleaned)
+ *cleaned = true;
+ }
}
static QStringList keywords;
@@ -778,12 +855,16 @@ QString cleanPackageName(QString packageName)
QChar c = word[0];
if ((c >= u'0' && c <= u'9') || c == u'_') {
packageName.insert(index + 1, u'a');
+ if (cleaned)
+ *cleaned = true;
index = next + 1;
continue;
}
}
if (keywords.contains(word)) {
packageName.insert(next, "_"_L1);
+ if (cleaned)
+ *cleaned = true;
index = next + 1;
} else {
index = next;
@@ -813,18 +894,31 @@ QString detectLatestAndroidPlatform(const QString &sdkPath)
return latestPlatform.baseName();
}
-QString packageNameFromAndroidManifest(const QString &androidManifestPath)
+QString extractPackageName(Options *options)
{
- QFile androidManifestXml(androidManifestPath);
+ {
+ const QString gradleBuildFile = options->androidSourceDirectory + "/build.gradle"_L1;
+ QString packageName = gradleBuildConfigs(gradleBuildFile).appNamespace;
+
+ if (!packageName.isEmpty() && packageName != "androidPackageName"_L1)
+ return packageName;
+ }
+
+ QFile androidManifestXml(options->androidSourceDirectory + "/AndroidManifest.xml"_L1);
if (androidManifestXml.open(QIODevice::ReadOnly)) {
QXmlStreamReader reader(&androidManifestXml);
while (!reader.atEnd()) {
reader.readNext();
- if (reader.isStartElement() && reader.name() == "manifest"_L1)
- return cleanPackageName(reader.attributes().value("package"_L1).toString());
+ if (reader.isStartElement() && reader.name() == "manifest"_L1) {
+ QString packageName = reader.attributes().value("package"_L1).toString();
+ if (!packageName.isEmpty() && packageName != "org.qtproject.example"_L1)
+ return packageName;
+ break;
+ }
}
}
- return {};
+
+ return QString();
}
bool parseCmakeBoolean(const QJsonValue &value)
@@ -1222,6 +1316,24 @@ bool readInputFile(Options *options)
}
{
+ const QJsonValue androidPackageName = jsonObject.value("android-package-name"_L1);
+ const QString extractedPackageName = extractPackageName(options);
+ if (!extractedPackageName.isEmpty())
+ options->packageName = extractedPackageName;
+ else if (!androidPackageName.isUndefined())
+ options->packageName = androidPackageName.toString();
+ else
+ options->packageName = "org.qtproject.example.%1"_L1.arg(options->applicationBinary);
+
+ bool cleaned;
+ options->packageName = cleanPackageName(options->packageName, &cleaned);
+ if (cleaned) {
+ fprintf(stderr, "Warning: Package name contained illegal characters and was cleaned "
+ "to \"%s\"\n", qPrintable(options->packageName));
+ }
+ }
+
+ {
using ItFlag = QDirListing::IteratorFlag;
const QJsonValue deploymentDependencies = jsonObject.value("deployment-dependencies"_L1);
if (!deploymentDependencies.isUndefined()) {
@@ -1278,9 +1390,6 @@ bool readInputFile(Options *options)
options->isZstdCompressionEnabled = zstdCompressionFlag.toBool();
}
}
- options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + "/AndroidManifest.xml"_L1);
- if (options->packageName.isEmpty())
- options->packageName = cleanPackageName("org.qtproject.example.%1"_L1.arg(options->applicationBinary));
return true;
}
@@ -1380,6 +1489,9 @@ bool copyAndroidTemplate(const Options &options)
if (!copyAndroidTemplate(options, "/src/android/templates"_L1))
return false;
+ if (options.buildAar)
+ return copyAndroidTemplate(options, "/src/android/templates_aar"_L1);
+
return true;
}
@@ -1735,13 +1847,7 @@ bool updateAndroidManifest(Options &options)
reader.readNext();
if (reader.isStartElement()) {
- if (reader.name() == "manifest"_L1) {
- if (!reader.attributes().hasAttribute("package"_L1)) {
- fprintf(stderr, "Invalid android manifest file: %s\n", qPrintable(androidManifestPath));
- return false;
- }
- options.packageName = reader.attributes().value("package"_L1).toString();
- } else if (reader.name() == "uses-sdk"_L1) {
+ if (reader.name() == "uses-sdk"_L1) {
if (reader.attributes().hasAttribute("android:minSdkVersion"_L1))
if (reader.attributes().value("android:minSdkVersion"_L1).toInt() < 23) {
fprintf(stderr, "Invalid minSdkVersion version, minSdkVersion must be >= 23\n");
@@ -2014,7 +2120,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(fileName));
- FILE *readElfCommand = openProcess(readElf);
+ auto readElfCommand = openProcess(readElf);
if (!readElfCommand) {
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
return QStringList();
@@ -2024,7 +2130,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
bool readLibs = false;
char buffer[512];
- while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) {
+ while (fgets(buffer, sizeof(buffer), readElfCommand.get()) != nullptr) {
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
QString library;
line = line.trimmed();
@@ -2034,7 +2140,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
if (it == elfArchitectures.constEnd() || *it != options.currentArchitecture.toLatin1()) {
if (options.verbose)
fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName));
- pclose(readElfCommand);
return {};
}
}
@@ -2049,8 +2154,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
ret += libraryName;
}
- pclose(readElfCommand);
-
return ret;
}
@@ -2188,7 +2291,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
qmlImportScanner.toLocal8Bit().constData());
}
- FILE *qmlImportScannerCommand = popen(qmlImportScanner.toLocal8Bit().constData(), QT_POPEN_READ);
+ auto qmlImportScannerCommand = openProcess(qmlImportScanner);
if (qmlImportScannerCommand == 0) {
fprintf(stderr, "Couldn't run qmlimportscanner.\n");
return false;
@@ -2196,13 +2299,12 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
QByteArray output;
char buffer[512];
- while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand) != 0)
+ while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand.get()) != nullptr)
output += QByteArray(buffer, qstrlen(buffer));
QJsonDocument jsonDocument = QJsonDocument::fromJson(output);
if (jsonDocument.isNull()) {
fprintf(stderr, "Invalid json output from qmlimportscanner.\n");
- pclose(qmlImportScannerCommand);
return false;
}
@@ -2211,7 +2313,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
QJsonValue value = jsonArray.at(i);
if (!value.isObject()) {
fprintf(stderr, "Invalid format of qmlimportscanner output.\n");
- pclose(qmlImportScannerCommand);
return false;
}
@@ -2257,7 +2358,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
if (importPathOfThisImport.isEmpty()) {
fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath()));
- pclose(qmlImportScannerCommand);
return false;
}
@@ -2325,7 +2425,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
}
}
- pclose(qmlImportScannerCommand);
return true;
}
@@ -2344,17 +2443,17 @@ bool runCommand(const Options &options, const QString &command)
if (options.verbose)
fprintf(stdout, "Running command '%s'\n", qPrintable(command));
- FILE *runCommand = openProcess(command);
+ auto runCommand = openProcess(command);
if (runCommand == nullptr) {
fprintf(stderr, "Cannot run command '%s'\n", qPrintable(command));
return false;
}
char buffer[4096];
- while (fgets(buffer, sizeof(buffer), runCommand) != nullptr) {
+ while (fgets(buffer, sizeof(buffer), runCommand.get()) != nullptr) {
if (options.verbose)
fprintf(stdout, "%s", buffer);
}
- pclose(runCommand);
+ runCommand.reset();
fflush(stdout);
fflush(stderr);
return true;
@@ -2505,7 +2604,8 @@ bool containsApplicationBinary(Options *options)
return true;
}
-FILE *runAdb(const Options &options, const QString &arguments)
+auto runAdb(const Options &options, const QString &arguments)
+ -> decltype(openProcess({}))
{
QString adb = execSuffixAppended(options.sdkPath + "/platform-tools/adb"_L1);
if (!QFile::exists(adb)) {
@@ -2521,7 +2621,7 @@ FILE *runAdb(const Options &options, const QString &arguments)
if (options.verbose)
fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData());
- FILE *adbCommand = openProcess(adb);
+ auto adbCommand = openProcess(adb);
if (adbCommand == 0) {
fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb));
return 0;
@@ -2745,38 +2845,6 @@ void checkAndWarnGradleLongPaths(const QString &outputDirectory)
}
#endif
-struct GradleFlags {
- bool setsLegacyPackaging = false;
- bool usesIntegerCompileSdkVersion = false;
-};
-
-GradleFlags gradleBuildFlags(const QString &path)
-{
- GradleFlags flags;
-
- QFile file(path);
- if (!file.open(QIODevice::ReadOnly))
- return flags;
-
- auto isComment = [](const QByteArray &line) {
- const auto trimmed = line.trimmed();
- return trimmed.startsWith("//") || trimmed.startsWith('*') || trimmed.startsWith("/*");
- };
-
- const auto lines = file.readAll().split('\n');
- for (const auto &line : lines) {
- if (isComment(line))
- continue;
- if (line.contains("useLegacyPackaging")) {
- flags.setsLegacyPackaging = true;
- } else if (line.contains("compileSdkVersion androidCompileSdkVersion.toInteger()")) {
- flags.usesIntegerCompileSdkVersion = true;
- }
- }
-
- return flags;
-}
-
bool buildAndroidProject(const Options &options)
{
GradleProperties localProperties;
@@ -2789,8 +2857,8 @@ bool buildAndroidProject(const Options &options)
GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath);
const QString gradleBuildFilePath = options.outputDirectory + "build.gradle"_L1;
- GradleFlags gradleFlags = gradleBuildFlags(gradleBuildFilePath);
- if (!gradleFlags.setsLegacyPackaging)
+ GradleBuildConfigs gradleConfigs = gradleBuildConfigs(gradleBuildFilePath);
+ if (!gradleConfigs.setsLegacyPackaging)
gradleProperties["android.bundle.enableUncompressedNativeLibs"] = "false";
gradleProperties["buildDir"] = "build";
@@ -2809,7 +2877,7 @@ bool buildAndroidProject(const Options &options)
QByteArray sdkPlatformVersion;
// Provide the integer version only if build.gradle explicitly converts to Integer,
// to avoid regression to existing projects that build for sdk platform of form android-xx.
- if (gradleFlags.usesIntegerCompileSdkVersion) {
+ if (gradleConfigs.usesIntegerCompileSdkVersion) {
const QByteArray tmp = options.androidPlatform.split(u'-').last().toLocal8Bit();
bool ok;
tmp.toInt(&ok);
@@ -2824,6 +2892,7 @@ bool buildAndroidProject(const Options &options)
if (sdkPlatformVersion.isEmpty())
sdkPlatformVersion = options.androidPlatform.toLocal8Bit();
+ gradleProperties["androidPackageName"] = options.packageName.toLocal8Bit();
gradleProperties["androidCompileSdkVersion"] = sdkPlatformVersion;
gradleProperties["qtMinSdkVersion"] = options.minSdkVersion;
gradleProperties["qtTargetSdkVersion"] = options.targetSdkVersion;
@@ -2839,6 +2908,9 @@ bool buildAndroidProject(const Options &options)
abiList.append(it.key());
}
gradleProperties["qtTargetAbiList"] = abiList.toLocal8Bit();// armeabi-v7a or arm64-v8a or ...
+ gradleProperties["qtGradlePluginType"] = options.buildAar
+ ? "com.android.library"
+ : "com.android.application";
if (!mergeGradleProperties(gradlePropertiesPath, gradleProperties))
return false;
@@ -2864,19 +2936,19 @@ bool buildAndroidProject(const Options &options)
if (options.verbose)
commandLine += " --info"_L1;
- FILE *gradleCommand = openProcess(commandLine);
+ auto gradleCommand = openProcess(commandLine);
if (gradleCommand == 0) {
fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine));
return false;
}
char buffer[512];
- while (fgets(buffer, sizeof(buffer), gradleCommand) != 0) {
+ while (fgets(buffer, sizeof(buffer), gradleCommand.get()) != nullptr) {
fprintf(stdout, "%s", buffer);
fflush(stdout);
}
- int errorCode = pclose(gradleCommand);
+ const int errorCode = pclose(gradleCommand.release());
if (errorCode != 0) {
fprintf(stderr, "Building the android package failed!\n");
if (!options.verbose)
@@ -2902,18 +2974,18 @@ bool uninstallApk(const Options &options)
fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName));
- FILE *adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName));
+ auto adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName));
if (adbCommand == 0)
return false;
if (options.verbose || mustReadOutputAnyway) {
char buffer[512];
- while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
+ while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr)
if (options.verbose)
fprintf(stdout, "%s", buffer);
}
- int returnCode = pclose(adbCommand);
+ const int returnCode = pclose(adbCommand.release());
if (returnCode != 0) {
fprintf(stderr, "Warning: Uninstall failed!\n");
if (!options.verbose)
@@ -2926,39 +2998,43 @@ bool uninstallApk(const Options &options)
enum PackageType {
AAB,
+ AAR,
UnsignedAPK,
SignedAPK
};
-QString packagePath(const Options &options, PackageType pt)
-{
- QString path(options.outputDirectory);
- path += "/build/outputs/%1/"_L1.arg(pt >= UnsignedAPK ? QStringLiteral("apk") : QStringLiteral("bundle"));
- QString buildType(options.releasePackage ? "release/"_L1 : "debug/"_L1);
- if (QDir(path + buildType).exists())
- path += buildType;
- path += QDir(options.outputDirectory).dirName() + u'-';
- if (options.releasePackage) {
- path += "release-"_L1;
- if (pt >= UnsignedAPK) {
- if (pt == UnsignedAPK)
- path += "un"_L1;
- path += "signed.apk"_L1;
- } else {
- path.chop(1);
- path += ".aab"_L1;
- }
- } else {
- path += "debug"_L1;
- if (pt >= UnsignedAPK) {
- if (pt == SignedAPK)
- path += "-signed"_L1;
- path += ".apk"_L1;
- } else {
- path += ".aab"_L1;
- }
- }
- return path;
+QString packagePath(const Options &options, PackageType packageType)
+{
+ // The package type is always AAR if option.buildAar has been set
+ if (options.buildAar)
+ packageType = AAR;
+
+ static const QHash<PackageType, QLatin1StringView> packageTypeToPath{
+ { AAB, "bundle"_L1 }, { AAR, "aar"_L1 }, { UnsignedAPK, "apk"_L1 }, { SignedAPK, "apk"_L1 }
+ };
+ static const QHash<PackageType, QLatin1StringView> packageTypeToExtension{
+ { AAB, "aab"_L1 }, { AAR, "aar"_L1 }, { UnsignedAPK, "apk"_L1 }, { SignedAPK, "apk"_L1 }
+ };
+
+ const QString buildType(options.releasePackage ? "release"_L1 : "debug"_L1);
+ QString signedSuffix;
+ if (packageType == SignedAPK)
+ signedSuffix = "-signed"_L1;
+ else if (packageType == UnsignedAPK && options.releasePackage)
+ signedSuffix = "-unsigned"_L1;
+
+ QString dirPath(options.outputDirectory);
+ dirPath += "/build/outputs/%1/"_L1.arg(packageTypeToPath[packageType]);
+ if (QDir(dirPath + buildType).exists())
+ dirPath += buildType;
+
+ const QString fileName = "/%1-%2%3.%4"_L1.arg(
+ QDir(options.outputDirectory).dirName(),
+ buildType,
+ signedSuffix,
+ packageTypeToExtension[packageType]);
+
+ return dirPath + fileName;
}
bool installApk(const Options &options)
@@ -2971,20 +3047,20 @@ bool installApk(const Options &options)
if (options.verbose)
fprintf(stdout, "Installing Android package to device.\n");
- FILE *adbCommand = runAdb(options, " install -r "_L1
- + packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
- : SignedAPK));
+ auto adbCommand = runAdb(options, " install -r "_L1
+ + packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
+ : SignedAPK));
if (adbCommand == 0)
return false;
if (options.verbose || mustReadOutputAnyway) {
char buffer[512];
- while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
+ while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr)
if (options.verbose)
fprintf(stdout, "%s", buffer);
}
- int returnCode = pclose(adbCommand);
+ const int returnCode = pclose(adbCommand.release());
if (returnCode != 0) {
fprintf(stderr, "Installing to device failed!\n");
if (!options.verbose)
@@ -3102,7 +3178,7 @@ bool signAAB(const Options &options)
QString command = jarSignerTool + " %1 %2"_L1.arg(shellQuote(file))
.arg(shellQuote(options.keyStoreAlias));
- FILE *jarSignerCommand = openProcess(command);
+ auto jarSignerCommand = openProcess(command);
if (jarSignerCommand == 0) {
fprintf(stderr, "Couldn't run jarsigner.\n");
return false;
@@ -3110,11 +3186,11 @@ bool signAAB(const Options &options)
if (options.verbose) {
char buffer[512];
- while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0)
+ while (fgets(buffer, sizeof(buffer), jarSignerCommand.get()) != nullptr)
fprintf(stdout, "%s", buffer);
}
- int errorCode = pclose(jarSignerCommand);
+ const int errorCode = pclose(jarSignerCommand.release());
if (errorCode != 0) {
fprintf(stderr, "jarsigner command failed.\n");
if (!options.verbose)
@@ -3142,17 +3218,17 @@ bool signPackage(const Options &options)
return false;
auto zipalignRunner = [](const QString &zipAlignCommandLine) {
- FILE *zipAlignCommand = openProcess(zipAlignCommandLine);
+ auto zipAlignCommand = openProcess(zipAlignCommandLine);
if (zipAlignCommand == 0) {
fprintf(stderr, "Couldn't run zipalign.\n");
return false;
}
char buffer[512];
- while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0)
+ while (fgets(buffer, sizeof(buffer), zipAlignCommand.get()) != nullptr)
fprintf(stdout, "%s", buffer);
- return pclose(zipAlignCommand) == 0;
+ return pclose(zipAlignCommand.release()) == 0;
};
const QString verifyZipAlignCommandLine =
@@ -3209,17 +3285,17 @@ bool signPackage(const Options &options)
apkSignCommand += " %1"_L1.arg(shellQuote(packagePath(options, SignedAPK)));
auto apkSignerRunner = [](const QString &command, bool verbose) {
- FILE *apkSigner = openProcess(command);
+ auto apkSigner = openProcess(command);
if (apkSigner == 0) {
fprintf(stderr, "Couldn't run apksigner.\n");
return false;
}
char buffer[512];
- while (fgets(buffer, sizeof(buffer), apkSigner) != 0)
+ while (fgets(buffer, sizeof(buffer), apkSigner.get()) != nullptr)
fprintf(stdout, "%s", buffer);
- int errorCode = pclose(apkSigner);
+ const int errorCode = pclose(apkSigner.release());
if (errorCode != 0) {
fprintf(stderr, "apksigner command failed.\n");
if (!verbose)
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index 02e9ef178a..1c6604a96e 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -833,7 +833,7 @@ void Generator::generateProperties()
//
if (cdef->propertyList.size())
- fprintf(out, "\n // properties: name, type, flags\n");
+ fprintf(out, "\n // properties: name, type, flags, notifyId, revision\n");
for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
uint flags = Invalid;
if (!isBuiltinType(p.type))
diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp
index bb51352519..89fb367ca7 100644
--- a/src/tools/moc/main.cpp
+++ b/src/tools/moc/main.cpp
@@ -19,7 +19,8 @@
#include <qcoreapplication.h>
#include <qcommandlineoption.h>
#include <qcommandlineparser.h>
-#include <qscopedpointer.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -58,10 +59,21 @@ void error(const char *msg = "Invalid argument")
fprintf(stderr, "moc: %s\n", msg);
}
-struct ScopedPointerFileCloser
+static auto openFileForWriting(const QString &name)
{
- static inline void cleanup(FILE *handle) { if (handle) fclose(handle); }
-};
+ struct Closer { void operator()(FILE *handle) const { fclose(handle); } };
+ using R = std::unique_ptr<FILE, Closer>;
+
+#ifdef _MSC_VER
+ FILE *file;
+ if (_wfopen_s(&file, reinterpret_cast<const wchar_t *>(name.utf16()), L"w") != 0)
+ return R{};
+ return R{file};
+#else
+ return R{fopen(QFile::encodeName(name).constData(), "w")};
+#endif
+}
+using File = decltype(openFileForWriting({}));
static inline bool hasNext(const Symbols &symbols, int i)
{ return (i < symbols.size()); }
@@ -178,7 +190,7 @@ int runMoc(int argc, char **argv)
QString filename;
QString output;
QFile in;
- FILE *out = nullptr;
+ File out;
// Note that moc isn't translated.
// If you use this code as an example for a translated app, make sure to translate the strings.
@@ -528,16 +540,12 @@ int runMoc(int argc, char **argv)
// 3. and output meta object code
- QScopedPointer<FILE, ScopedPointerFileCloser> jsonOutput;
+ File jsonOutput;
bool outputToFile = true;
if (output.size()) { // output file specified
-#if defined(_MSC_VER)
- if (_wfopen_s(&out, reinterpret_cast<const wchar_t *>(output.utf16()), L"w") != 0)
-#else
- out = fopen(QFile::encodeName(output).constData(), "w"); // create output file
+ out = openFileForWriting(output);
if (!out)
-#endif
{
const auto fopen_errno = errno;
fprintf(stderr, "moc: Cannot create %s. Error: %s\n",
@@ -548,37 +556,29 @@ int runMoc(int argc, char **argv)
if (parser.isSet(jsonOption)) {
const QString jsonOutputFileName = output + ".json"_L1;
- FILE *f;
-#if defined(_MSC_VER)
- if (_wfopen_s(&f, reinterpret_cast<const wchar_t *>(jsonOutputFileName.utf16()), L"w") != 0)
-#else
- f = fopen(QFile::encodeName(jsonOutputFileName).constData(), "w");
- if (!f)
-#endif
- {
+ jsonOutput = openFileForWriting(jsonOutputFileName);
+ if (!jsonOutput) {
const auto fopen_errno = errno;
fprintf(stderr, "moc: Cannot create JSON output file %s. Error: %s\n",
QFile::encodeName(jsonOutputFileName).constData(),
strerror(fopen_errno));
}
- jsonOutput.reset(f);
}
} else { // use stdout
- out = stdout;
+ out.reset(stdout);
outputToFile = false;
}
if (pp.preprocessOnly) {
- fprintf(out, "%s\n", composePreprocessorOutput(moc.symbols).constData());
+ fprintf(out.get(), "%s\n", composePreprocessorOutput(moc.symbols).constData());
} else {
if (moc.classList.isEmpty())
moc.note("No relevant classes found. No output generated.");
else
- moc.generate(out, jsonOutput.data());
+ moc.generate(out.get(), jsonOutput.get());
}
- if (output.size())
- fclose(out);
+ out.reset();
if (parser.isSet(depFileOption)) {
// 4. write a Make-style dependency file (can also be consumed by Ninja).
@@ -596,26 +596,17 @@ int runMoc(int argc, char **argv)
fprintf(stderr, "moc: Writing to stdout, but no depfile path specified.\n");
}
- QScopedPointer<FILE, ScopedPointerFileCloser> depFileHandle;
- FILE *depFileHandleRaw;
-#if defined(_MSC_VER)
- if (_wfopen_s(&depFileHandleRaw,
- reinterpret_cast<const wchar_t *>(depOutputFileName.utf16()), L"w") != 0)
-#else
- depFileHandleRaw = fopen(QFile::encodeName(depOutputFileName).constData(), "w");
- if (!depFileHandleRaw)
-#endif
- {
+ File depFileHandle = openFileForWriting(depOutputFileName);
+ if (!depFileHandle) {
const auto fopen_errno = errno;
fprintf(stderr, "moc: Cannot create dep output file '%s'. Error: %s\n",
QFile::encodeName(depOutputFileName).constData(),
strerror(fopen_errno));
}
- depFileHandle.reset(depFileHandleRaw);
- if (!depFileHandle.isNull()) {
+ if (depFileHandle) {
// First line is the path to the generated file.
- fprintf(depFileHandle.data(), "%s: ",
+ fprintf(depFileHandle.get(), "%s: ",
escapeAndEncodeDependencyPath(depRuleName).constData());
QByteArrayList dependencies;
@@ -647,7 +638,7 @@ int runMoc(int argc, char **argv)
// Join dependencies, output them, and output a final new line.
const auto dependenciesJoined = dependencies.join(QByteArrayLiteral(" \\\n "));
- fprintf(depFileHandle.data(), "%s\n", dependenciesJoined.constData());
+ fprintf(depFileHandle.get(), "%s\n", dependenciesJoined.constData());
}
}
diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
index 579604286c..d637854d2b 100644
--- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
+++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
@@ -276,7 +276,7 @@ QTextStream &QDBusXmlToCpp::writeHeader(QTextStream &ts, bool changesWillBeLost)
{
ts << "/*\n"
" * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION "\n"
- " * Command line was: " << commandLine << "\n"
+ " * Source file was " << QFileInfo(inputFile).fileName() << "\n"
" *\n"
" * " PROGRAMNAME " is " PROGRAMCOPYRIGHT "\n"
" *\n"
diff --git a/src/tools/qlalr/cppgenerator.cpp b/src/tools/qlalr/cppgenerator.cpp
index fd56de106d..f12917f0eb 100644
--- a/src/tools/qlalr/cppgenerator.cpp
+++ b/src/tools/qlalr/cppgenerator.cpp
@@ -1,5 +1,7 @@
+// REUSE-IgnoreStart
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// REUSE-IgnoreEnd
#include "cppgenerator.h"
@@ -39,7 +41,7 @@ void generateList(const QList<int> &list, QTextStream &out)
}
}
-
+// REUSE-IgnoreStart
QString CppGenerator::copyrightHeader() const
{
return
@@ -47,6 +49,7 @@ QString CppGenerator::copyrightHeader() const
"// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0\n"
"\n"_L1;
}
+// REUSE-IgnoreEnd
QString CppGenerator::privateCopyrightHeader() const
{
diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp
index 444e9c4ae5..0fdba3671d 100644
--- a/src/tools/rcc/rcc.cpp
+++ b/src/tools/rcc/rcc.cpp
@@ -21,7 +21,7 @@
# include <zstd.h>
#endif
-// Note: A copy of this file is used in Qt Designer (qttools/src/designer/src/lib/shared/rcc.cpp)
+// Note: A copy of this file is used in Qt Widgets Designer (qttools/src/designer/src/lib/shared/rcc.cpp)
QT_BEGIN_NAMESPACE
@@ -321,7 +321,7 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
// some info
if (text || pass1) {
lib.writeString(" // ");
- lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit());
+ lib.writeByteArray(m_fileInfo.fileName().toLocal8Bit());
lib.writeString("\n ");
}
diff --git a/src/tools/rcc/rcc.h b/src/tools/rcc/rcc.h
index 60af1c67cf..bfc3503da8 100644
--- a/src/tools/rcc/rcc.h
+++ b/src/tools/rcc/rcc.h
@@ -2,7 +2,7 @@
// Copyright (C) 2018 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-// Note: A copy of this file is used in Qt Designer (qttools/src/designer/src/lib/shared/rcc_p.h)
+// Note: A copy of this file is used in Qt Widgets Designer (qttools/src/designer/src/lib/shared/rcc_p.h)
#ifndef RCC_H
#define RCC_H
diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp
index 893cc5b8ec..c9356a4111 100644
--- a/src/tools/uic/cpp/cppwriteinitialization.cpp
+++ b/src/tools/uic/cpp/cppwriteinitialization.cpp
@@ -1393,8 +1393,8 @@ void WriteInitialization::writeProperties(const QString &varName,
case DomProperty::CursorShape:
if (p->hasAttributeStdset() && !p->attributeStdset())
varNewName += language::derefPointer + "viewport()"_L1;
- propertyValue = "QCursor(Qt"_L1 + language::qualifier
- + p->elementCursorShape() + u')';
+ propertyValue = "QCursor(Qt"_L1 + language::qualifier + "CursorShape"_L1
+ + language::qualifier + p->elementCursorShape() + u')';
break;
case DomProperty::Enum:
propertyValue = p->elementEnum();
@@ -1708,8 +1708,9 @@ static void writeIconAddFile(QTextStream &output, const QString &indent,
{
output << indent << iconName << ".addFile("
<< language::qstring(fileName, indent) << ", QSize(), QIcon"
- << language::qualifier << mode << ", QIcon" << language::qualifier
- << state << ')' << language::eol;
+ << language::qualifier << "Mode" << language::qualifier << mode
+ << ", QIcon" << language::qualifier << "State" << language::qualifier << state
+ << ')' << language::eol;
}
// Post 4.4 write resource icon
@@ -1757,7 +1758,8 @@ static void writeIconAddPixmap(QTextStream &output, const QString &indent,
const char *mode, const char *state)
{
output << indent << iconName << ".addPixmap(" << call << ", QIcon"
- << language::qualifier << mode << ", QIcon" << language::qualifier
+ << language::qualifier << "Mode" << language::qualifier << mode
+ << ", QIcon" << language::qualifier << "State" << language::qualifier
<< state << ')' << language::eol;
}
@@ -2153,7 +2155,7 @@ QString WriteInitialization::pixCall(const DomProperty *p) const
s = p->elementPixmap()->text();
break;
default:
- qWarning("%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Designer.",
+ qWarning("%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Qt Widgets Designer.",
qPrintable(m_option.messagePrefix()));
return "QIcon()"_L1;
break;
diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp
index b122c0f895..74eeab8387 100644
--- a/src/tools/uic/python/pythonwriteimports.cpp
+++ b/src/tools/uic/python/pythonwriteimports.cpp
@@ -229,9 +229,13 @@ void WriteImports::addPythonCustomWidget(const QString &className, const DomCust
QString modulePath = node->elementHeader()->text();
// Replace the '/' by '.'
modulePath.replace(u'/', u'.');
- // '.h' is added by default on headers for <customwidget>
- if (modulePath.endsWith(".h"_L1))
+ // '.h' is added by default on headers for <customwidget>.
+ if (modulePath.endsWith(".h"_L1, Qt::CaseInsensitive))
modulePath.chop(2);
+ else if (modulePath.endsWith(".hh"_L1))
+ modulePath.chop(3);
+ else if (modulePath.endsWith(".hpp"_L1))
+ modulePath.chop(4);
insertClass(modulePath, className, &m_customWidgets);
}
}
diff --git a/src/tools/uic/uic.cpp b/src/tools/uic/uic.cpp
index fb0a37d21d..1b10e1d722 100644
--- a/src/tools/uic/uic.cpp
+++ b/src/tools/uic/uic.cpp
@@ -165,7 +165,7 @@ DomUI *Uic::parseUiFile(QXmlStreamReader &reader)
&& !ui) {
const double version = versionFromUiAttribute(reader);
if (version < 4.0) {
- const QString msg = QString::fromLatin1("uic: File generated with too old version of Qt Designer (%1)").arg(version);
+ const QString msg = QString::fromLatin1("uic: File generated with too old version of Qt Widgets Designer (%1)").arg(version);
fprintf(stderr, "%s\n", qPrintable(msg));
return nullptr;
}
@@ -202,7 +202,7 @@ bool Uic::write(QIODevice *in)
double version = ui->attributeVersion().toDouble();
if (version < 4.0) {
- fprintf(stderr, "uic: File generated with too old version of Qt Designer\n");
+ fprintf(stderr, "uic: File generated with too old version of Qt Widgets Designer\n");
return false;
}
diff --git a/src/tools/windeployqt/main.cpp b/src/tools/windeployqt/main.cpp
index 837d4c7bbc..dca9132e15 100644
--- a/src/tools/windeployqt/main.cpp
+++ b/src/tools/windeployqt/main.cpp
@@ -137,7 +137,12 @@ static Platform platformFromMkSpec(const QString &xSpec)
return WindowsDesktopClangMinGW;
if (xSpec.contains("clang-msvc++"_L1))
return WindowsDesktopClangMsvc;
- return xSpec.contains("g++"_L1) ? WindowsDesktopMinGW : WindowsDesktopMsvc;
+ if (xSpec.contains("arm"_L1))
+ return WindowsDesktopMsvcArm;
+ if (xSpec.contains("G++"_L1))
+ return WindowsDesktopMinGW;
+
+ return WindowsDesktopMsvc;
}
return UnknownPlatform;
}
@@ -183,7 +188,7 @@ struct Options {
bool softwareRasterizer = true;
bool ffmpeg = true;
PluginSelections pluginSelections;
- Platform platform = WindowsDesktopMsvc;
+ Platform platform = WindowsDesktopMsvcIntel;
ModuleBitset additionalLibraries;
ModuleBitset disabledLibraries;
unsigned updateFileFlags = 0;
@@ -563,13 +568,14 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
options->quickImports = !parser->isSet(noQuickImportOption);
// default to deployment of compiler runtime for windows desktop configurations
- if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopMsvc
+ if (options->platform == WindowsDesktopMinGW || options->platform.testFlags(WindowsDesktopMsvc)
|| parser->isSet(compilerRunTimeOption))
options->compilerRunTime = true;
if (parser->isSet(noCompilerRunTimeOption))
options->compilerRunTime = false;
- if (options->compilerRunTime && options->platform != WindowsDesktopMinGW && options->platform != WindowsDesktopMsvc) {
+ if (options->compilerRunTime && options->platform != WindowsDesktopMinGW
+ && !options->platform.testFlags(WindowsDesktopMsvc)) {
*errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only.");
return CommandLineParseError;
}
@@ -1363,7 +1369,8 @@ static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platfor
break;
}
#ifdef Q_OS_WIN
- case WindowsDesktopMsvc: { // MSVC/Desktop: Add redistributable packages.
+ case WindowsDesktopMsvcIntel:
+ case WindowsDesktopMsvcArm: { // MSVC/Desktop: Add redistributable packages.
QString vcRedistDirName = vcRedistDir();
if (vcRedistDirName.isEmpty())
break;
@@ -1923,6 +1930,24 @@ int main(int argc, char **argv)
}
options.platform = platformFromMkSpec(xSpec);
+ // We are on MSVC and not crosscompiling. We need the host arch
+ if (options.platform == WindowsDesktopMsvc) {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ switch (si.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ case PROCESSOR_ARCHITECTURE_IA64:
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ options.platform |= IntelBased;
+ break;
+ case PROCESSOR_ARCHITECTURE_ARM:
+ case PROCESSOR_ARCHITECTURE_ARM64:
+ options.platform |= ArmBased;
+ break;
+ default:
+ options.platform = UnknownPlatform;
+ }
+ }
if (options.platform == UnknownPlatform) {
std::wcerr << "Unsupported platform " << xSpec << '\n';
return 1;
diff --git a/src/tools/windeployqt/utils.h b/src/tools/windeployqt/utils.h
index 2c7cd79bf0..fb3ba0b40b 100644
--- a/src/tools/windeployqt/utils.h
+++ b/src/tools/windeployqt/utils.h
@@ -29,7 +29,9 @@ enum PlatformFlag {
ClangMsvc = 0x00400,
ClangMinGW = 0x00800,
// Platforms
- WindowsDesktopMsvc = WindowsBased + IntelBased + Msvc,
+ WindowsDesktopMsvc = WindowsBased + Msvc,
+ WindowsDesktopMsvcIntel = WindowsDesktopMsvc + IntelBased,
+ WindowsDesktopMsvcArm = WindowsDesktopMsvc + ArmBased,
WindowsDesktopMinGW = WindowsBased + IntelBased + MinGW,
WindowsDesktopClangMsvc = WindowsBased + IntelBased + ClangMsvc,
WindowsDesktopClangMinGW = WindowsBased + IntelBased + ClangMinGW,
diff --git a/src/widgets/Qt6WidgetsMacros.cmake b/src/widgets/Qt6WidgetsMacros.cmake
index b15d1fe81d..a7ff7af2f3 100644
--- a/src/widgets/Qt6WidgetsMacros.cmake
+++ b/src/widgets/Qt6WidgetsMacros.cmake
@@ -49,3 +49,293 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
endif()
+
+function(qt6_add_ui target)
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "Target \"${target}\" does not exist.")
+ endif()
+
+ set(options)
+ set(oneValueArgs INCLUDE_PREFIX)
+ set(multiValueArgs SOURCES OPTIONS)
+
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
+ ${ARGN})
+
+ set(sources ${arg_SOURCES})
+ set(ui_options ${arg_OPTIONS})
+ set(raw_include_prefix "${arg_INCLUDE_PREFIX}")
+
+ if("${sources}" STREQUAL "")
+ message(FATAL_ERROR "The \"SOURCES\" parameter is empty.")
+ endif()
+
+
+ # Disable AUTOUIC for the target explicitly to avoid the AUTOUIC
+ # error message when the AUTOUIC is enabled for the target.
+ set_target_properties(${target} PROPERTIES AUTOUIC OFF)
+
+ if(NOT "${raw_include_prefix}" STREQUAL "")
+ # generate dummy `_` folders from the given path
+ # e.g. if the given path is `../a/b/c`, then the generated path will be
+ # `_`. if the given path is ``../a/../b/c`, then the generated path will
+ # be `_/_`
+ function(_qt_internal_generate_dash_path_from_input input_path
+ out_generated_dash_path)
+ string(REGEX MATCHALL "\\.\\." upper_folder_list "${input_path}")
+
+ list(JOIN upper_folder_list "" upper_folder_list)
+ string(REGEX REPLACE "\\.\\." "_/" additional_path
+ "${upper_folder_list}")
+
+ # remove last / character
+ if(NOT "${additional_path}" STREQUAL "")
+ string(LENGTH "${additional_path}" additional_path_length)
+ math(EXPR additional_path_length "${additional_path_length} - 1")
+ string(SUBSTRING "${additional_path}" 0 ${additional_path_length}
+ additional_path)
+ endif()
+
+ set(${out_generated_dash_path} "${additional_path}" PARENT_SCOPE)
+ endfunction()
+ # NOTE: If previous folders are less than ../ folder count in
+ # ${raw_include_prefix}, relative path calculation will miscalculate,
+ # so we need to add dummy folders to calculate the relative path
+ # correctly
+ _qt_internal_generate_dash_path_from_input("${raw_include_prefix}"
+ dummy_path_for_relative_calculation)
+ if(NOT "${dummy_path_for_relative_calculation}" STREQUAL "")
+ set(dummy_path_for_relative_calculation
+ "/${dummy_path_for_relative_calculation}")
+ set(raw_include_prefix_to_compare
+ "${dummy_path_for_relative_calculation}/${raw_include_prefix}")
+ else()
+ set(dummy_path_for_relative_calculation "/")
+ set(raw_include_prefix_to_compare "/${raw_include_prefix}")
+ endif()
+ # NOTE: This relative path calculation could be done just by using the
+ # below code
+ # cmake_path(RELATIVE_PATH normalized_include_prefix "${CMAKE_CURRENT_SOURCE_DIR}"
+ # but due to the backward compatibility, we need to use
+ # file(RELATIVE_PATH) and ../ folder calculation the with
+ # _qt_internal_generate_dash_path_from_input() function
+ if(WIN32)
+ set(dummy_path_for_relative_calculation
+ "${CMAKE_CURRENT_SOURCE_DIR}/${dummy_path_for_relative_calculation}")
+ set(raw_include_prefix_to_compare
+ "${CMAKE_CURRENT_SOURCE_DIR}/${raw_include_prefix_to_compare}")
+ string(REGEX REPLACE "//" "/" dummy_path_for_relative_calculation
+ "${dummy_path_for_relative_calculation}")
+ string(REGEX REPLACE "//" "/" raw_include_prefix_to_compare
+ "${raw_include_prefix_to_compare}")
+ endif()
+
+ file(RELATIVE_PATH normalized_include_prefix
+ "${dummy_path_for_relative_calculation}"
+ "${raw_include_prefix_to_compare}")
+
+ # if normalized_include_prefix ends with `/` remove it
+ string(REGEX REPLACE "/$" "" normalized_include_prefix
+ "${normalized_include_prefix}")
+
+ _qt_internal_generate_dash_path_from_input("${normalized_include_prefix}"
+ additional_path)
+ endif()
+
+ if(ui_options MATCHES "\\$<CONFIG")
+ set(is_ui_options_contains_config true)
+ endif()
+ get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi AND is_ui_options_contains_config)
+ set(include_folder "$<CONFIG>")
+ endif()
+
+ set(include_folder_to_add "${include_folder}")
+ if(NOT "${additional_path}" STREQUAL "")
+ set(include_folder_to_add "${include_folder_to_add}/${additional_path}")
+ endif()
+
+ set(prefix_info_file_cmake
+ "${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen/prefix_info.cmake")
+ if(EXISTS ${prefix_info_file_cmake})
+ include(${prefix_info_file_cmake})
+ set(prefix_info_file_cmake_exists true)
+ else()
+ set(prefix_info_file_cmake_exists false)
+ endif()
+
+ foreach(source_file ${sources})
+ get_filename_component(outfile "${source_file}" NAME_WE)
+ get_filename_component(infile "${source_file}" ABSOLUTE)
+ string(SHA1 infile_hash "${target}${infile}")
+ string(SUBSTRING "${infile_hash}" 0 6 short_hash)
+ set(file_ui_folder "${CMAKE_CURRENT_BINARY_DIR}/.qt/${short_hash}")
+ target_include_directories(${target} SYSTEM PRIVATE
+ "${file_ui_folder}/${include_folder_to_add}")
+
+ set(target_include_folder_with_add_path
+ "${file_ui_folder}/${include_folder}")
+ # Add additional path to include folder if it is not empty
+ if(NOT "${additional_path}" STREQUAL "")
+ set(target_include_folder_with_add_path
+ "${target_include_folder_with_add_path}/${additional_path}")
+ endif()
+
+ set(inc_dir_to_create "${target_include_folder_with_add_path}")
+ if(NOT "${raw_include_prefix}" STREQUAL "")
+ set(inc_dir_to_create
+ "${target_include_folder_with_add_path}/${raw_include_prefix}")
+ endif()
+
+ set(output_directory "${target_include_folder_with_add_path}")
+ if(NOT "${normalized_include_prefix}" STREQUAL "")
+ set(output_directory
+ "${output_directory}/${normalized_include_prefix}")
+ endif()
+
+ if(NOT EXISTS "${infile}")
+ message(FATAL_ERROR "${infile} does not exist.")
+ endif()
+ set_source_files_properties(${infile} PROPERTIES SKIP_AUTOUIC ON)
+
+ macro(_qt_internal_set_output_file_properties file)
+ set_source_files_properties(${file} PROPERTIES
+ SKIP_AUTOMOC TRUE
+ SKIP_AUTOUIC TRUE
+ SKIP_LINTING TRUE)
+ endmacro()
+
+ set(outfile "${output_directory}/ui_${outfile}.h")
+ # Before CMake 3.27, there is a bug for using $<CONFIG> in a generated
+ # file with Ninja Multi-Config generator. To avoid this issue, we need
+ # to add the generated file for each configuration.
+ # Explicitly set the output file properties for each configuration
+ # to avoid Policy CMP0071 warnings.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/24848
+ # Xcode generator cannot handle $<CONFIG> in the output file name.
+ # it changes $<CONFIG> with NOCONFIG. That's why we need to add the
+ # generated file for each configuration for Xcode generator as well.
+ if(is_multi AND outfile MATCHES "\\$<CONFIG>"
+ AND CMAKE_VERSION VERSION_LESS "3.27"
+ OR CMAKE_GENERATOR MATCHES "Xcode")
+ foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ string(REPLACE "$<CONFIG>" "${config}" outfile_with_config
+ "${outfile}")
+ _qt_internal_set_output_file_properties(
+ ${outfile_with_config})
+ target_sources(${target} PRIVATE ${outfile_with_config})
+ endforeach()
+ else()
+ _qt_internal_set_output_file_properties(${outfile})
+ target_sources(${target} PRIVATE ${outfile})
+ endif()
+ # remove double slashes
+ string(REGEX REPLACE "//" "/" outfile "${outfile}")
+
+ # Note: If INCLUDE_PREFIX is changed without changing the corresponding
+ # include path in the source file and Ninja generator is used, this
+ # casues the double build issue. To avoid this issue, we need to
+ # remove the output file in configure step if the include_prefix is
+ # changed.
+ if(CMAKE_GENERATOR MATCHES "Ninja")
+ if(prefix_info_file_cmake_exists)
+ if(NOT "${${short_hash}_prefix}" STREQUAL
+ "${normalized_include_prefix}")
+ file(REMOVE_RECURSE "${file_ui_folder}")
+ list(APPEND prefix_info_list
+ "set(${short_hash}_prefix \"${normalized_include_prefix}\")")
+ elseif(NOT DEFINED ${short_hash}_prefix)
+ list(APPEND prefix_info_list
+ "set(${short_hash}_prefix \"${normalized_include_prefix}\")")
+ endif()
+ else()
+ set(prefix_info_list "")
+ list(APPEND prefix_info_list
+ "set(${short_hash}_prefix \"${normalized_include_prefix}\")")
+ endif()
+ file(MAKE_DIRECTORY ${file_ui_folder})
+ endif()
+
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.17")
+ set(remove_command rm -rf)
+ else()
+ set(remove_command "remove_directory")
+ endif()
+
+ add_custom_command(OUTPUT ${outfile}
+ DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::uic
+ COMMAND ${CMAKE_COMMAND} -E ${remove_command} "${file_ui_folder}/${include_folder}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${inc_dir_to_create}
+ COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::uic ${ui_options} -o
+ ${outfile} ${infile}
+ COMMAND_EXPAND_LISTS
+ MAIN_DEPENDENCY ${infile} VERBATIM)
+ endforeach()
+
+
+ get_target_property(is_guard_on ${target} _qt_ui_property_check_guard)
+ if(NOT is_guard_on)
+ # Ninja fails when a newline is used. That's why message is
+ # divided into parts.
+ set(error_message_1
+ "Error: The target \"${target}\" has \"AUTOUIC\" enabled.")
+ set(error_message_2
+ "Error: Please disable \"AUTOUIC\" for the target \"${target}\".")
+
+ set(ui_property_check_dummy_file
+ "${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen/ui_property_check_timestamp")
+
+ add_custom_command(OUTPUT ${ui_property_check_dummy_file}
+ COMMAND ${CMAKE_COMMAND} -E make_directory
+ "${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen"
+ COMMAND ${CMAKE_COMMAND} -E touch ${ui_property_check_dummy_file}
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;echo;${error_message_1}>"
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;echo;${error_message_2}>"
+ # Remove the dummy file so that the error message is shown until
+ # the AUTOUIC is disabled. Otherwise, the error message is shown
+ # only once when the AUTOUIC is enabled with Visual Studio generator.
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;remove;${ui_property_check_dummy_file}>"
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;false>"
+ COMMAND_EXPAND_LISTS
+ VERBATIM)
+
+ # When AUTOUIC is enabled, AUTOUIC runs before ${target}_ui_property_check
+ # target. So we need to add ${target}_ui_property_check as a dependency
+ # to ${target} to make sure that AUTOUIC runs after ${target}_ui_property_check
+ if (NOT QT_NO_MIX_UI_AUTOUIC_CHECK)
+ set_target_properties(${target} PROPERTIES
+ _qt_ui_property_check_guard ON)
+ add_custom_target(${target}_ui_property_check
+ ALL DEPENDS ${ui_property_check_dummy_file})
+ _qt_internal_assign_to_internal_targets_folder(
+ ${target}_ui_property_check)
+ add_dependencies(${target} ${target}_ui_property_check)
+ endif()
+ endif()
+
+ # write prefix info file
+ if(CMAKE_GENERATOR MATCHES "Ninja")
+ list(PREPEND prefix_info_list "include_guard()")
+ string(REPLACE ";" "\n" prefix_info_list "${prefix_info_list}")
+ file(WRITE "${prefix_info_file_cmake}" "${prefix_info_list}")
+ endif()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_add_ui)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_add_ui(${ARGN})
+ else()
+ message(FATAL_ERROR "qt_add_ui() is only available in Qt 6.")
+ endif()
+ endfunction()
+endif()
+
diff --git a/src/widgets/accessible/itemviews_p.h b/src/widgets/accessible/itemviews_p.h
index ddc97baba1..077f14de1d 100644
--- a/src/widgets/accessible/itemviews_p.h
+++ b/src/widgets/accessible/itemviews_p.h
@@ -144,8 +144,6 @@ public:
private:
QModelIndex indexFromLogical(int row, int column = 0) const;
-
- inline int logicalIndex(const QModelIndex &index) const;
};
#endif
diff --git a/src/widgets/accessible/qaccessiblewidgetfactory.cpp b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
index e13b7ebcf7..664e35a6e7 100644
--- a/src/widgets/accessible/qaccessiblewidgetfactory.cpp
+++ b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
@@ -121,7 +121,6 @@ QAccessibleInterface *qAccessibleFactory(const QString &classname, QObject *obje
#if QT_CONFIG(itemviews)
} else if (classname == "QTableView"_L1 || classname == "QListView"_L1) {
iface = new QAccessibleTable(widget);
- // ### This should be cleaned up. We return the parent for the scrollarea to hide it.
#endif // QT_CONFIG(itemviews)
#if QT_CONFIG(tabbar)
} else if (classname == "QTabBar"_L1) {
diff --git a/src/widgets/dialogs/qdialog.h b/src/widgets/dialogs/qdialog.h
index 4d11fe2d8d..22360bc358 100644
--- a/src/widgets/dialogs/qdialog.h
+++ b/src/widgets/dialogs/qdialog.h
@@ -28,6 +28,7 @@ public:
~QDialog();
enum DialogCode { Rejected, Accepted };
+ Q_ENUM(DialogCode)
int result() const;
diff --git a/src/widgets/doc/snippets/cmake-macros/examples.cmake b/src/widgets/doc/snippets/cmake-macros/examples.cmake
index 3c58509fdf..7d0023aed4 100644
--- a/src/widgets/doc/snippets/cmake-macros/examples.cmake
+++ b/src/widgets/doc/snippets/cmake-macros/examples.cmake
@@ -6,3 +6,30 @@ set(SOURCES mainwindow.cpp main.cpp)
qt_wrap_ui(SOURCES mainwindow.ui)
qt_add_executable(myapp ${SOURCES})
#! [qt_wrap_ui]
+
+#! [qt6_add_ui_1]
+qt_add_executable(myapp mainwindow.cpp main.cpp)
+qt6_add_ui(myapp SOURCES mainwindow.ui)
+#! [qt6_add_ui_1]
+
+#! [qt6_add_ui_2]
+qt_add_executable(myapp mainwindow.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files" SOURCES mainwindow.ui)
+#! [qt6_add_ui_2]
+
+#! [qt6_add_ui_3]
+qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files" SOURCES widget1.ui widget2.ui)
+#! [qt6_add_ui_3]
+
+#! [qt6_add_ui_4]
+qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files"
+ SOURCES "my_ui_files_1/widget1.ui" "my_ui_files_2/widget2.ui")
+#! [qt6_add_ui_4]
+
+#! [qt6_add_ui_5]
+qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files_1" SOURCES "my_ui_files/widget1.ui")
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files_2" SOURCES "my_ui_files/widget2.ui")
+#! [qt6_add_ui_5]
diff --git a/src/widgets/doc/snippets/cmake-macros/examples.cpp b/src/widgets/doc/snippets/cmake-macros/examples.cpp
new file mode 100644
index 0000000000..683f8453e4
--- /dev/null
+++ b/src/widgets/doc/snippets/cmake-macros/examples.cpp
@@ -0,0 +1,26 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+//! [qt6_add_ui_1]
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+//! [qt6_add_ui_1]
+
+//! [qt6_add_ui_2]
+#include "mainwindow.h"
+#include "src/files/ui_mainwindow.h"
+//! [qt6_add_ui_2]
+
+//! [qt6_add_ui_3_1]
+#include "src/files/ui_widget1.h"
+//! [qt6_add_ui_3_1]
+
+//! [qt6_add_ui_3_2]
+#include "src/files/ui_widget2.h"
+//! [qt6_add_ui_3_2]
+
+//! [qt6_add_ui_5]
+#include "src/files_1/ui_widget1.h"
+#include "src/files_2/ui_widget2.h"
+//! [qt6_add_ui_5]
diff --git a/src/widgets/doc/src/cmake-macros.qdoc b/src/widgets/doc/src/cmake-macros.qdoc
index 13bdcca67b..906a18b2b0 100644
--- a/src/widgets/doc/src/cmake-macros.qdoc
+++ b/src/widgets/doc/src/cmake-macros.qdoc
@@ -30,6 +30,10 @@ directory. The paths of the generated header files are added to \c{<VAR>}.
\note This is a low-level macro. See the \l{CMake AUTOUIC Documentation} for a
more convenient way to process \c{.ui} files with \c{uic}.
+Since 6.8:
+\note \l{qt6_add_ui}{qt_add_ui} is the recommended way to process \c{.ui}
+files.
+
\section1 Options
You can set additional \c{OPTIONS} that should be added to the \c{uic} calls.
@@ -39,3 +43,132 @@ You can find possible options in the \l{uic}{uic documentation}.
\snippet cmake-macros/examples.cmake qt_wrap_ui
*/
+
+/*!
+\page qt-add-ui.html
+\ingroup cmake-macros-qtwidgets
+
+\title qt_add_ui
+\keyword qt6_add_ui
+
+\summary {Adds .ui files to a target.}
+
+\include cmake-find-package-widgets.qdocinc
+
+\section1 Synopsis
+
+\badcode
+qt_add_ui(<TARGET>
+ SOURCES file1.ui [file2.ui ...]
+ [INCLUDE_PREFIX <PREFIX>]
+ [OPTIONS ...])
+\endcode
+
+\versionlessCMakeCommandsNote qt6_add_ui()
+
+\cmakecommandsince 6.8
+
+\section1 Description
+
+Creates rules for calling the \l{uic}{User Interface Compiler (uic)} on the
+\c{.ui} files. For each input file, a header file is generated in the build
+directory. The generated header files are added to sources of the target.
+
+\section1 Arguments
+
+\section2 TARGET
+
+The \c{TARGET} argument specifies the CMake target to which the generated header
+files will be added.
+
+\section2 SOURCES
+
+The \c{SOURCES} argument specifies the list of \c{.ui} files to process.
+
+\section2 INCLUDE_PREFIX
+
+\c INCLUDE_PREFIX specifies the include prefix for the generated header files.
+Use the same include prefix as in the \c{#include} directive in the source
+files. If \c{ui_<basename>.h} is included without a prefix, then this argument
+can be omitted.
+
+\section2 OPTIONS
+
+You can set additional \c{OPTIONS} that should be added to the \c{uic} calls.
+You can find possible options in the \l{uic}{uic documentation}.
+
+\section1 Examples
+
+\section2 Without INCLUDE_PREFIX
+
+In the following snippet, the \c{mainwindow.cpp} file includes
+\c{ui_mainwindow.h} and \c{mainwindow.h}.
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_1
+
+\c{CMakeLists.txt} is implemented as follows and it calls
+\l{qt6_add_ui}{qt_add_ui} to add \c{ui_mainwindow.h} to the \c{myapp} target.
+
+\snippet cmake-macros/examples.cmake qt6_add_ui_1
+
+In the above example, \c{ui_mainwindow.h} is included without a prefix. So the
+\c{INCLUDE_PREFIX} argument is not specified.
+
+\section2 With INCLUDE_PREFIX
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_2
+
+In the above snippet, \c{mainwindow.cpp} includes \c{ui_mainwindow.h} with a
+prefix.
+
+\snippet cmake-macros/examples.cmake qt6_add_ui_2
+
+Since \c{ui_mainwindow.h} is included with a prefix, the \c{INCLUDE_PREFIX}
+argument is specified as \c{src/files} in the above example.
+
+\section2 Multiple .ui files
+
+In the following snippets, both \c{widget1.cpp} and \c{widget2.cpp} include
+\c{ui_widget1.h} and \c{ui_widget2.h} respectively.
+
+\c{widget1.cpp}:
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_3_1
+
+\c{widget2.cpp}:
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_3_2
+
+Both \c{ui_widget1.h} and \c{ui_widget2.h} are included with the same prefix
+
+\snippet cmake-macros/examples.cmake qt6_add_ui_3
+
+In this case, the \c{INCLUDE_PREFIX} argument can be specified as \c{src/files}
+for both files in the above snippet.
+
+\section1 When to prefer \l{qt6_add_ui}{qt_add_ui} over \c{AUTOUIC}?
+
+\l{qt6_add_ui}{qt_add_ui} has some advantages over \c{AUTOUIC}:
+
+\list
+\li \l{qt6_add_ui}{qt_add_ui} ensures that the \c{.ui} files are generated
+correctly during the first build, for the \c{Ninja} and \c{Ninja Multi-Config}
+generators.
+
+\li \l{qt6_add_ui}{qt_add_ui} guarantees that the generated \c{.h} files are
+not leaked outside the build directory.
+
+\li Since \l{qt6_add_ui}{qt_add_ui} does not scan source files, it provides a
+faster build than \c{AUTOUIC}.
+
+\endlist
+
+\section1 When to prefer \l{qt6_add_ui}{qt_add_ui} over \c{qt_wrap_ui}?
+
+\l{qt6_add_ui}{qt_add_ui} has the \c{INCLUDE_PREFIX} argument, which can be used to
+specify the include prefix for the generated header files.
+
+\note It is not recommended to use both \l{qt6_add_ui}{qt_add_ui} and
+\c{AUTOUIC} for the same target.
+
+*/
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index de7d93ce20..a1392e10dc 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -1094,6 +1094,12 @@ QPalette QApplicationPrivate::basePalette() const
if (const QPalette *themePalette = platformTheme() ? platformTheme()->palette() : nullptr)
palette = themePalette->resolve(palette);
+ // This palette now is Qt-generated, so reset the resolve mask. This allows
+ // QStyle::polish implementations to respect palettes that are user provided,
+ // by checking if the palette has a brush set for a color that the style might
+ // otherwise overwrite.
+ palette.setResolveMask(0);
+
// Finish off by letting the application style polish the palette. This will
// not result in the polished palette becoming a user-set palette, as the
// resulting base palette is only used as a fallback, with the resolve mask
diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp
index c93876c500..edb159bbbf 100644
--- a/src/widgets/kernel/qgesturemanager.cpp
+++ b/src/widgets/kernel/qgesturemanager.cpp
@@ -610,7 +610,8 @@ void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt));
target = child ? child : topLevel;
}
- } else {
+ }
+ if (!target) {
// or use the context of the gesture
QObject *context = m_gestureOwners.value(gesture, 0);
if (context->isWidgetType())
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 2cc40fc7ad..ead633cda3 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -5160,6 +5160,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
const QRegion oldSystemClip = enginePriv->systemClip;
const QRegion oldBaseClip = enginePriv->baseSystemClip;
const QRegion oldSystemViewport = enginePriv->systemViewport;
+ const Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
// This ensures that all painting triggered by render() is clipped to the current engine clip.
if (painter->hasClipping()) {
@@ -5168,6 +5169,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
} else {
enginePriv->setSystemViewport(oldSystemClip);
}
+ painter->setLayoutDirection(layoutDirection());
d->render(target, targetOffset, toBePainted, renderFlags);
@@ -5175,6 +5177,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
enginePriv->baseSystemClip = oldBaseClip;
enginePriv->setSystemTransformAndViewport(oldTransform, oldSystemViewport);
enginePriv->systemStateChanged();
+ painter->setLayoutDirection(oldLayoutDirection);
// Restore shared painter.
d->setSharedPainter(oldPainter);
@@ -6616,7 +6619,9 @@ void QWidgetPrivate::setFocus_sys()
{
Q_Q(QWidget);
// Embedded native widget may have taken the focus; get it back to toplevel
- // if that is the case (QTBUG-25852)
+ // if that is the case (QTBUG-25852), unless widget is a window container.
+ if (extra && extra->hasWindowContainer)
+ return;
// Do not activate in case the popup menu opens another application (QTBUG-70810)
// unless the application is embedded (QTBUG-71991).
if (QWindow *nativeWindow = q->testAttribute(Qt::WA_WState_Created) ? q->window()->windowHandle() : nullptr) {
@@ -7689,11 +7694,15 @@ QMargins QWidgetPrivate::safeAreaMargins() const
return QMargins();
// Or, if one of our ancestors are in a layout that does not have WA_LayoutOnEntireRect
- // set, then we know that the layout has already taken care of placing us inside the
- // safe area, by taking the contents rect of its parent widget into account.
+ // set, and the widget respects the safe area, then we know that the layout has already
+ // taken care of placing us inside the safe area, by taking the contents rect of its
+ // parent widget into account.
const QWidget *assumedSafeWidget = nullptr;
for (const QWidget *w = q; w != nativeWidget; w = w->parentWidget()) {
QWidget *parentWidget = w->parentWidget();
+ if (!parentWidget->testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea))
+ continue; // Layout can't help us
+
if (parentWidget->testAttribute(Qt::WA_LayoutOnEntireRect))
continue; // Layout not going to help us
@@ -13612,7 +13621,8 @@ bool QWidgetPrivate::isInFocusChain() const
when the focus chain has been initialized. A newly constructed widget is considered to have
a consistent focus chain, while not being part of a focus chain.
- This method returns \c true early, if a widget is pointing to itself.
+ The method always returns \c true, when the logging category "qt.widgets.focus" is disabled.
+ When it is enabled, the method returns \c true early, if a widget is pointing to itself.
It returns \c false, if one of the following is detected:
\list
\li nullptr found in a previous/next pointer.
@@ -13629,6 +13639,10 @@ bool QWidgetPrivate::isInFocusChain() const
bool QWidgetPrivate::isFocusChainConsistent() const
{
Q_Q(const QWidget);
+ const bool skip = !QLoggingCategory("qt.widgets.focus").isDebugEnabled();
+ if (skip)
+ return true;
+
if (!isInFocusChain())
return true;
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index f51baba88b..03dde9ca69 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -77,6 +77,39 @@ public:
widget->focusWidget()->clearFocus();
}
+ void setFocusToTarget(FocusTarget target, Qt::FocusReason reason) override
+ {
+ Q_Q(QWidgetWindow);
+ QWidget *widget = q->widget();
+ if (!widget)
+ return;
+ QWidget *newFocusWidget = nullptr;
+
+ switch (target) {
+ case FocusTarget::First:
+ newFocusWidget = q->getFocusWidget(QWidgetWindow::FirstFocusWidget);
+ break;
+ case FocusTarget::Last:
+ newFocusWidget = q->getFocusWidget(QWidgetWindow::LastFocusWidget);
+ break;
+ case FocusTarget::Next: {
+ QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
+ newFocusWidget = focusWidget->nextInFocusChain() ? focusWidget->nextInFocusChain() : focusWidget;
+ break;
+ }
+ case FocusTarget::Prev: {
+ QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
+ newFocusWidget = focusWidget->previousInFocusChain() ? focusWidget->previousInFocusChain() : focusWidget;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (newFocusWidget)
+ newFocusWidget->setFocus(reason);
+ }
+
QRectF closestAcceptableGeometry(const QRectF &rect) const override;
void processSafeAreaMarginsChanged() override
@@ -472,9 +505,6 @@ void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e)
void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
{
- static const QEvent::Type contextMenuTrigger =
- QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
- QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
if (QApplicationPrivate::inPopupMode()) {
QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
QPointF mapped = event->position();
@@ -591,7 +621,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
}
qt_replay_popup_mouse_event = false;
#ifndef QT_NO_CONTEXTMENU
- } else if (event->type() == contextMenuTrigger
+ } else if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
&& event->button() == Qt::RightButton
&& (openPopupCount == oldOpenPopupCount)) {
QWidget *receiver = activePopupWidget;
@@ -604,7 +634,6 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
QApplication::forwardEvent(receiver, &e, event);
}
#else
- Q_UNUSED(contextMenuTrigger);
Q_UNUSED(oldOpenPopupCount);
}
#endif
@@ -651,7 +680,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
event->setAccepted(translated.isAccepted());
}
#ifndef QT_NO_CONTEXTMENU
- if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton
+ if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
+ && event->button() == Qt::RightButton
&& m_widget->rect().contains(event->position().toPoint())) {
QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers());
QGuiApplication::forwardEvent(receiver, &e, event);
diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp
index c15ec54f35..1aaf04af43 100644
--- a/src/widgets/kernel/qwindowcontainer.cpp
+++ b/src/widgets/kernel/qwindowcontainer.cpp
@@ -5,6 +5,7 @@
#include "qwidget_p.h"
#include "qwidgetwindow_p.h"
#include <QtGui/qwindow.h>
+#include <QtGui/private/qwindow_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <QDebug>
@@ -28,7 +29,6 @@ public:
QWindowContainerPrivate()
: window(nullptr)
- , oldFocusWindow(nullptr)
, usesNativeWidgets(false)
{
}
@@ -103,7 +103,6 @@ public:
}
QPointer<QWindow> window;
- QWindow *oldFocusWindow;
QWindow fakeParent;
uint usesNativeWidgets : 1;
@@ -207,6 +206,7 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt:
}
d->window = embeddedWindow;
+ d->window->installEventFilter(this);
QString windowName = d->window->objectName();
if (windowName.isEmpty())
@@ -219,9 +219,6 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt:
setAcceptDrops(true);
- connect(qGuiApp, &QGuiApplication::focusWindowChanged,
- this, &QWindowContainer::focusWindowChanged);
-
connect(containedWindow(), &QWindow::minimumHeightChanged, this, &QWindowContainer::updateGeometry);
connect(containedWindow(), &QWindow::minimumWidthChanged, this, &QWindowContainer::updateGeometry);
}
@@ -244,30 +241,12 @@ QWindowContainer::~QWindowContainer()
// QEvent::PlatformSurface delivery relies on virtuals. Getting
// SurfaceAboutToBeDestroyed can be essential for OpenGL, Vulkan, etc.
// QWindow subclasses in particular. Keep these working.
- if (d->window)
+ if (d->window) {
+ d->window->removeEventFilter(this);
d->window->destroy();
+ }
delete d->window;
-
- disconnect(qGuiApp, &QGuiApplication::focusWindowChanged,
- this, &QWindowContainer::focusWindowChanged);
-}
-
-
-
-/*!
- \internal
- */
-
-void QWindowContainer::focusWindowChanged(QWindow *focusWindow)
-{
- Q_D(QWindowContainer);
- d->oldFocusWindow = focusWindow;
- if (focusWindow == d->window) {
- QWidget *widget = QApplication::focusWidget();
- if (widget)
- widget->clearFocus();
- }
}
/*!
@@ -284,8 +263,12 @@ bool QWindowContainer::eventFilter(QObject *o, QEvent *e)
QChildEvent *ce = static_cast<QChildEvent *>(e);
if (ce->child() == d->window) {
o->removeEventFilter(this);
+ d->window->removeEventFilter(this);
d->window = nullptr;
}
+ } else if (e->type() == QEvent::FocusIn) {
+ if (o == d->window)
+ setFocus(Qt::ActiveWindowFocusReason);
}
return false;
}
@@ -335,11 +318,16 @@ bool QWindowContainer::event(QEvent *e)
break;
case QEvent::FocusIn:
if (d->window->parent()) {
- if (d->oldFocusWindow != d->window) {
+ if (QGuiApplication::focusWindow() != d->window) {
+ QFocusEvent *event = static_cast<QFocusEvent *>(e);
+ const auto reason = event->reason();
+ QWindowPrivate::FocusTarget target = QWindowPrivate::FocusTarget::Current;
+ if (reason == Qt::TabFocusReason)
+ target = QWindowPrivate::FocusTarget::First;
+ else if (reason == Qt::BacktabFocusReason)
+ target = QWindowPrivate::FocusTarget::Last;
+ qt_window_private(d->window)->setFocusToTarget(target, reason);
d->window->requestActivate();
- } else {
- QWidget *next = nextInFocusChain();
- next->setFocus();
}
}
break;
diff --git a/src/widgets/kernel/qwindowcontainer_p.h b/src/widgets/kernel/qwindowcontainer_p.h
index a303f25424..0cbcc5321d 100644
--- a/src/widgets/kernel/qwindowcontainer_p.h
+++ b/src/widgets/kernel/qwindowcontainer_p.h
@@ -42,9 +42,6 @@ public:
protected:
bool event(QEvent *ev) override;
bool eventFilter(QObject *, QEvent *ev) override;
-
-private slots:
- void focusWindowChanged(QWindow *focusWindow);
};
QT_END_NAMESPACE
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 046af3a073..aab1192d50 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -750,70 +750,75 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
case PE_IndicatorArrowRight:
case PE_IndicatorArrowLeft:
{
- if (opt->rect.width() <= 1 || opt->rect.height() <= 1)
+ const QRect &r = opt->rect;
+ if (r.width() <= 1 || r.height() <= 1)
break;
- QRect r = opt->rect;
int size = qMin(r.height(), r.width());
QPixmap pixmap;
+ const qreal dpr = p->device()->devicePixelRatio();
const QString pixmapName = QStyleHelper::uniqueName("$qt_ia-"_L1
% QLatin1StringView(metaObject()->className())
% HexString<uint>(pe),
- opt, QSize(size, size));
+ opt, QSize(size, size), dpr);
if (!QPixmapCache::find(pixmapName, &pixmap)) {
- const qreal pixelRatio = p->device()->devicePixelRatio();
- const qreal border = pixelRatio * (size / 5.);
- const qreal sqsize = pixelRatio * size;
- QImage image(sqsize, sqsize, QImage::Format_ARGB32_Premultiplied);
- image.fill(Qt::transparent);
- QPainter imagePainter(&image);
-
- QPolygonF poly;
+ // dpr scaling does not work well on such small pixel sizes, do it on our own
+ const int border = 1 * dpr;
+ const int sizeDpr = size * dpr;
+ int width = sizeDpr - 2 * border - 1;
+ int height = width / 2;
+ const int add = ((width & 1) == 1);
+ if (pe == PE_IndicatorArrowRight || pe == PE_IndicatorArrowLeft)
+ std::swap(width, height);
+ pixmap = styleCachePixmap(QSize(sizeDpr, sizeDpr), 1);
+
+ std::array<QPointF, 4> poly;
switch (pe) {
case PE_IndicatorArrowUp:
- poly = {QPointF(border, sqsize / 2), QPointF(sqsize / 2, border), QPointF(sqsize - border, sqsize / 2)};
+ poly = {QPointF(0, height), QPointF(width, height),
+ QPointF(width / 2 + add, 0), QPointF(width / 2, 0)};
break;
case PE_IndicatorArrowDown:
- poly = {QPointF(border, sqsize / 2), QPointF(sqsize / 2, sqsize - border), QPointF(sqsize - border, sqsize / 2)};
+ poly = {QPointF(0, 0), QPointF(width, 0),
+ QPointF(width / 2 + add, height), QPointF(width / 2, height)};
break;
case PE_IndicatorArrowRight:
- poly = {QPointF(sqsize - border, sqsize / 2), QPointF(sqsize / 2, border), QPointF(sqsize / 2, sqsize - border)};
+ poly = {QPointF(0, 0), QPointF(0, height),
+ QPointF(width, height / 2 + add), QPointF(width, height / 2)};
break;
case PE_IndicatorArrowLeft:
- poly = {QPointF(border, sqsize / 2), QPointF(sqsize / 2, border), QPointF(sqsize / 2, sqsize - border)};
+ poly = {QPointF(width, 0), QPointF(width, height),
+ QPointF(0, height / 2 + add), QPointF(0, height / 2)};
break;
default:
break;
}
- int bsx = 0;
- int bsy = 0;
-
+ QPainter imagePainter(&pixmap);
+ imagePainter.translate((sizeDpr - width) / 2, (sizeDpr - height) / 2);
if (opt->state & State_Sunken) {
- bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
- bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
+ const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
+ const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
+ imagePainter.translate(bsx, bsy);
}
-
- const QRectF bounds = poly.boundingRect();
- const qreal sx = sqsize / 2 - bounds.center().x() - 1;
- const qreal sy = sqsize / 2 - bounds.center().y() - 1;
- imagePainter.translate(sx + bsx, sy + bsy);
imagePainter.setPen(opt->palette.buttonText().color());
imagePainter.setBrush(opt->palette.buttonText());
if (!(opt->state & State_Enabled)) {
- imagePainter.translate(1, 1);
+ const int ofs = qRound(1 * dpr);
+ imagePainter.translate(ofs, ofs);
imagePainter.setBrush(opt->palette.light().color());
imagePainter.setPen(opt->palette.light().color());
- imagePainter.drawPolygon(poly);
- imagePainter.translate(-1, -1);
+ imagePainter.drawPolygon(poly.data(), int(poly.size()));
+ imagePainter.drawPoints(poly.data(), int(poly.size()));
+ imagePainter.translate(-ofs, -ofs);
imagePainter.setBrush(opt->palette.mid().color());
imagePainter.setPen(opt->palette.mid().color());
}
-
- imagePainter.drawPolygon(poly);
+ imagePainter.drawPolygon(poly.data(), int(poly.size()));
+ // sometimes the corners are not drawn by drawPolygon for unknown reaons, so re-draw them again
+ imagePainter.drawPoints(poly.data(), int(poly.size()));
imagePainter.end();
- pixmap = QPixmap::fromImage(image);
- pixmap.setDevicePixelRatio(pixelRatio);
+ pixmap.setDevicePixelRatio(dpr);
QPixmapCache::insert(pixmapName, pixmap);
}
int xOffset = r.x() + (r.width() - size)/2;
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index 8328459976..6b8fd979a9 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -145,6 +145,7 @@ static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QS
return;
const qreal dpi = QStyleHelper::dpi(option);
+ const qreal dpr = painter->device()->devicePixelRatio();
const int arrowWidth = int(QStyleHelper::dpiScaled(14, dpi));
const int arrowHeight = int(QStyleHelper::dpiScaled(8, dpi));
@@ -156,10 +157,9 @@ static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QS
const QString cacheKey = QStyleHelper::uniqueName("fusion-arrow"_L1
% HexString<uint>(type)
% HexString<uint>(color.rgba()),
- option, rect.size());
+ option, rect.size(), dpr);
if (!QPixmapCache::find(cacheKey, &cachePixmap)) {
- cachePixmap = styleCachePixmap(rect.size());
- cachePixmap.fill(Qt::transparent);
+ cachePixmap = styleCachePixmap(rect.size(), dpr);
QPainter cachePainter(&cachePixmap);
QRectF arrowRect;
@@ -1138,15 +1138,15 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(option);
const bool isSectionDragTarget = headerV2 ? headerV2->isSectionDragTarget : false;
+ const qreal dpr = painter->device()->devicePixelRatio();
const QString pixmapName = QStyleHelper::uniqueName("headersection-"_L1
% HexString(header->position)
% HexString(header->orientation)
% QLatin1Char(isSectionDragTarget ? '1' : '0'),
- option, option->rect.size());
+ option, option->rect.size(), dpr);
QPixmap cache;
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(rect.size(), dpr);
QRect pixmapRect(0, 0, rect.width(), rect.height());
QPainter cachePainter(&cache);
QColor buttonColor = d->buttonColor(option->palette);
@@ -1879,12 +1879,12 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
#if QT_CONFIG(spinbox)
case CC_SpinBox:
if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ const qreal dpr = painter->device()->devicePixelRatio();
QPixmap cache;
- QString pixmapName = QStyleHelper::uniqueName("spinbox"_L1, spinBox, spinBox->rect.size());
+ QString pixmapName = QStyleHelper::uniqueName("spinbox"_L1, spinBox, spinBox->rect.size(), dpr);
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(spinBox->rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(spinBox->rect.size(), dpr);
QRect pixmapRect(0, 0, spinBox->rect.width(), spinBox->rect.height());
QRect rect = pixmapRect;
@@ -2576,16 +2576,16 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
bool hasFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange;
bool sunken = comboBox->state & State_On; // play dead, if combobox has no items
bool isEnabled = (comboBox->state & State_Enabled);
+ const qreal dpr = painter->device()->devicePixelRatio();
QPixmap cache;
const QString pixmapName = QStyleHelper::uniqueName("combobox"_L1
% QLatin1StringView(sunken ? "-sunken" : "")
% QLatin1StringView(comboBox->editable ? "-editable" : "")
% QLatin1StringView(isEnabled ? "-enabled" : "")
% QLatin1StringView(!comboBox->frame ? "-frameless" : ""),
- option, comboBox->rect.size());
+ option, comboBox->rect.size(), dpr);
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(comboBox->rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(comboBox->rect.size(), dpr);
QPainter cachePainter(&cache);
QRect pixmapRect(0, 0, comboBox->rect.width(), comboBox->rect.height());
QStyleOptionComboBox comboBoxCopy = *comboBox;
@@ -2673,6 +2673,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
#if QT_CONFIG(slider)
case CC_Slider:
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ const qreal dpr = painter->device()->devicePixelRatio();
QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
@@ -2694,13 +2695,13 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
grooveColor.setHsv(buttonColor.hue(),
qMin(255, (int)(buttonColor.saturation())),
qMin(255, (int)(buttonColor.value()*0.9)));
- QString groovePixmapName = QStyleHelper::uniqueName("slider_groove"_L1, option, groove.size());
+ QString groovePixmapName = QStyleHelper::uniqueName("slider_groove"_L1, option,
+ groove.size(), dpr);
QRect pixmapRect(0, 0, groove.width(), groove.height());
// draw background groove
if (!QPixmapCache::find(groovePixmapName, &cache)) {
- cache = styleCachePixmap(pixmapRect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(pixmapRect.size(), dpr);
QPainter groovePainter(&cache);
groovePainter.setRenderHint(QPainter::Antialiasing, true);
groovePainter.translate(0.5, 0.5);
@@ -2728,8 +2729,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
if (!groovePixmapName.isEmpty())
groovePixmapName += "_blue"_L1;
if (!QPixmapCache::find(groovePixmapName, &cache)) {
- cache = styleCachePixmap(pixmapRect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(pixmapRect.size(), dpr);
QPainter groovePainter(&cache);
QLinearGradient gradient;
if (horizontal) {
@@ -2839,10 +2839,10 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
}
// draw handle
if ((option->subControls & SC_SliderHandle) ) {
- QString handlePixmapName = QStyleHelper::uniqueName("slider_handle"_L1, option, handle.size());
+ QString handlePixmapName = QStyleHelper::uniqueName("slider_handle"_L1, option,
+ handle.size(), dpr);
if (!QPixmapCache::find(handlePixmapName, &cache)) {
- cache = styleCachePixmap(handle.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(handle.size(), dpr);
QRect pixmapRect(0, 0, handle.width(), handle.height());
QPainter handlePainter(&cache);
QRect gradRect = pixmapRect.adjusted(2, 2, -2, -2);
@@ -3660,7 +3660,7 @@ QRect QFusionStyle::subElementRect(SubElement sr, const QStyleOption *opt, const
}
/*!
- \reimp
+ \internal
*/
QIcon QFusionStyle::iconFromTheme(StandardPixmap standardIcon) const
{
diff --git a/src/widgets/styles/qstyle_p.h b/src/widgets/styles/qstyle_p.h
index c4daa09c11..59e87810c5 100644
--- a/src/widgets/styles/qstyle_p.h
+++ b/src/widgets/styles/qstyle_p.h
@@ -29,38 +29,26 @@ class QStylePrivate: public QObjectPrivate
{
Q_DECLARE_PUBLIC(QStyle)
public:
- inline QStylePrivate()
- : layoutSpacingIndex(-1), proxyStyle(nullptr) {}
-
static bool useFullScreenForPopup();
- mutable int layoutSpacingIndex;
QStyle *proxyStyle;
QString name;
};
-inline QImage styleCacheImage(const QSize &size)
-{
- const qreal pixelRatio = qApp->devicePixelRatio();
- QImage cacheImage = QImage(size * pixelRatio, QImage::Format_ARGB32_Premultiplied);
- cacheImage.setDevicePixelRatio(pixelRatio);
- return cacheImage;
-}
-
-inline QPixmap styleCachePixmap(const QSize &size)
+inline QPixmap styleCachePixmap(const QSize &size, qreal pixelRatio)
{
- const qreal pixelRatio = qApp->devicePixelRatio();
QPixmap cachePixmap = QPixmap(size * pixelRatio);
cachePixmap.setDevicePixelRatio(pixelRatio);
+ cachePixmap.fill(Qt::transparent);
return cachePixmap;
}
#define BEGIN_STYLE_PIXMAPCACHE(a) \
QRect rect = option->rect; \
QPixmap internalPixmapCache; \
- QImage imageCache; \
QPainter *p = painter; \
- const QString unique = QStyleHelper::uniqueName((a), option, option->rect.size()); \
+ const auto dpr = p->device()->devicePixelRatio(); \
+ const QString unique = QStyleHelper::uniqueName((a), option, option->rect.size(), dpr); \
int txType = painter->deviceTransform().type() | painter->worldTransform().type(); \
const bool doPixmapCache = (!option->rect.isEmpty()) \
&& ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); \
@@ -69,9 +57,8 @@ inline QPixmap styleCachePixmap(const QSize &size)
} else { \
if (doPixmapCache) { \
rect.setRect(0, 0, option->rect.width(), option->rect.height()); \
- imageCache = styleCacheImage(option->rect.size()); \
- imageCache.fill(0); \
- p = new QPainter(&imageCache); \
+ internalPixmapCache = styleCachePixmap(option->rect.size(), dpr); \
+ p = new QPainter(&internalPixmapCache); \
}
@@ -80,7 +67,6 @@ inline QPixmap styleCachePixmap(const QSize &size)
if (doPixmapCache) { \
p->end(); \
delete p; \
- internalPixmapCache = QPixmap::fromImage(imageCache); \
painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
QPixmapCache::insert(unique, internalPixmapCache); \
} \
diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp
index 1084761d30..b4616b8c24 100644
--- a/src/widgets/styles/qstylehelper.cpp
+++ b/src/widgets/styles/qstylehelper.cpp
@@ -32,7 +32,7 @@ static inline bool usePixmapCache(const QStyleOption *opt)
return true;
}
-QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size)
+QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size, qreal dpr)
{
if (!usePixmapCache(option))
return {};
@@ -43,7 +43,8 @@ QString uniqueName(const QString &key, const QStyleOption *option, const QSize &
% HexString<uint>(complexOption ? uint(complexOption->activeSubControls) : 0u)
% HexString<quint64>(option->palette.cacheKey())
% HexString<uint>(size.width())
- % HexString<uint>(size.height());
+ % HexString<uint>(size.height())
+ % HexString<qreal>(dpr);
#if QT_CONFIG(spinbox)
if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
@@ -201,7 +202,7 @@ QPolygonF calcLines(const QStyleOptionSlider *dial)
qreal xc = width / 2 + 0.5;
qreal yc = height / 2 + 0.5;
const int ns = dial->tickInterval;
- if (!ns) // Invalid values may be set by Qt Designer.
+ if (!ns) // Invalid values may be set by Qt Widgets Designer.
return poly;
int notches = (dial->maximum + ns - 1 - dial->minimum) / ns;
if (notches <= 0)
diff --git a/src/widgets/styles/qstylehelper_p.h b/src/widgets/styles/qstylehelper_p.h
index 524417e405..98470ad1ce 100644
--- a/src/widgets/styles/qstylehelper_p.h
+++ b/src/widgets/styles/qstylehelper_p.h
@@ -39,7 +39,7 @@ class QWindow;
namespace QStyleHelper
{
- QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size);
+ QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size, qreal dpr);
Q_WIDGETS_EXPORT qreal dpi(const QStyleOption *option);
diff --git a/src/widgets/styles/qstylesheetstyle_default.cpp b/src/widgets/styles/qstylesheetstyle_default.cpp
index e50e18f291..6356835ff4 100644
--- a/src/widgets/styles/qstylesheetstyle_default.cpp
+++ b/src/widgets/styles/qstylesheetstyle_default.cpp
@@ -122,7 +122,8 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
// pixmap based style doesn't support any features
bool styleIsPixmapBased = baseStyle()->inherits("QMacStyle")
- || baseStyle()->inherits("QWindowsVistaStyle");
+ || (baseStyle()->inherits("QWindowsVistaStyle")
+ && !baseStyle()->inherits("QWindows11Style"));
/*QLineEdit {
diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp
index 394a968aad..f52321a3e1 100644
--- a/src/widgets/util/qcompleter.cpp
+++ b/src/widgets/util/qcompleter.cpp
@@ -1296,10 +1296,21 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e)
{
Q_D(QCompleter);
- if (d->eatFocusOut && o == d->widget && e->type() == QEvent::FocusOut) {
- d->hiddenBecauseNoMatch = false;
- if (d->popup && d->popup->isVisible())
- return true;
+ if (o == d->widget) {
+ switch (e->type()) {
+ case QEvent::FocusOut:
+ if (d->eatFocusOut) {
+ d->hiddenBecauseNoMatch = false;
+ if (d->popup && d->popup->isVisible())
+ return true;
+ }
+ break;
+ case QEvent::Hide:
+ if (d->popup)
+ d->popup->hide();
+ default:
+ break;
+ }
}
if (o != d->popup)
diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp
index 034127b4f3..0495b20422 100644
--- a/src/widgets/widgets/qcalendarwidget.cpp
+++ b/src/widgets/widgets/qcalendarwidget.cpp
@@ -2731,12 +2731,29 @@ bool QCalendarWidget::isGridVisible() const
return d->m_view->showGrid();
}
+/*!
+ \since 5.14
+ Report the calendar system in use by this widget.
+
+ \sa setCalendar()
+*/
+
QCalendar QCalendarWidget::calendar() const
{
Q_D(const QCalendarWidget);
return d->m_model->m_calendar;
}
+/*!
+ \since 5.14
+ Set \a c as the calendar system to be used by this widget.
+
+ The widget can use any supported calendar system.
+ By default, it uses the Gregorian calendar.
+
+ \sa calendar()
+*/
+
void QCalendarWidget::setCalendar(QCalendar c)
{
Q_D(QCalendarWidget);
diff --git a/src/widgets/widgets/qcheckbox.cpp b/src/widgets/widgets/qcheckbox.cpp
index 88cd603d70..3c03e9efa5 100644
--- a/src/widgets/widgets/qcheckbox.cpp
+++ b/src/widgets/widgets/qcheckbox.cpp
@@ -93,6 +93,11 @@ public:
\fn void QCheckBox::stateChanged(int state)
\deprecated [6.9] Use checkStateChanged(Qt::CheckState) instead.
+
+ This signal is emitted whenever the checkbox's state changes, i.e.,
+ whenever the user checks or unchecks it.
+
+ \a state contains the checkbox's new Qt::CheckState.
*/
/*!
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp
index 01e52b2fa6..a9b5babde5 100644
--- a/src/widgets/widgets/qdatetimeedit.cpp
+++ b/src/widgets/widgets/qdatetimeedit.cpp
@@ -303,6 +303,12 @@ void QDateTimeEdit::setTime(QTime time)
}
}
+/*!
+ \since 5.14
+ Report the calendar system in use by this widget.
+
+ \sa setCalendar()
+*/
QCalendar QDateTimeEdit::calendar() const
{
@@ -310,6 +316,16 @@ QCalendar QDateTimeEdit::calendar() const
return d->calendar;
}
+/*!
+ \since 5.14
+ Set \a calendar as the calendar system to be used by this widget.
+
+ The widget can use any supported calendar system.
+ By default, it uses the Gregorian calendar.
+
+ \sa calendar()
+*/
+
void QDateTimeEdit::setCalendar(QCalendar calendar)
{
Q_D(QDateTimeEdit);
@@ -2462,7 +2478,7 @@ int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) con
return NoSectionIndex;
}
-int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const
+int QDateTimeEditPrivate::absoluteIndex(SectionNode s) const
{
return sectionNodes.indexOf(s);
}
diff --git a/src/widgets/widgets/qdatetimeedit_p.h b/src/widgets/widgets/qdatetimeedit_p.h
index 215ee75bfe..f93afd1519 100644
--- a/src/widgets/widgets/qdatetimeedit_p.h
+++ b/src/widgets/widgets/qdatetimeedit_p.h
@@ -67,7 +67,7 @@ public:
int cursorPosition() const override { return edit ? edit->cursorPosition() : -1; }
int absoluteIndex(QDateTimeEdit::Section s, int index) const;
- int absoluteIndex(const SectionNode &s) const;
+ int absoluteIndex(SectionNode s) const;
QDateTime stepBy(int index, int steps, bool test = false) const;
int sectionAt(int pos) const;
int closestSection(int index, bool forward) const;
diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp
index 30ace89fa8..0b6a4df41a 100644
--- a/src/widgets/widgets/qdialogbuttonbox.cpp
+++ b/src/widgets/widgets/qdialogbuttonbox.cpp
@@ -374,7 +374,7 @@ QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardBut
button->setIcon(style->standardIcon(QStyle::StandardPixmap(icon), nullptr, q));
if (style != QApplication::style()) // Propagate style
button->setStyle(style);
- standardButtonHash.insert(button, sbutton);
+ standardButtonMap.insert(button, sbutton);
QPlatformDialogHelper::ButtonRole role = QPlatformDialogHelper::buttonRole(static_cast<QPlatformDialogHelper::StandardButton>(sbutton));
if (Q_UNLIKELY(role == QPlatformDialogHelper::InvalidRole))
qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
@@ -426,10 +426,10 @@ void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardBu
void QDialogButtonBoxPrivate::retranslateStrings()
{
- for (auto &&[key, value] : std::as_const(standardButtonHash).asKeyValueRange()) {
- const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(value);
+ for (const auto &it : std::as_const(standardButtonMap)) {
+ const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(it.second);
if (!text.isEmpty())
- key->setText(text);
+ it.first->setText(text);
}
}
@@ -644,15 +644,15 @@ void QDialogButtonBox::clear()
Q_D(QDialogButtonBox);
// Remove the created standard buttons, they should be in the other lists, which will
// do the deletion
- d->standardButtonHash.clear();
+ d->standardButtonMap.clear();
for (int i = 0; i < NRoles; ++i) {
QList<QAbstractButton *> &list = d->buttonLists[i];
- while (list.size()) {
- QAbstractButton *button = list.takeAt(0);
+ for (auto button : std::as_const(list)) {
QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
d, &QDialogButtonBoxPrivate::handleButtonDestroyed);
delete button;
}
+ list.clear();
}
}
@@ -680,7 +680,11 @@ QList<QAbstractButton *> QDialogButtonBoxPrivate::visibleButtons() const
QList<QAbstractButton *> QDialogButtonBoxPrivate::allButtons() const
{
- return visibleButtons() << hiddenButtons.keys();
+ QList<QAbstractButton *> ret(visibleButtons());
+ ret.reserve(ret.size() + hiddenButtons.size());
+ for (const auto &it : hiddenButtons)
+ ret.push_back(it.first);
+ return ret;
}
/*!
@@ -718,9 +722,9 @@ void QDialogButtonBox::removeButton(QAbstractButton *button)
Removes \param button.
\param reason determines the behavior following the removal:
\list
- \li \c ManualRemove disconnects all signals and removes the button from standardButtonHash.
- \li \c HideEvent keeps connections alive, standard buttons remain in standardButtonHash.
- \li \c Destroyed removes the button from standardButtonHash. Signals remain untouched, because
+ \li \c ManualRemove disconnects all signals and removes the button from standardButtonMap.
+ \li \c HideEvent keeps connections alive, standard buttons remain in standardButtonMap.
+ \li \c Destroyed removes the button from standardButtonMap. Signals remain untouched, because
the button might already be only a QObject, the destructor of which handles disconnecting.
\endlist
*/
@@ -744,7 +748,7 @@ void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveReason
button->removeEventFilter(filter.get());
Q_FALLTHROUGH();
case RemoveReason::Destroyed:
- standardButtonHash.remove(reinterpret_cast<QPushButton *>(button));
+ standardButtonMap.remove(reinterpret_cast<QPushButton *>(button));
break;
case RemoveReason::HideEvent:
break;
@@ -818,8 +822,9 @@ void QDialogButtonBox::setStandardButtons(StandardButtons buttons)
{
Q_D(QDialogButtonBox);
// Clear out all the old standard buttons, then recreate them.
- qDeleteAll(d->standardButtonHash.keyBegin(), d->standardButtonHash.keyEnd());
- d->standardButtonHash.clear();
+ const auto oldButtons = d->standardButtonMap.keys();
+ d->standardButtonMap.clear();
+ qDeleteAll(oldButtons);
d->createStandardButtons(buttons);
}
@@ -828,11 +833,8 @@ QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const
{
Q_D(const QDialogButtonBox);
StandardButtons standardButtons = NoButton;
- QHash<QPushButton *, StandardButton>::const_iterator it = d->standardButtonHash.constBegin();
- while (it != d->standardButtonHash.constEnd()) {
- standardButtons |= it.value();
- ++it;
- }
+ for (const auto value : d->standardButtonMap.values())
+ standardButtons |= value;
return standardButtons;
}
@@ -845,7 +847,12 @@ QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const
QPushButton *QDialogButtonBox::button(StandardButton which) const
{
Q_D(const QDialogButtonBox);
- return d->standardButtonHash.key(which);
+
+ for (const auto &it : std::as_const(d->standardButtonMap)) {
+ if (it.second == which)
+ return it.first;
+ }
+ return nullptr;
}
/*!
@@ -857,7 +864,7 @@ QPushButton *QDialogButtonBox::button(StandardButton which) const
QDialogButtonBox::StandardButton QDialogButtonBox::standardButton(QAbstractButton *button) const
{
Q_D(const QDialogButtonBox);
- return d->standardButtonHash.value(static_cast<QPushButton *>(button));
+ return d->standardButtonMap.value(static_cast<QPushButton *>(button));
}
void QDialogButtonBoxPrivate::handleButtonClicked()
@@ -965,16 +972,13 @@ bool QDialogButtonBox::centerButtons() const
*/
void QDialogButtonBox::changeEvent(QEvent *event)
{
- typedef QHash<QPushButton *, QDialogButtonBox::StandardButton> StandardButtonHash;
-
Q_D(QDialogButtonBox);
switch (event->type()) {
case QEvent::StyleChange: // Propagate style
- if (!d->standardButtonHash.empty()) {
+ if (!d->standardButtonMap.empty()) {
QStyle *newStyle = style();
- const StandardButtonHash::iterator end = d->standardButtonHash.end();
- for (StandardButtonHash::iterator it = d->standardButtonHash.begin(); it != end; ++it)
- it.key()->setStyle(newStyle);
+ for (auto key : d->standardButtonMap.keys())
+ key->setStyle(newStyle);
}
#ifdef Q_OS_MAC
Q_FALLTHROUGH();
diff --git a/src/widgets/widgets/qdialogbuttonbox_p.h b/src/widgets/widgets/qdialogbuttonbox_p.h
index c3d7e03489..e439819c49 100644
--- a/src/widgets/widgets/qdialogbuttonbox_p.h
+++ b/src/widgets/widgets/qdialogbuttonbox_p.h
@@ -16,6 +16,7 @@
//
#include <private/qwidget_p.h>
+#include <private/qflatmap_p.h>
#include <qdialogbuttonbox.h>
QT_BEGIN_NAMESPACE
@@ -42,8 +43,8 @@ public:
QDialogButtonBoxPrivate(Qt::Orientation orient);
QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles];
- QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash;
- QHash<QAbstractButton *, QDialogButtonBox::ButtonRole> hiddenButtons;
+ QVarLengthFlatMap<QPushButton *, QDialogButtonBox::StandardButton, 8> standardButtonMap;
+ QVarLengthFlatMap<QAbstractButton *, QDialogButtonBox::ButtonRole, 8> hiddenButtons;
Qt::Orientation orientation;
QDialogButtonBox::ButtonLayout layoutPolicy;
diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp
index 8909ac80d9..0db46bf175 100644
--- a/src/widgets/widgets/qlineedit.cpp
+++ b/src/widgets/widgets/qlineedit.cpp
@@ -2211,11 +2211,13 @@ QMenu *QLineEdit::createStandardContextMenu()
if (!isReadOnly()) {
action = popup->addAction(QLineEdit::tr("&Undo") + ACCEL_KEY(QKeySequence::Undo));
action->setEnabled(d->control->isUndoAvailable());
+ action->setObjectName(QStringLiteral("edit-undo"));
setActionIcon(action, QStringLiteral("edit-undo"));
connect(action, &QAction::triggered, this, &QLineEdit::undo);
action = popup->addAction(QLineEdit::tr("&Redo") + ACCEL_KEY(QKeySequence::Redo));
action->setEnabled(d->control->isRedoAvailable());
+ action->setObjectName(QStringLiteral("edit-redo"));
setActionIcon(action, QStringLiteral("edit-redo"));
connect(action, &QAction::triggered, this, &QLineEdit::redo);
@@ -2227,6 +2229,7 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut));
action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText()
&& d->control->echoMode() == QLineEdit::Normal);
+ action->setObjectName(QStringLiteral("edit-cut"));
setActionIcon(action, QStringLiteral("edit-cut"));
connect(action, &QAction::triggered, this, &QLineEdit::cut);
}
@@ -2234,12 +2237,14 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy));
action->setEnabled(d->control->hasSelectedText()
&& d->control->echoMode() == QLineEdit::Normal);
+ action->setObjectName(QStringLiteral("edit-copy"));
setActionIcon(action, QStringLiteral("edit-copy"));
connect(action, &QAction::triggered, this, &QLineEdit::copy);
if (!isReadOnly()) {
action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste));
action->setEnabled(!d->control->isReadOnly() && !QGuiApplication::clipboard()->text().isEmpty());
+ action->setObjectName(QStringLiteral("edit-paste"));
setActionIcon(action, QStringLiteral("edit-paste"));
connect(action, &QAction::triggered, this, &QLineEdit::paste);
}
@@ -2248,6 +2253,7 @@ QMenu *QLineEdit::createStandardContextMenu()
if (!isReadOnly()) {
action = popup->addAction(QLineEdit::tr("Delete"));
action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText());
+ action->setObjectName(QStringLiteral("edit-delete"));
setActionIcon(action, QStringLiteral("edit-delete"));
connect(action, &QAction::triggered,
d->control, &QWidgetLineControl::_q_deleteSelected);
@@ -2258,6 +2264,7 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll));
action->setEnabled(!d->control->text().isEmpty() && !d->control->allSelected());
+ action->setObjectName(QStringLiteral("select-all"));
setActionIcon(action, QStringLiteral("edit-select-all"));
d->selectAllAction = action;
connect(action, &QAction::triggered, this, &QLineEdit::selectAll);
diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp
index db17e50d5c..85c58fd70f 100644
--- a/src/widgets/widgets/qmainwindowlayout.cpp
+++ b/src/widgets/widgets/qmainwindowlayout.cpp
@@ -1931,6 +1931,11 @@ bool QMainWindowTabBar::contains(const QDockWidget *dockWidget) const
return false;
}
+// When a dock widget is removed from a floating tab,
+// Events need to be processed for the tab bar to realize that the dock widget is gone.
+// In this case count() counts the dock widget in transition and accesses dockAt
+// with an out-of-bounds index.
+// => return nullptr in contrast to other xxxxxAt() functions
QDockWidget *QMainWindowTabBar::dockAt(int index) const
{
QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this);
@@ -1938,10 +1943,15 @@ QDockWidget *QMainWindowTabBar::dockAt(int index) const
QDockAreaLayoutInfo *info = mlayout->dockInfo(that);
if (!info)
return nullptr;
+
const int itemIndex = info->tabIndexToListIndex(index);
- Q_ASSERT(itemIndex >= 0 && itemIndex < info->item_list.count());
- const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
- return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
+ if (itemIndex >= 0) {
+ Q_ASSERT(itemIndex < info->item_list.count());
+ const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
+ return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
+ }
+
+ return nullptr;
}
void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index 2a75fb44d5..1297db9b8a 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -57,12 +57,16 @@ if(QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS)
endif()
if(QT_BUILD_WASM_BATCHED_TESTS)
+ if(TARGET Qt::Concurrent)
+ add_subdirectory(corelib/io/qurl)
+ endif()
add_subdirectory(corelib/io/qdiriterator)
add_subdirectory(corelib/io/largefile)
add_subdirectory(corelib/io/qdataurl)
add_subdirectory(corelib/io/qbuffer)
add_subdirectory(corelib/io/qabstractfileengine)
add_subdirectory(corelib/io/qsettings)
+ add_subdirectory(corelib/io/qstandardpaths)
add_subdirectory(corelib/io/qfileselector)
add_subdirectory(corelib/io/qfile)
add_subdirectory(corelib/serialization)
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
index 3331ad260d..b159de7c9c 100644
--- a/tests/auto/cmake/CMakeLists.txt
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -399,8 +399,44 @@ endif()
_qt_internal_test_expect_pass(test_config_expressions)
_qt_internal_test_expect_pass(test_QTP0003)
+
if(NOT NO_GUI)
_qt_internal_test_expect_pass(test_collecting_plugins)
endif()
_qt_internal_test_expect_pass(test_qt_manual_moc)
+
+# check if the os is opensuse. If it is, we need to skip tests due to CI problems
+set(is_opensuse FALSE)
+if(UNIX)
+ if(EXISTS "/etc/os-release")
+ file(STRINGS "/etc/os-release" os_release_content)
+ foreach(line IN LISTS os_release_content)
+ if(line MATCHES "openSUSE" OR line MATCHES "opensuse")
+ set(is_opensuse TRUE)
+ break()
+ endif()
+ endforeach()
+ endif()
+endif()
+
+if(NOT QNX AND NOT WASM AND NOT (WIN32 AND QT_BUILD_MINIMAL_STATIC_TESTS)
+ AND NOT is_opensuse)
+ # Since our CI machines are slow, ctest --build-and-test buffers the output
+ # of the configure step of a test, and the fact that we run all the test
+ # logic in the configure step, we need to divide the tests into smaller
+ # chunks to avoid CI stdout timeout errors.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/25790
+ _qt_internal_test_expect_pass(test_qt_add_ui_common)
+ _qt_internal_test_expect_pass(test_qt_add_ui_1)
+ _qt_internal_test_expect_pass(test_qt_add_ui_2)
+ _qt_internal_test_expect_pass(test_qt_add_ui_3)
+ _qt_internal_test_expect_pass(test_qt_add_ui_4)
+ _qt_internal_test_expect_pass(test_qt_add_ui_5)
+ _qt_internal_test_expect_pass(test_qt_add_ui_6)
+ _qt_internal_test_expect_pass(test_qt_add_ui_7)
+ _qt_internal_test_expect_pass(test_qt_add_ui_8)
+ _qt_internal_test_expect_pass(test_qt_add_ui_9)
+ _qt_internal_test_expect_pass(test_qt_add_ui_10)
+endif()
+
diff --git a/tests/auto/cmake/test_qt_add_ui_1/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_1/CMakeLists.txt
new file mode 100644
index 0000000000..882abecc0b
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_1/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ if(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: ui_mainwindow.h is included as
+ # "sub1/sub2/sub3/sub4/../../../../src/ui_files/ui_mainwindow.h".
+ # Expect 1: Successful build without the double build issue.
+ # Expect 2: No build folder leakage and generation of the
+ # sub1/sub2/sub3/sub4 folder in ${hash_folder}/include
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ generate_hash_folder( "example" "${test_ui_file}" hash_folder)
+ string(CONCAT test_build_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/UicBuildLeak_incPathGen"
+ "${config_path}-build")
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_additional_args "-DMAINWINDOW_UI_PATH=sub1/sub2/"
+ "sub3/sub4/../../../../src/ui_files/")
+ string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
+ "${config_arg}/src/ui_files/ui_mainwindow.h")
+ string(CONCAT test_folder_to_check "${test_build_dir}/.qt/"
+ "${hash_folder}/${config_arg}/sub1/sub2/sub3/sub4")
+ incremental_build_test(
+ TEST_NAME UicBuildLeak_incPathGen
+ SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ CONFIG "${config_arg}"
+ GENERATOR "${generator}"
+ ADDITIONAL_ARGS "${test_additional_args}"
+ FILE_TO_TOUCH "${test_ui_file}"
+ FILE_TO_CHECK "${test_file_to_check}"
+ FOLDER_TO_CHECK "${test_folder_to_check}"
+ )
+ endforeach()
+endforeach()
+
diff --git a/tests/auto/cmake/test_qt_add_ui_10/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_10/CMakeLists.txt
new file mode 100644
index 0000000000..6b223fb281
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_10/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ # A CI test fails with the below condition. So, we are running the test
+ # only for the Debug configuration.
+ if ("${generator}" MATCHES "Xcode" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+ set(configs "Debug")
+ elseif(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: mainwindow.ui file is touched after the first build. The
+ # ui_mainwindow.h should be generated without the ${config_arg} folder.
+ # Expect 1: Successful build without the double build issue.
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "qt_add_ui_simple_no_config${config_path}-build")
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ generate_hash_folder(
+ "example"
+ "${test_ui_file}"
+ hash_folder)
+ incremental_build_test(
+ TEST_NAME qt6_add_ui_simple_no_config
+ SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ GENERATOR "${generator}"
+ CONFIG "${config_arg}"
+ ADDITIONAL_ARGS "-DUI_NO_CONFIG_OPTIONS=ON"
+ FILE_TO_TOUCH "${test_file_to_touch}"
+ FILE_TO_CHECK
+ "${test_build_dir}/.qt/${hash_folder}/ui_mainwindow.h"
+ )
+ endforeach()
+endforeach()
diff --git a/tests/auto/cmake/test_qt_add_ui_2/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_2/CMakeLists.txt
new file mode 100644
index 0000000000..dceb0c7a2e
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_2/CMakeLists.txt
@@ -0,0 +1,60 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ # A CI test fails with the below condition. So, we are running the test
+ # only for the Debug configuration.
+ if ("${generator}" MATCHES "Xcode" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+ set(configs "Debug")
+ elseif(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: mainwindow.ui file is touched after the first build.
+ # Expect 1: Successful build without the double build issue.
+ set(test_build_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/qt_add_ui_simple${config_path}-build")
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ generate_hash_folder(
+ "example"
+ "${test_ui_file}"
+ hash_folder)
+ incremental_build_test(
+ TEST_NAME qt6_add_ui_simple
+ SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ GENERATOR "${generator}"
+ CONFIG "${config_arg}"
+ FILE_TO_TOUCH "${test_file_to_touch}"
+ FILE_TO_CHECK
+ "${test_build_dir}/.qt/${hash_folder}/${config_arg}/ui_mainwindow.h"
+ )
+ endforeach()
+endforeach()
diff --git a/tests/auto/cmake/test_qt_add_ui_3/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_3/CMakeLists.txt
new file mode 100644
index 0000000000..81a9a38431
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_3/CMakeLists.txt
@@ -0,0 +1,199 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ if(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: Check whether api sets warning against AUTOUIC activation.
+ # Expect 1: Printing of the error message and failure of the build.
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_warning_test${config_path}-build")
+ run_cmake_configure(SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ GENERATOR "${generator}"
+ CLEAN_FIRST
+ ADDITIONAL_ARGS "-DCMAKE_AUTOUIC=ON"
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ RESULT_VARIABLE cmake_result)
+ if(NOT cmake_result EQUAL 0)
+ message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error: "
+ "${cmake_error}\nFAIL: \"uic_warning_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-"
+ "build failed to configure")
+ else()
+ message(STATUS "PASS: \"uic_warning_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-"
+ "build was configured successfully")
+ endif()
+
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_warning_test${config_path}-build")
+ run_cmake_build(
+ BUILD_DIR "${test_build_dir}"
+ VERBOSE ON
+ CONFIG "${config_arg}"
+ OUTPUT_VARIABLE cmake_build_output
+ RESULT_VARIABLE cmake_build_result)
+ if(NOT cmake_build_result EQUAL 0)
+ message(STATUS "PASS: \"uic_warning_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}"
+ "-build failed to build")
+ else()
+ message(FATAL_ERROR "FAIL: \"uic_warning_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-"
+ "build was built successfully")
+ endif()
+ expect_string_contains("${cmake_build_output}" "has \"AUTOUIC\" enabled"
+ SUCCESS_MESSAGE "\"uic_warning_test\" test in \
+${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-build \
+has \"has AUTOUIC enabled\""
+ FAILURE_MESSAGE "\"uic_warning_test\" test in \
+${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-build \
+does not have \"has AUTOUIC enabled\"")
+
+
+ if("${generator}" MATCHES "Ninja")
+ # Test case: If INCLUDE_PREFIX is changed without changing the
+ # corresponding include path in the source file and Ninja generator
+ # is used, this casues the double build issue.
+ # Note: Only happens in Ninja generator.
+ # Expect 1: Failure of the build in the first build.
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_double_build_test${config_path}-build")
+ run_cmake_configure(SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ GENERATOR "${generator}"
+ CLEAN_FIRST
+ ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3/"
+ "-DDO_NOT_GENERATE_FILE=ON"
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ RESULT_VARIABLE cmake_result)
+
+ if(NOT cmake_result EQUAL 0)
+ message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
+ ": ${cmake_error}\nFAIL: \"uic_double_build_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build failed to configure")
+ else()
+ message(STATUS "PASS: \"uic_double_build_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build was configured successfully")
+ endif()
+
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_double_build_test${config_path}-build")
+ run_cmake_build(
+ BUILD_DIR "${test_build_dir}"
+ VERBOSE ON
+ CONFIG "${config_arg}"
+ OUTPUT_VARIABLE cmake_build_output
+ RESULT_VARIABLE cmake_build_result)
+
+ if(NOT cmake_build_result EQUAL 0)
+ message(FATAL_ERROR "cmake_build_output: ${cmake_build_output}"
+ "FAIL: \"uic_double_build_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build failed to build in the first build")
+ else()
+ message(STATUS "PASS: \"uic_double_build_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build was built successfully in the first "
+ "build")
+ endif()
+
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_double_build_test${config_path}-build")
+ run_cmake_configure(SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ GENERATOR "${generator}"
+ # We change the INCLUDE_PREFIX here.
+ ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub/"
+ "-DDO_NOT_GENERATE_FILE=ON"
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ RESULT_VARIABLE cmake_result)
+
+ if(NOT cmake_result EQUAL 0)
+ message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
+ ":${cmake_error}\nFAIL: \"uic_double_build_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build failed to configure in the second "
+ "build")
+ else()
+ message(STATUS "PASS: \"uic_double_build_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build was configured successfully in the "
+ "second build")
+ endif()
+
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_double_build_test${config_path}-build")
+ run_cmake_build(
+ BUILD_DIR "${test_build_dir}"
+ VERBOSE ON
+ CONFIG "${config_arg}"
+ OUTPUT_VARIABLE cmake_build_output
+ ERROR_VARIABLE cmake_build_error
+ RESULT_VARIABLE cmake_build_result)
+
+ if(NOT cmake_build_result EQUAL 0)
+ message(STATUS "PASS: \"uic_double_build_test\" test in"
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build failed to build in the first build "
+ "after changing INCLUDE_PREFIX")
+ else()
+ message(FATAL_ERROR "cmake_build_output: ${cmake_build_output}"
+ "\ncmake_build_error: ${cmake_build_error}\n"
+ "FAIL: \"uic_double_build_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
+ "${config_path}-build was built successfully in the first "
+ "build after changing INCLUDE_PREFIX")
+ endif()
+
+ set(expected_fail_string "No such file or directory|file not found")
+ expect_string_contains(${cmake_build_output}
+ "${expected_fail_string}"
+ SUCCESS_MESSAGE "\"uic_double_build_test\" test in \
+${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test${config_path}\
+-build has \"ui_mainwindow.h: No such file or directory\" in \
+the first build after changing INCLUDE_PREFIX"
+ FAILURE_MESSAGE "\"uic_double_build_test\" test in \
+${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test${config_path}\
+-build does not have \"ui_mainwindow.h: No such file or \
+directory\" in the first build after changing INCLUDE_PREFIX")
+
+ endif()
+ endforeach()
+endforeach()
+
diff --git a/tests/auto/cmake/test_qt_add_ui_4/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_4/CMakeLists.txt
new file mode 100644
index 0000000000..51c74352d6
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_4/CMakeLists.txt
@@ -0,0 +1,65 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ # A CI test fails with the below condition. So, we are running the test
+ # only for the Debug configuration.
+ if ("${generator}" MATCHES "Xcode" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+ set(configs "Debug")
+ elseif(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: widget1.ui file is touched after the first build.
+ # Expect 1: Successful build without the double build issue.
+ # Expect 2: Only touched files to be built
+ set(test_build_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/UicIncrementalBuild${config_path}-build")
+ string(CONCAT ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/UicIncrementalBuild/src/widget1.ui")
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/UicIncrementalBuild")
+
+ generate_hash_folder(
+ "example"
+ "${ui_file}"
+ hash_folder)
+ string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
+ "${config_arg}/src/ui_widget1.h")
+ incremental_build_test(
+ TEST_NAME UicIncrementalBuild
+ SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ CONFIG "${config_arg}"
+ GENERATOR "${generator}"
+ FILE_TO_TOUCH "${ui_file}"
+ FILE_TO_CHECK
+ "${test_file_to_check}"
+ FOLDER_TO_CHECK
+ "${test_build_dir}/.qt/${hash_folder}/${config_arg}/src"
+ CHECK_UNWANTED_BUILDS
+ )
+ endforeach()
+endforeach()
diff --git a/tests/auto/cmake/test_qt_add_ui_5/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_5/CMakeLists.txt
new file mode 100644
index 0000000000..7b29bcf52b
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_5/CMakeLists.txt
@@ -0,0 +1,164 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ if(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+
+ if("${generator}" MATCHES "Ninja")
+ # Test case: Add a new ui file to CMakeLists.txt after the first
+ # build.
+ # Expect 1: Expect ${target}_autogen/prefix_info.cmake to be
+ # generated as expected.
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_prefix_info_cmake_test${config_path}-build")
+ run_cmake_configure(SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ GENERATOR "${generator}"
+ CLEAN_FIRST
+ ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3/"
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ RESULT_VARIABLE cmake_result)
+
+ if(NOT cmake_result EQUAL 0)
+ message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
+ ":${cmake_error}\nFAIL: \"uic_prefix_info_cmake_test\" test"
+ " in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build failed to configure")
+ else()
+ message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in"
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build was configured successfully")
+ endif()
+
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ generate_hash_folder("example" "${test_ui_file}"
+ hash_folder_mainwindow)
+ string(CONCAT expected_prefix_info_cmake_content
+ "include_guard()\nset(${hash_folder_mainwindow}_prefix \""
+ "sub1/sub2/sub3\")")
+ # read the content of the prefix_info.cmake file
+ string(CONCAT "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_prefix_info_cmake_test${config_path}-build")
+ file(READ
+ "${test_build_dir}/example_autogen/prefix_info.cmake"
+ prefix_info_cmake_content)
+
+ if("${prefix_info_cmake_content}" STREQUAL
+ "${expected_prefix_info_cmake_content}")
+ message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build has the expected content in "
+ "prefix_info.cmake")
+ else()
+ message(FATAL_ERROR "FAIL: \"uic_prefix_info_cmake_test\" test "
+ "in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build does not have the expected content in"
+ " prefix_info.cmake")
+ endif()
+
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_prefix_info_cmake_test${config_path}-build")
+ run_cmake_build(
+ BUILD_DIR "${test_build_dir}"
+ VERBOSE ON
+ CONFIG "${config_arg}"
+ OUTPUT_VARIABLE cmake_build_output
+ ERROR_VARIABLE cmake_build_error
+ RESULT_VARIABLE cmake_build_result)
+
+ if(NOT cmake_build_result EQUAL 0)
+ message(FATAL_ERROR "cmake_build_output: ${cmake_build_output}"
+ "\ncmake_build_error: ${cmake_build_error}\n"
+ "FAIL: \"uic_prefix_info_cmake_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build failed to build in the first build")
+ else()
+ message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build was built successfully in the first "
+ "build")
+ endif()
+
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_prefix_info_cmake_test${config_path}-build")
+ run_cmake_configure(SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ GENERATOR "${generator}"
+ ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3/"
+ "-DNEW_UI_PATH=sub5/sub6/sub7/ " "-DADD_NEW_UI=ON"
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ RESULT_VARIABLE cmake_result)
+
+ if(NOT cmake_result EQUAL 0)
+ message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
+ ": ${cmake_error}\nFAIL: \"uic_prefix_info_cmake_test\" "
+ "test in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_"
+ "test ${config_path}-build failed to configure in the"
+ "second build")
+ else()
+ message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in"
+ " ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build was configured successfully in the "
+ "second build")
+ endif()
+
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/subdir/mainwindow.ui")
+ generate_hash_folder("example" "${test_ui_file}"
+ hash_folder_subdir_mainwindow)
+ set(expected_prefix_info_cmake_content
+ "include_guard()\nset(${hash_folder_subdir_mainwindow}_prefix \
+\"sub5/sub6/sub7\")")
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "uic_prefix_info_cmake_test${config_path}-build")
+ file(READ
+ "${test_build_dir}/example_autogen/prefix_info.cmake"
+ prefix_info_cmake_content)
+
+ if("${prefix_info_cmake_content}" STREQUAL
+ "${expected_prefix_info_cmake_content}")
+ message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in "
+ "${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build has the expected content in "
+ "prefix_info.cmake")
+ else()
+ message(FATAL_ERROR "FAIL: \"uic_prefix_info_cmake_test\" test "
+ "in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
+ "${config_path}-build does not have the expected content "
+ "in prefix_info.cmake")
+ endif()
+ endif()
+ endforeach()
+endforeach()
+
diff --git a/tests/auto/cmake/test_qt_add_ui_6/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_6/CMakeLists.txt
new file mode 100644
index 0000000000..2d57c6067d
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_6/CMakeLists.txt
@@ -0,0 +1,64 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ # A CI test fails with the below condition. So, we are running the test
+ # only for the Debug configuration.
+ if ("${generator}" MATCHES "Xcode" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+ set(configs "Debug")
+ elseif(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: ui_mainwindow.h is included as
+ # "../../../../src/ui_files/ui_mainwindow.h".
+ # Test case: mainwindow1.ui file is touched after the first build.
+ # Expect 1: Successful build without the double build issue.
+ # Expect 2: No build folder leakage and generation of the "_/_/_/_/"
+ # folder in ${hash_folder}/include.
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../test_qt_add_ui_"
+ "common/uic_test/mainwindow.ui")
+ generate_hash_folder("example" "${test_ui_file}" hash_folder)
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/UicBuildLeak_"
+ "subFolderGen${config_path}-build")
+ string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
+ "${config_arg}/src/ui_files/ui_mainwindow.h")
+ incremental_build_test(
+ TEST_NAME UicBuildLeak_subFolderGen
+ SOURCE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/../test_qt_add_ui_common/uic_test"
+ BUILD_DIR "${test_build_dir}"
+ CONFIG "${config_arg}"
+ GENERATOR "${generator}"
+ ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=../../../../src/ui_files/"
+ FILE_TO_TOUCH "${test_file_to_touch}"
+ FILE_TO_CHECK "${test_file_to_check}"
+ FOLDER_TO_CHECK
+ "${test_build_dir}/.qt/${hash_folder}/${config_arg}/_/_/_/_"
+ )
+ endforeach()
+endforeach()
diff --git a/tests/auto/cmake/test_qt_add_ui_7/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_7/CMakeLists.txt
new file mode 100644
index 0000000000..8278f13a72
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_7/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ # A CI test fails with the below condition. So, we are running the test
+ # only for the Debug configuration.
+ if ("${generator}" MATCHES "Xcode" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+ set(configs "Debug")
+ elseif(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case 1: There are two widget1.ui files in different folders.
+ # Expect 1: Successful build without the double build issue.
+ # Expect 2: Only touched files to be built.
+ string(CONCAT ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui")
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/sub1/sub2/sub3/"
+ "sub4")
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "UicIncBuild_sameFileDiffFolder${config_path}-build")
+ string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui")
+ generate_hash_folder(
+ "example"
+ "${ui_file}"
+ hash_folder)
+ incremental_build_test(
+ TEST_NAME UicIncBuild_sameFileDiffFolder
+ SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ CONFIG "${config_arg}"
+ GENERATOR "${generator}"
+ FILE_TO_TOUCH "${test_file_to_touch}"
+ CHECK_UNWANTED_BUILDS
+ )
+
+ endforeach()
+endforeach()
diff --git a/tests/auto/cmake/test_qt_add_ui_8/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_8/CMakeLists.txt
new file mode 100644
index 0000000000..f8d0763d35
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_8/CMakeLists.txt
@@ -0,0 +1,67 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ # A CI test fails with the below condition. So, we are running the test
+ # only for the Debug configuration.
+ if ("${generator}" MATCHES "Xcode" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+ set(configs "Debug")
+ elseif(multi_config_out)
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: ui_mainwindow.h is included as
+ # "sub1/sub2/sub3/../../../../../../../../../../../../../ui_mainwindow.h".
+ # Test case: mainwindow1.ui file is touched after the first build.
+ # Expect 1: Successful build without the double build issue.
+ # Expect 2: No build folder leakage and generation of the
+ # "_/_/_/_/_/_/_/_/_/_/sub1/sub2/sub3" folder in ${hash_folder}/include.
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ generate_hash_folder("example" "${test_ui_file}" hash_folder)
+ string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
+ "UicBuildLeak_subFolderGen_complex${config_path}-build")
+ string(CONCAT test_additional_args "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3"
+ "/../../../../../../../../../../../../../")
+ string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
+ "${config_arg}/ui_mainwindow.h")
+ string(CONCAT test_folder_to_check "${test_build_dir}/.qt/${hash_folder}/"
+ "${config_arg}/_/_/_/_/_/_/_/_/_/_/sub1/sub2/sub3")
+ incremental_build_test(
+ TEST_NAME UicBuildLeak_subFolderGen_complex
+ SOURCE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/../test_qt_add_ui_common/uic_test"
+ BUILD_DIR "${test_build_dir}"
+ CONFIG "${config_arg}"
+ GENERATOR "${generator}"
+ ADDITIONAL_ARGS "${test_additional_args}"
+ FILE_TO_TOUCH "${test_file_to_touch}"
+ FILE_TO_CHECK "${test_file_to_check}"
+ FOLDER_TO_CHECK "${test_folder_to_check}"
+ )
+ endforeach()
+endforeach()
diff --git a/tests/auto/cmake/test_qt_add_ui_9/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_9/CMakeLists.txt
new file mode 100644
index 0000000000..9e28ddc927
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_9/CMakeLists.txt
@@ -0,0 +1,66 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+include(../test_qt_add_ui_common/RunCMake.cmake)
+include(../test_qt_add_ui_common/functions.cmake)
+
+get_generators(generators)
+
+foreach(generator IN ITEMS ${generators})
+ message(STATUS "Running tests for generator: ${generator}")
+ is_multi_config(${generator} multi_config_out)
+ if(multi_config_out)
+ # Since our CI machines are slow, ctest --build-and-test buffers the
+ # output of the configure step of a test, and the fact that we run all
+ # the test logic in the configure step, we need to exclude Release
+ # to avoid CI stdout timeout errors.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/25790
+ set(configs "Debug" "Release")
+ else()
+ set(configs "single_config")
+ endif()
+
+ foreach(config IN ITEMS ${configs})
+ if("${config}" STREQUAL "single_config")
+ set(config_path "")
+ set(config_arg "")
+ else()
+ set(config_path "_${config}")
+ set(config_arg "${config}")
+ endif()
+
+ # Test case: ui_mainwindow.h is included as
+ # "sub2/sub3/../../../src/ui_files/ui_mainwindow.h".
+ # Expect 1: Successful build without the double build issue.
+ # Expect 2: No build folder leakage and generation of
+ # _/sub2/sub3 in ${hash_folder}/include.
+ # Note: This test case is a mix of previous two test cases.
+ string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test/mainwindow.ui")
+ generate_hash_folder("example" "${test_ui_file}" hash_folder)
+ set(test_build_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/UicBuildLeak_mix${config_path}-build")
+ string(CONCAT test_additional_args "-DMAINWINDOW_UI_PATH=sub2/sub3/"
+ "../../../src/ui_files/")
+ string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
+ "${config_arg}/src/ui_files/ui_mainwindow.h")
+ string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/uic_test")
+ incremental_build_test(
+ TEST_NAME UicBuildLeak_mix
+ SOURCE_DIR "${test_source_dir}"
+ BUILD_DIR "${test_build_dir}"
+ CONFIG "${config_arg}"
+ GENERATOR "${generator}"
+ ADDITIONAL_ARGS "${test_additional_args}"
+ FILE_TO_TOUCH "${test_ui_file}"
+ FILE_TO_CHECK "${test_file_to_check}"
+ FOLDER_TO_CHECK
+ "${test_build_dir}/.qt/${hash_folder}/${config_arg}/_/sub2/sub3"
+ )
+ endforeach()
+endforeach()
+
diff --git a/tests/auto/cmake/test_qt_add_ui_common/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_common/CMakeLists.txt
new file mode 100644
index 0000000000..628dc9373a
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(test)
+
+add_executable(test main.cpp)
diff --git a/tests/auto/cmake/test_qt_add_ui_common/RunCMake.cmake b/tests/auto/cmake/test_qt_add_ui_common/RunCMake.cmake
new file mode 100644
index 0000000000..6b39fe3398
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/RunCMake.cmake
@@ -0,0 +1,157 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(run_cmake_configure)
+ set(options CLEAN_FIRST)
+ set(oneValueArgs SOURCE_DIR BUILD_DIR RESULT_VARIABLE OUTPUT_VARIABLE
+ ERROR_VARIABLE GENERATOR)
+ set(multiValueArgs ADDITIONAL_ARGS)
+
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
+ ${ARGN})
+
+ if(NOT arg_SOURCE_DIR)
+ message(FATAL_ERROR "SOURCE_DIR not specified")
+ endif()
+
+ if(NOT arg_BUILD_DIR)
+ message(FATAL_ERROR "BUILD_DIR not specified")
+ endif()
+
+ is_multi_config(arg_GENERATOR multi_config_out)
+ if (NOT ${multi_config_out})
+ set(run_arg_config_arg -Darg_TYPE=Debug)
+ endif()
+
+ set(test_project_source_dir ${arg_SOURCE_DIR})
+ set(test_project_build_dir ${arg_BUILD_DIR})
+
+ # Make sure that file paths are 'real' paths
+ get_filename_component(test_project_source_dir "${test_project_source_dir}"
+ REALPATH)
+ get_filename_component(test_project_build_dir "${test_project_build_dir}"
+ REALPATH)
+
+ if(arg_CLEAN_FIRST)
+ file(REMOVE_RECURSE "${test_project_build_dir}")
+ endif()
+ file(MAKE_DIRECTORY "${test_project_build_dir}")
+
+ execute_process(COMMAND
+ "${CMAKE_COMMAND}"
+ -S "${test_project_source_dir}"
+ -B "${test_project_build_dir}"
+ -G "${arg_GENERATOR}"
+ "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
+ ${run_arg_config_arg}
+ ${arg_ADDITIONAL_ARGS}
+ RESULT_VARIABLE cmake_result
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ ECHO_OUTPUT_VARIABLE
+ ECHO_ERROR_VARIABLE
+ )
+
+ # set output variables
+ set(${arg_RESULT_VARIABLE} ${cmake_result} PARENT_SCOPE)
+ set(${arg_OUTPUT_VARIABLE} ${cmake_output} PARENT_SCOPE)
+ set(${arg_ERROR_VARIABLE} ${cmake_error} PARENT_SCOPE)
+endfunction()
+
+function(run_cmake_build)
+ set(options VERBOSE)
+ set(oneValueArgs CONFIG BUILD_DIR RESULT_VARIABLE OUTPUT_VARIABLE
+ ERROR_VARIABLE)
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
+ ${ARGN})
+
+ if(NOT arg_BUILD_DIR)
+ message(FATAL_ERROR "BUILD_DIR not specified")
+ endif()
+
+ if (arg_VERBOSE OR arg_VERBOSE STREQUAL "")
+ set(arg_VERBOSE_ARG --verbose)
+ endif()
+
+ if(arg_CONFIG)
+ set(arg_BUILD_CONFIG_ARG --config ${arg_CONFIG})
+ endif()
+
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ --build ${arg_BUILD_DIR}
+ ${arg_VERBOSE_ARG}
+ ${arg_BUILD_CONFIG_ARG}
+ RESULT_VARIABLE cmake_result
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ ECHO_OUTPUT_VARIABLE
+ ECHO_ERROR_VARIABLE)
+
+ set(${arg_RESULT_VARIABLE} ${cmake_result} PARENT_SCOPE)
+ set(${arg_OUTPUT_VARIABLE} ${cmake_output} PARENT_SCOPE)
+ set(${arg_ERROR_VARIABLE} ${cmake_error} PARENT_SCOPE)
+endfunction()
+
+function(is_multi_config generator output)
+ if ("${generator}" MATCHES "Visual Studio" OR "${generator}" MATCHES "Xcode"
+ OR "${generator}" MATCHES "Ninja Multi-Config")
+ set(${output} TRUE PARENT_SCOPE)
+ else()
+ set(${output} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+# check if string includes substring
+function(_internal_string_contains output string substring)
+ if("${string}" MATCHES "${substring}")
+ set(${output} TRUE PARENT_SCOPE)
+ else()
+ set(${output} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(expect_string_contains string substring)
+ set(oneValueArgs SUCCESS_MESSAGE FAILURE_MESSAGE)
+ cmake_parse_arguments(expect_string_contains "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN})
+ _internal_string_contains(result "${string}" "${substring}")
+ if("${result}" STREQUAL TRUE)
+ if (expect_string_contains_SUCCESS_MESSAGE)
+ message(STATUS "PASS: ${expect_string_contains_SUCCESS_MESSAGE}")
+ else()
+ message(STATUS "PASS: \"${string}\" contains \"${substring}\"")
+ endif()
+ else()
+ if (expect_string_contains_FAILURE_MESSAGE)
+ message(FATAL_ERROR
+ "FAIL: ${expect_string_contains_FAILURE_MESSAGE}")
+ else()
+ message(FATAL_ERROR "FAIL: \"${string}\" contains \"${substring}\"")
+ endif()
+ endif()
+endfunction()
+
+function(expect_string_not_contains string substring)
+ set(oneValueArgs SUCCESS_MESSAGE FAILURE_MESSAGE)
+ cmake_parse_arguments(expect_string_not_contains
+ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ _internal_string_contains(result ${string} ${substring})
+ if(${result} STREQUAL FALSE)
+ if (expect_string_not_contains_SUCCESS_MESSAGE)
+ message(STATUS "PASS: ${expect_string_not_contains_SUCCESS_MESSAGE}")
+ else()
+ message(STATUS "PASS: \"${string}\" not contains \"${substring}\"")
+ endif()
+ else()
+ if (expect_string_not_contains_FAILURE_MESSAGE)
+ message(FATAL_ERROR
+ "FAIL: ${expect_string_not_contains_FAILURE_MESSAGE}")
+ else()
+ message(FATAL_ERROR "FAIL: \"${string}\" contains \"${substring}\"")
+ endif()
+ endif()
+endfunction()
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/main.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/main.cpp
new file mode 100644
index 0000000000..27296cb9a0
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/main.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char* argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/mainwindow.h b/tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/mainwindow.h
new file mode 100644
index 0000000000..9aeaefbe08
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicBuildFolderLeakageCommon/mainwindow.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class MainWindow;
+}
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget* parent = nullptr);
+ ~MainWindow();
+
+private:
+ Ui::MainWindow* ui;
+};
+#endif // MAINWINDOW_H
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/main.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/main.cpp
new file mode 100644
index 0000000000..27296cb9a0
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/main.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char* argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.cpp
new file mode 100644
index 0000000000..d4302325fb
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mainwindow.h"
+
+#include <QVBoxLayout>
+
+#include "../../../../src/ui_files/ui_mainwindow.h"
+#include "widget1.h"
+
+MainWindow::MainWindow(QWidget* parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+ auto layout = new QVBoxLayout;
+ layout->addWidget(new Widget1);
+
+ QWidget* w = new QWidget(this);
+ w->setLayout(layout);
+
+ setCentralWidget(w);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.h b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.h
new file mode 100644
index 0000000000..46dc7690cc
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/mainwindow.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class MainWindow;
+}
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow(QWidget* parent = nullptr);
+ ~MainWindow();
+
+private:
+ Ui::MainWindow* ui;
+};
+#endif // MAINWINDOW_H
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/mainwindow.ui b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/mainwindow.ui
new file mode 100644
index 0000000000..828d7c1782
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/mainwindow.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout"/>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>22</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/widget1.ui b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/widget1.ui
new file mode 100644
index 0000000000..db0c58d5df
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/ui_files/widget1.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget1</class>
+ <widget class="QWidget" name="Widget1">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Input:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>OnTextChanged:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="OnTextChanged">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.cpp
new file mode 100644
index 0000000000..2139ff2c84
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "widget1.h"
+
+#include "../../../../src/ui_files/ui_widget1.h"
+
+Widget1::Widget1(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::Widget1)
+{
+ ui->setupUi(this);
+ connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(onTextChanged(const QString&)));
+}
+
+Widget1::~Widget1()
+{
+ delete ui;
+}
+
+void Widget1::onTextChanged(const QString& text)
+{
+ ui->OnTextChanged->setText(text);
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.h b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.h
new file mode 100644
index 0000000000..f8a5ad57d5
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef WIDGET1_H
+#define WIDGET1_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class Widget1;
+}
+QT_END_NAMESPACE
+
+class Widget1 : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit Widget1(QWidget* parent = nullptr);
+ ~Widget1();
+public slots:
+ void onTextChanged(const QString& text);
+
+private:
+ Ui::Widget1* ui;
+};
+
+#endif // WIDGET1_H
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui
new file mode 100644
index 0000000000..db0c58d5df
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget1</class>
+ <widget class="QWidget" name="Widget1">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Input:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>OnTextChanged:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="OnTextChanged">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.cpp
new file mode 100644
index 0000000000..721f0c868f
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "widget2.h"
+
+#include "../../../../ui_widget1.h"
+
+Widget2::Widget2(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::Widget2)
+{
+ ui->setupUi(this);
+ connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(onTextChanged(const QString&)));
+}
+
+Widget2::~Widget2()
+{
+ delete ui;
+}
+
+void Widget2::onTextChanged(const QString& text)
+{
+ ui->OnTextChanged->setText(text);
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.h b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.h
new file mode 100644
index 0000000000..e448b12caf
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget2.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef WIDGET2_H
+#define WIDGET2_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class Widget2;
+}
+QT_END_NAMESPACE
+
+class Widget2 : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit Widget2(QWidget* parent = nullptr);
+ ~Widget2();
+public slots:
+ void onTextChanged(const QString& text);
+
+private:
+ Ui::Widget2* ui;
+};
+
+#endif // WIDGET2_H
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/sub1/sub2/sub3/sub4/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/sub1/sub2/sub3/sub4/CMakeLists.txt
new file mode 100644
index 0000000000..b8443c370d
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/sub1/sub2/sub3/sub4/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+project(UicIncrementalBuild_sameFileDifferentFolder LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui)
+
+set(CMAKE_AUTOMOC ON)
+
+qt_add_executable(example
+ ../../../../src/ui_files/mainwindow.ui
+ ../../../../src/ui_files/widget1.ui
+ ../../../../widget1.ui
+ ../../../../src/mainwindow.h
+ ../../../../src/widget1.h
+ ../../../../src/widget2.h
+ ../../../../src/main.cpp
+ ../../../../src/mainwindow.cpp
+ ../../../../src/widget1.cpp
+ ../../../../src/widget2.cpp
+)
+
+target_link_libraries(example PRIVATE Qt6::Widgets
+ Qt6::Core
+ Qt6::Gui)
+
+qt6_add_ui(example
+ INCLUDE_PREFIX "../../../../src/ui_files"
+ SOURCES "../../../../src/ui_files/mainwindow.ui"
+ "../../../../src/ui_files/widget1.ui"
+ OPTIONS "$<$<CONFIG:Debug>:-a>")
+
+qt6_add_ui(example
+ INCLUDE_PREFIX "../../../../"
+ SOURCES "../../../../widget1.ui"
+ OPTIONS "$<$<CONFIG:Debug>:-a>")
+
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/widget1.ui b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/widget1.ui
new file mode 100644
index 0000000000..facf4678f2
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/widget1.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget2</class>
+ <widget class="QWidget" name="Widget2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Input:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>OnTextChanged:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="OnTextChanged">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/CMakeLists.txt
new file mode 100644
index 0000000000..81023c3382
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+project(UicIncrementalBuild LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+set(CMAKE_AUTOMOC ON)
+
+qt_add_executable(example
+ src/mainwindow.ui
+ src/widget1.ui
+ src/widget2.ui
+ src/mainwindow.h
+ src/widget1.h
+ src/widget2.h
+ src/main.cpp
+ src/mainwindow.cpp
+ src/widget1.cpp
+ src/widget2.cpp
+)
+
+target_link_libraries(example PRIVATE Qt6::Widgets
+ Qt6::Core
+ Qt6::Gui)
+
+qt6_add_ui(example
+ INCLUDE_PREFIX "src"
+ SOURCES "src/mainwindow.ui" "src/widget1.ui" "src/widget2.ui"
+ OPTIONS "$<$<CONFIG:Debug>:-a>")
+
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/main.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/main.cpp
new file mode 100644
index 0000000000..27296cb9a0
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/main.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char* argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.cpp
new file mode 100644
index 0000000000..ef582f187c
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mainwindow.h"
+
+#include <QVBoxLayout>
+
+#include "src/ui_mainwindow.h"
+#include "widget1.h"
+
+MainWindow::MainWindow(QWidget* parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+ auto layout = new QVBoxLayout;
+ layout->addWidget(new Widget1);
+
+ QWidget* w = new QWidget(this);
+ w->setLayout(layout);
+
+ setCentralWidget(w);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.h b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.h
new file mode 100644
index 0000000000..46dc7690cc
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class MainWindow;
+}
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow(QWidget* parent = nullptr);
+ ~MainWindow();
+
+private:
+ Ui::MainWindow* ui;
+};
+#endif // MAINWINDOW_H
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.ui b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.ui
new file mode 100644
index 0000000000..828d7c1782
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/mainwindow.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout"/>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>22</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.cpp
new file mode 100644
index 0000000000..4047ea4d9c
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "widget1.h"
+
+#include "src/ui_widget1.h"
+
+Widget1::Widget1(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::Widget1)
+{
+ ui->setupUi(this);
+ connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(onTextChanged(const QString&)));
+}
+
+Widget1::~Widget1()
+{
+ delete ui;
+}
+
+void Widget1::onTextChanged(const QString& text)
+{
+ ui->OnTextChanged->setText(text);
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.h b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.h
new file mode 100644
index 0000000000..f8a5ad57d5
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef WIDGET1_H
+#define WIDGET1_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class Widget1;
+}
+QT_END_NAMESPACE
+
+class Widget1 : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit Widget1(QWidget* parent = nullptr);
+ ~Widget1();
+public slots:
+ void onTextChanged(const QString& text);
+
+private:
+ Ui::Widget1* ui;
+};
+
+#endif // WIDGET1_H
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.ui b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.ui
new file mode 100644
index 0000000000..db0c58d5df
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget1.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget1</class>
+ <widget class="QWidget" name="Widget1">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Input:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>OnTextChanged:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="OnTextChanged">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.cpp b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.cpp
new file mode 100644
index 0000000000..1dc28b0c8b
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "widget2.h"
+
+#include "src/ui_widget2.h"
+
+Widget2::Widget2(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::Widget2)
+{
+ ui->setupUi(this);
+ connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(onTextChanged(const QString&)));
+}
+
+Widget2::~Widget2()
+{
+ delete ui;
+}
+
+void Widget2::onTextChanged(const QString& text)
+{
+ ui->OnTextChanged->setText(text);
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.h b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.h
new file mode 100644
index 0000000000..e448b12caf
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef WIDGET2_H
+#define WIDGET2_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class Widget2;
+}
+QT_END_NAMESPACE
+
+class Widget2 : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit Widget2(QWidget* parent = nullptr);
+ ~Widget2();
+public slots:
+ void onTextChanged(const QString& text);
+
+private:
+ Ui::Widget2* ui;
+};
+
+#endif // WIDGET2_H
diff --git a/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.ui b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.ui
new file mode 100644
index 0000000000..facf4678f2
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/UicIncrementalBuild/src/widget2.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget2</class>
+ <widget class="QWidget" name="Widget2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Input:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>OnTextChanged:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="OnTextChanged">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/functions.cmake b/tests/auto/cmake/test_qt_add_ui_common/functions.cmake
new file mode 100644
index 0000000000..efb8b09774
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/functions.cmake
@@ -0,0 +1,223 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(generate_hash_folder target_name infile out_folder)
+ get_filename_component(infile_abs "${infile}" ABSOLUTE)
+ string(SHA1 infile_hash "${target_name}${infile_abs}")
+ string(SUBSTRING "${infile_hash}" 0 6 short_hash)
+ set(${out_folder} "${short_hash}" PARENT_SCOPE)
+endfunction()
+
+function(get_latest_vs_generator output)
+ execute_process(COMMAND ${CMAKE_COMMAND} -G
+ ERROR_VARIABLE CMAKE_GENERATORS_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REGEX MATCHALL "Visual Studio [0-9]+ [0-9]+" vs_generators
+ "${CMAKE_GENERATORS_ERROR}")
+
+ if(NOT vs_generators)
+ message(FATAL_ERROR "No visual studio generators found")
+ endif()
+
+ set(last_version "0")
+ set(last_generator "")
+ foreach(generator IN LISTS vs_generators)
+ string(REGEX MATCH "Visual Studio ([0-9]+) [0-9]+" unused "${generator}")
+ if("${CMAKE_MATCH_1}" VERSION_GREATER "${last_version}")
+ set(last_version "${CMAKE_MATCH_1}")
+ set(last_generator "${CMAKE_MATCH_0}")
+ endif()
+ endforeach()
+ set(${output} "${last_generator}" PARENT_SCOPE)
+endfunction()
+
+function(check_unwanted_builds_after_first_build cmake_output test_name test_dir
+ generator)
+ set(unwanted_builds_success_message
+ "\"${test_name}\" in \"${test_dir}\" -> No unwanted builds")
+ set(unwanted_builds_failure_message
+ "\"${test_name}\" in \"${test_dir}\" -> Unwanted builds found")
+ if(${generator} MATCHES "Ninja")
+ expect_string_not_contains(${cmake_output}
+ "widget2.cpp.o.d|mainwindow.cpp.o.d"
+ SUCCESS_MESSAGE ${unwanted_builds_success_message}
+ FAILURE_MESSAGE ${unwanted_builds_failure_message})
+ elseif(${generator} MATCHES "Make")
+ string(CONCAT not_expect_string
+ "Building CXX object UicIncrementalBuild/CMakeFiles"
+ "/example.dir/src/widget2.cpp.o|Building CXX object UicIncremental"
+ "Build/CMakeFiles/example.dir/src/mainwindow.cpp.o")
+ expect_string_not_contains(${cmake_output} "${not_expect_string}"
+ SUCCESS_MESSAGE ${unwanted_builds_success_message}
+ FAILURE_MESSAGE ${unwanted_builds_failure_message})
+ elseif(${generator} MATCHES "Visual Studio")
+ expect_string_not_contains(${cmake_output} "widget2.cpp|mainwindow.cpp"
+ SUCCESS_MESSAGE ${unwanted_builds_success_message}
+ FAILURE_MESSAGE ${unwanted_builds_failure_message})
+ elseif(${generator} MATCHES "Xcode")
+ expect_string_not_contains(${cmake_output} "widget2.cpp|mainwindow.cpp"
+ SUCCESS_MESSAGE ${unwanted_builds_success_message}
+ FAILURE_MESSAGE ${unwanted_builds_failure_message})
+ endif()
+endfunction()
+
+function(check_output_after_second_build cmake_output test_name
+ test_dir generator)
+ set(second_build_success_message
+ "\"${test_name}\" in \"${test_dir}\" -> Generation of UI files were not \
+triggered in the second build")
+ set(second_build_failure_message
+ "\"${test_name}\" in \"${test_dir}\" -> Generation of UI files were \
+triggered in the second build")
+
+ if(${generator} MATCHES "Ninja")
+ expect_string_contains(${cmake_output} "ninja: no work to do."
+ SUCCESS_MESSAGE ${second_build_success_message}
+ FAILURE_MESSAGE ${second_build_failure_message})
+ elseif(${generator} MATCHES "Visual Studio" OR ${generator} MATCHES "Xcode")
+ expect_string_not_contains(${cmake_output} "mainwindow"
+ SUCCESS_MESSAGE
+ ${second_build_success_message}
+ FAILURE_MESSAGE
+ ${second_build_failure_message})
+ elseif(${generator} MATCHES "Makefiles")
+ expect_string_not_contains(${cmake_output} "mainwindow.cpp.o.d -o"
+ SUCCESS_MESSAGE ${second_build_success_message}
+ FAILURE_MESSAGE ${second_build_failure_message})
+ endif()
+endfunction()
+
+function(incremental_build_test)
+ set(options CHECK_UNWANTED_BUILDS)
+ set(oneValueArgs CONFIG TEST_NAME SOURCE_DIR BUILD_DIR FILE_TO_TOUCH
+ FILE_TO_CHECK FOLDER_TO_CHECK GENERATOR)
+ set(multiValueArgs ADDITIONAL_ARGS)
+
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
+ ${ARGN})
+
+ string(REPLACE ";" " " arg_ADDITIONAL_ARGS "${arg_ADDITIONAL_ARGS}")
+ if ("${arg_SOURCE_DIR}" STREQUAL "")
+ message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" test failed because "
+ "SOURCE_DIR is empty")
+ endif()
+
+ if ("${arg_BUILD_DIR}" STREQUAL "")
+ message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" test failed because "
+ "BUILD_DIR is empty")
+ endif()
+
+ if ("${arg_GENERATOR}" STREQUAL "")
+ message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" test failed because "
+ "GENERATOR is empty")
+ endif()
+
+ run_cmake_configure(SOURCE_DIR "${arg_SOURCE_DIR}"
+ BUILD_DIR "${arg_BUILD_DIR}"
+ GENERATOR "${arg_GENERATOR}"
+ CLEAN_FIRST
+ ADDITIONAL_ARGS ${arg_ADDITIONAL_ARGS}
+ OUTPUT_VARIABLE cmake_output
+ ERROR_VARIABLE cmake_error
+ RESULT_VARIABLE cmake_result)
+
+ if(${cmake_result} EQUAL 0)
+ message(STATUS
+ "PASS: \"${arg_TEST_NAME}\" test in ${arg_BUILD_DIR} was configured "
+ "successfully")
+ else()
+ message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error: "
+ "${cmake_error}\nFAIL: \"${arg_TEST_NAME}\" test in ${arg_BUILD_DIR}"
+ " failed to configure")
+ endif()
+
+ if(NOT "${arg_CONFIG}" STREQUAL "single_config")
+ set(config_arg "${arg_CONFIG}")
+ endif()
+
+ run_cmake_build(BUILD_DIR ${arg_BUILD_DIR}
+ VERBOSE ON
+ CONFIG ${config_arg}
+ OUTPUT_VARIABLE cmake_build_output
+ ERROR_VARIABLE cmake_build_error
+ RESULT_VARIABLE cmake_build_result)
+
+ if(${cmake_build_result} EQUAL 0)
+ message(STATUS
+ "PASS: \"${arg_TEST_NAME}\" test in ${arg_BUILD_DIR} was built "
+ "successfully")
+ else()
+ message(FATAL_ERROR
+ "cmake_build_output: ${cmake_build_output}\ncmake_build_error: "
+ "${cmake_build_error}\nFAIL: \"${arg_TEST_NAME}\" test in "
+ "${arg_BUILD_DIR} failed to build")
+ endif()
+
+ if(NOT "${arg_FILE_TO_CHECK}" STREQUAL "")
+ if(NOT EXISTS "${arg_FILE_TO_CHECK}")
+ message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" ${arg_FILE_TO_CHECK}"
+ " could not be found")
+ else()
+ message(STATUS "PASS: \"${arg_TEST_NAME}\" \"${arg_FILE_TO_CHECK}\" "
+ "was generated successfully")
+ endif()
+ endif()
+
+ if(NOT "${arg_FOLDER_TO_CHECK}" STREQUAL "" AND NOT WIN32)
+ if(NOT EXISTS "${arg_FOLDER_TO_CHECK}")
+ message(FATAL_ERROR
+ "FAIL: \"${arg_TEST_NAME}\" Folder \"${arg_FOLDER_TO_CHECK}\" "
+ "does not exist")
+ else()
+ message(STATUS
+ "PASS: \"${arg_TEST_NAME}\" Folder \"${arg_FOLDER_TO_CHECK}\" "
+ "exists")
+ endif()
+ endif()
+
+ if(NOT "${arg_FILE_TO_TOUCH}" STREQUAL "")
+ file(TOUCH "${arg_FILE_TO_TOUCH}")
+ endif()
+
+ run_cmake_build(BUILD_DIR ${arg_BUILD_DIR}
+ VERBOSE ON
+ CONFIG ${arg_CONFIG}
+ OUTPUT_VARIABLE cmake_build_output)
+ if(${arg_CHECK_UNWANTED_BUILDS})
+ check_unwanted_builds_after_first_build(${cmake_build_output}
+ ${arg_TEST_NAME} ${arg_BUILD_DIR} ${arg_GENERATOR})
+ endif()
+
+ run_cmake_build(BUILD_DIR ${arg_BUILD_DIR}
+ VERBOSE ON
+ CONFIG ${arg_CONFIG}
+ OUTPUT_VARIABLE cmake_build_output)
+ check_output_after_second_build(${cmake_build_output}
+ ${arg_TEST_NAME} ${arg_BUILD_DIR} ${arg_GENERATOR})
+endfunction()
+
+function(get_generators output)
+ if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux")
+ set(generators "Unix Makefiles" "Ninja" "Ninja Multi-Config")
+ elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Windows")
+ # CI fails with Clang and Visual Studio generators.
+ # That's why discard that combination.
+ if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND
+ NOT MINGW)
+ get_latest_vs_generator(latest_vs)
+ endif()
+ set(generators "Ninja" "Ninja Multi-Config" "${latest_vs}")
+ elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin")
+ # TODO: Add Xcode generator when
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/25790 is fixed.
+ # Otherwise, adding Xcode generator might fail CI due to the timeout
+ # issue.
+ set(generators "Unix Makefiles" "Ninja" "Ninja Multi-Config")
+ else()
+ string(JOIN "" ERROR_MESSAGE
+ "FAIL: host OS not supported for this test."
+ "host : ${CMAKE_HOST_SYSTEM_NAME}")
+ message(FATAL_ERROR "${ERROR_MESSAGE}")
+ endif()
+ set(${output} "${generators}" PARENT_SCOPE)
+endfunction()
diff --git a/tests/auto/cmake/test_qt_add_ui_common/main.cpp b/tests/auto/cmake/test_qt_add_ui_common/main.cpp
new file mode 100644
index 0000000000..c93c3fc6a0
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/main.cpp
@@ -0,0 +1,4 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+int main() { return 0; }
diff --git a/tests/auto/cmake/test_qt_add_ui_common/uic_test/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_common/uic_test/CMakeLists.txt
new file mode 100644
index 0000000000..b05efd5e4d
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/uic_test/CMakeLists.txt
@@ -0,0 +1,65 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+project(UicTest LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui)
+
+set(CMAKE_AUTOMOC ON)
+
+if (NOT DO_NOT_GENERATE_FILE)
+ file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mainwindow.cpp"
+ CONTENT " \
+#include \"${CMAKE_CURRENT_SOURCE_DIR}/../UicBuildFolderLeakageCommon/mainwindow.h\" \n \
+#include \"${MAINWINDOW_UI_PATH}ui_mainwindow.h\" \n \
+MainWindow::MainWindow(QWidget* parent) \n \
+ : QMainWindow(parent) \n \
+ , ui(new Ui::MainWindow) \n \
+{ \n \
+ ui->setupUi(this); \n \
+} \n \
+ \n \
+MainWindow::~MainWindow() \n \
+{ \n \
+ delete ui; \n \
+} \n \
+")
+endif()
+
+qt_add_executable(example
+ ../UicBuildFolderLeakageCommon/main.cpp
+ ../UicBuildFolderLeakageCommon/mainwindow.h
+ mainwindow.ui
+)
+
+if (${DO_NOT_GENERATE_FILE})
+ target_sources(example PRIVATE mainwindow.cpp)
+else()
+ target_sources(example PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/mainwindow.cpp")
+endif()
+
+target_link_libraries(example PRIVATE Qt6::Widgets
+ Qt6::Core
+ Qt6::Gui)
+
+if (NOT UI_NO_CONFIG_OPTIONS)
+ set(uic_options "$<$<CONFIG:Debug>:-a>")
+endif()
+qt6_add_ui(example
+ INCLUDE_PREFIX "${MAINWINDOW_UI_PATH}"
+ SOURCES "mainwindow.ui"
+ OPTIONS "${uic_options}")
+
+if(ADD_NEW_UI)
+ qt6_add_ui(example INCLUDE_PREFIX "${NEW_UI_PATH}"
+ SOURCES "subdir/mainwindow.ui"
+ OPTIONS "${uic_options}")
+endif()
+
+# Enable AUTOUIC after qt6_add_ui() has been called
+if (CMAKE_AUTOUIC)
+ set_property(TARGET example PROPERTY AUTOUIC ON)
+endif()
+
diff --git a/tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.cpp b/tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.cpp
new file mode 100644
index 0000000000..1c4b48b49e
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "../UicBuildFolderLeakageCommon/mainwindow.h"
+#include "sub1/sub2/sub3/ui_mainwindow.h"
+
+MainWindow::MainWindow(QWidget* parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
diff --git a/tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.ui b/tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.ui
new file mode 100644
index 0000000000..4e57b05eac
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/uic_test/mainwindow.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>23</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/cmake/test_qt_add_ui_common/uic_test/subdir/mainwindow.ui b/tests/auto/cmake/test_qt_add_ui_common/uic_test/subdir/mainwindow.ui
new file mode 100644
index 0000000000..4e57b05eac
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/uic_test/subdir/mainwindow.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>23</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt b/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt
index 4bfdccdf86..31d8bff0a5 100644
--- a/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt
+++ b/tests/auto/corelib/global/qcomparehelpers/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qcomparehelpers
# CMake recognizes CXX_STANDARD=23 only starting from version 3.20
# macOS has some issues with concepts, see QTBUG-117765
-if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20" AND NOT MACOS AND NOT VXWORKS AND NOT (LINUX AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64"))
+if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20" AND NOT MACOS AND NOT VXWORKS AND NOT (LINUX AND "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64"))
qt_internal_add_test(tst_qcomparehelpers_cpp23
SOURCES
tst_qcomparehelpers.h tst_qcomparehelpers.cpp tst_qcomparehelpers1.cpp
diff --git a/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp b/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp
index f140c23ed0..cb114bc90b 100644
--- a/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp
+++ b/tests/auto/corelib/global/qcomparehelpers/tst_qcomparehelpers.cpp
@@ -597,4 +597,4 @@ void tst_QCompareHelpers::builtinOrder()
}
QTEST_MAIN(tst_QCompareHelpers)
-#include "tst_qcomparehelpers.moc"
+#include "moc_tst_qcomparehelpers.cpp"
diff --git a/tests/auto/corelib/global/qlogging/CMakeLists.txt b/tests/auto/corelib/global/qlogging/CMakeLists.txt
index b3c66aeb2e..f35c9c4192 100644
--- a/tests/auto/corelib/global/qlogging/CMakeLists.txt
+++ b/tests/auto/corelib/global/qlogging/CMakeLists.txt
@@ -23,7 +23,6 @@ set_target_properties(qlogging_helper PROPERTIES CXX_VISIBILITY_PRESET default)
qt_internal_add_test(tst_qlogging SOURCES tst_qlogging.cpp
DEFINES
QT_MESSAGELOGCONTEXT
- HELPER_BINARY="${CMAKE_CURRENT_BINARY_DIR}/qlogging_helper"
)
add_dependencies(tst_qlogging qlogging_helper)
diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
index 861e60e256..defe3ac421 100644
--- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
+++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
@@ -986,11 +986,9 @@ QString tst_qmessagehandler::backtraceHelperPath()
#ifdef Q_OS_ANDROID
QString appExe(QCoreApplication::applicationDirPath()
+ QLatin1String("/lib" BACKTRACE_HELPER_NAME ".so"));
-#elif defined(Q_OS_WEBOS)
+#else
QString appExe(QCoreApplication::applicationDirPath()
+ QLatin1String("/" BACKTRACE_HELPER_NAME));
-#else
- QString appExe(QLatin1String(HELPER_BINARY));
#endif
return appExe;
}
diff --git a/tests/auto/corelib/io/CMakeLists.txt b/tests/auto/corelib/io/CMakeLists.txt
index 7fdf4b52b0..291dbfb413 100644
--- a/tests/auto/corelib/io/CMakeLists.txt
+++ b/tests/auto/corelib/io/CMakeLists.txt
@@ -25,7 +25,7 @@ add_subdirectory(qloggingcategory)
add_subdirectory(qnodebug)
add_subdirectory(qsavefile)
add_subdirectory(qstandardpaths)
-if(NOT QNX)
+if(NOT QNX AND NOT VXWORKS)
add_subdirectory(qstorageinfo)
endif()
add_subdirectory(qtemporarydir)
diff --git a/tests/auto/corelib/io/largefile/tst_largefile.cpp b/tests/auto/corelib/io/largefile/tst_largefile.cpp
index 6fa3569c4f..f5af3bde63 100644
--- a/tests/auto/corelib/io/largefile/tst_largefile.cpp
+++ b/tests/auto/corelib/io/largefile/tst_largefile.cpp
@@ -46,6 +46,10 @@ public:
// This means that files are limited to 2 GB − 1 bytes.
// Limit max size to 256MB
maxSizeBits = 28; // 256 MiB
+ #elif defined(Q_OS_VXWORKS)
+ // VxWorks doesn't support sparse files, also, default /tmp directory is a RAM-disk which
+ // limits its capacity.
+ maxSizeBits = 28; // 256 MiB
#elif defined (Q_OS_WASM)
maxSizeBits = 28; // 256 MiB
#elif defined(QT_LARGEFILE_SUPPORT)
@@ -494,6 +498,7 @@ void tst_LargeFile::mapFile()
// 32-bit: limited to 44-bit offsets (when sizeof(off_t) == 8)
//Windows: memory-mapping beyond EOF is not allowed
//wasm: as for linux
+//VxWorks: memory-mapping beyond EOF is not allowed
void tst_LargeFile::mapOffsetOverflow()
{
enum {
@@ -506,6 +511,9 @@ void tst_LargeFile::mapOffsetOverflow()
#elif (defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)) && (Q_PROCESSOR_WORDSIZE == 4)
Succeeds = true,
MaxOffset = sizeof(QT_OFF_T) > 4 ? 43 : 30
+#elif defined(Q_OS_VXWORKS)
+ Succeeds = false,
+ MaxOffset = 8 * sizeof(QT_OFF_T) - 1
#else
Succeeds = true,
MaxOffset = 8 * sizeof(QT_OFF_T) - 1
diff --git a/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp
index a2747f55a7..cf00c1525c 100644
--- a/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp
+++ b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp
@@ -621,12 +621,12 @@ void tst_QAbstractFileEngine::fileIO()
* the original size + the '\r' characters added by autocrlf. */
QFile::OpenMode openMode = QIODevice::ReadOnly | QIODevice::Unbuffered;
-#ifdef Q_OS_WIN
+#if defined (Q_OS_WIN) || defined(Q_OS_WASM)
openMode |= QIODevice::Text;
#endif
QVERIFY(file.open(openMode));
QVERIFY(file.isOpen());
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_OS_WASM)
const qint64 convertedSize = fileSize + readContent.count('\n');
if (file.size() == convertedSize)
fileSize = convertedSize;
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index f7d531f61f..563e4c2a83 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -1217,9 +1217,16 @@ void tst_QFileInfo::setFileTimes()
QCOMPARE(file.write(data), data.size());
QCOMPARE(file.size(), data.size());
- const QDateTime before = QDateTime::currentDateTimeUtc().addMSecs(-5000);
+ QDateTime before = QDateTime::currentDateTimeUtc().addMSecs(-5000);
+
QVERIFY(file.setFileTime(before, QFile::FileModificationTime));
const QDateTime mtime = file.fileTime(QFile::FileModificationTime).toUTC();
+ if (mtime.time().msec() == 0)
+ {
+ const QTime beforeTime = before.time();
+ const QTime beforeTimeWithMSCutOff{beforeTime.hour(), beforeTime.minute(), beforeTime.second(), 0};
+ before.setTime(beforeTimeWithMSCutOff);
+ }
QCOMPARE(mtime, before);
}
diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp
index a5b0087f9c..184eef3f15 100644
--- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp
+++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp
@@ -26,14 +26,18 @@
using namespace std::chrono_literals;
#if defined(Q_OS_QNX)
-// Longer polling times on QNX, otherwise the tests fail on the CI
+constexpr bool isQNX = true;
+#else
+constexpr bool isQNX = false;
+#endif
+
+#if defined(Q_OS_QNX) || defined(Q_OS_VXWORKS)
+// Longer polling times on QNX and VxWorks, otherwise the tests fail on the CI
constexpr auto nativeEngineTimeout = 1s;
constexpr auto pollingEngineTimeout = 1s;
-constexpr bool isQNX = true;
#else
constexpr auto nativeEngineTimeout = 0ms;
constexpr auto pollingEngineTimeout = 20ms;
-constexpr bool isQNX = false;
#endif
/* All tests need to run in temporary directories not used
diff --git a/tests/auto/corelib/io/qprocess/testBatFiles/simple.bat b/tests/auto/corelib/io/qprocess/testBatFiles/simple.bat
index 900f7ae356..8567e16850 100755
--- a/tests/auto/corelib/io/qprocess/testBatFiles/simple.bat
+++ b/tests/auto/corelib/io/qprocess/testBatFiles/simple.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
@echo off
-echo Hello \ No newline at end of file
+echo Hello
diff --git a/tests/auto/corelib/io/qprocess/testBatFiles/with space.bat b/tests/auto/corelib/io/qprocess/testBatFiles/with space.bat
index 900f7ae356..8567e16850 100755
--- a/tests/auto/corelib/io/qprocess/testBatFiles/with space.bat
+++ b/tests/auto/corelib/io/qprocess/testBatFiles/with space.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
@echo off
-echo Hello \ No newline at end of file
+echo Hello
diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
index 1056eaa107..5f35732979 100644
--- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
+++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
@@ -48,6 +48,7 @@ private slots:
void constructing();
void simpleStart();
void startCommand();
+ void startCommandEmptyString();
void startWithOpen();
void startWithOldOpen();
void execute();
@@ -299,6 +300,25 @@ void tst_QProcess::startCommand()
QCOMPARE(actual, expected);
}
+void tst_QProcess::startCommandEmptyString()
+{
+ static const char warningMsg[] =
+ "QProcess::startCommand: empty or whitespace-only command was provided";
+ QProcess process;
+
+ QTest::ignoreMessage(QtWarningMsg, warningMsg);
+ process.startCommand("");
+ QVERIFY(!process.waitForStarted());
+
+ QTest::ignoreMessage(QtWarningMsg, warningMsg);
+ process.startCommand(" ");
+ QVERIFY(!process.waitForStarted());
+
+ QTest::ignoreMessage(QtWarningMsg, warningMsg);
+ process.startCommand("\t\n");
+ QVERIFY(!process.waitForStarted());
+}
+
void tst_QProcess::startWithOpen()
{
QProcess p;
diff --git a/tests/auto/corelib/io/qresourceengine/generateResources.sh b/tests/auto/corelib/io/qresourceengine/generateResources.sh
index 9894f6bfb7..18d1e0b80f 100755
--- a/tests/auto/corelib/io/qresourceengine/generateResources.sh
+++ b/tests/auto/corelib/io/qresourceengine/generateResources.sh
@@ -1,3 +1,5 @@
+# Copyright (C) 2016 Intel Corporation.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#!/bin/sh
count=`awk '/ZERO_FILE_LEN/ { print $3 }' tst_qresourceengine.cpp`
dd if=/dev/zero of=zero.txt bs=1 count=$count
diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/test.qrc b/tests/auto/corelib/io/qresourceengine/testqrc/test.qrc
index f5e8c849a6..56972ea764 100644
--- a/tests/auto/corelib/io/qresourceengine/testqrc/test.qrc
+++ b/tests/auto/corelib/io/qresourceengine/testqrc/test.qrc
@@ -9,10 +9,10 @@
<file>searchpath1/search_file.txt</file>
<file>searchpath2/search_file.txt</file>
<file>search_file.txt</file>
- </qresource>
- <qresource><file>test/testdir.txt</file>
+ <file>test/testdir.txt</file>
<file>otherdir/otherdir.txt</file>
<file alias="aliasdir/aliasdir.txt">test/testdir2.txt</file>
+ <file alias="uncompresseddir/uncompressed.txt" compression-algorithm="none">aliasdir/compressme.txt</file>
<file>test/test</file>
</qresource>
<qresource lang="ko">
@@ -21,7 +21,7 @@
<qresource lang="de_CH">
<file alias="aliasdir/aliasdir.txt" compress="9" threshold="30">aliasdir/compressme.txt</file>
</qresource>
- <qresource lang="de">
+ <qresource lang="de" compression-algorithm="none">
<file alias="aliasdir/aliasdir.txt">test/german.txt</file>
</qresource>
<qresource prefix="withoutslashes">
diff --git a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
index fc9b9ee201..f0dab35f81 100644
--- a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
+++ b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
@@ -45,6 +45,7 @@ private slots:
private:
const QString m_runtimeResourceRcc;
+ QByteArray m_runtimeResourceData;
};
@@ -73,15 +74,27 @@ void tst_QResourceEngine::initTestCase()
#endif
QVERIFY(!m_runtimeResourceRcc.isEmpty());
+
+ QFile resourceFile(m_runtimeResourceRcc);
+ QVERIFY2(resourceFile.open(QIODevice::ReadOnly), qPrintable(resourceFile.errorString()));
+
+ // register once with the file name, which will attempt to use mmap()
+ // (uses QDynamicFileResourceRoot)
QVERIFY(QResource::registerResource(m_runtimeResourceRcc));
- QVERIFY(QResource::registerResource(m_runtimeResourceRcc, "/secondary_root/"));
+
+ // and register a second time with a gifted memory block
+ // (uses QDynamicBufferResourceRoot)
+ m_runtimeResourceData = resourceFile.readAll();
+ auto resourcePtr = reinterpret_cast<const uchar *>(m_runtimeResourceData.constData());
+ QVERIFY(QResource::registerResource(resourcePtr, "/secondary_root/"));
}
void tst_QResourceEngine::cleanupTestCase()
{
// make sure we don't leak memory
QVERIFY(QResource::unregisterResource(m_runtimeResourceRcc));
- QVERIFY(QResource::unregisterResource(m_runtimeResourceRcc, "/secondary_root/"));
+ auto resourcePtr = reinterpret_cast<const uchar *>(m_runtimeResourceData.constData());
+ QVERIFY(QResource::unregisterResource(resourcePtr, "/secondary_root/"));
}
void tst_QResourceEngine::compressedResource_data()
@@ -180,6 +193,7 @@ void tst_QResourceEngine::checkStructure_data()
#if defined(BUILTIN_TESTDATA)
<< QLatin1String("testqrc")
#endif
+ << QLatin1String("uncompresseddir")
<< QLatin1String("withoutslashes");
QTest::newRow("root dir") << QString(":/")
@@ -212,56 +226,56 @@ void tst_QResourceEngine::checkStructure_data()
for(int i = 0; i < roots.size(); ++i) {
const QString root = roots.at(i);
- QTest::addRow("%s prefix dir", qPrintable(root)) << QString(root + "test/abc/123/+++")
+ QTest::addRow("prefix dir on %s", qPrintable(root)) << QString(root + "test/abc/123/+++")
<< QByteArray()
<< (QStringList() << QLatin1String("currentdir.txt") << QLatin1String("currentdir2.txt") << QLatin1String("parentdir.txt"))
<< (QStringList() << QLatin1String("subdir"))
<< QLocale::c()
<< qlonglong(0);
- QTest::addRow("%s parent to prefix", qPrintable(root)) << QString(root + "test/abc/123")
+ QTest::addRow("parent to prefix on %s", qPrintable(root)) << QString(root + "test/abc/123")
<< QByteArray()
<< QStringList()
<< (QStringList() << QLatin1String("+++"))
<< QLocale::c()
<< qlonglong(0);
- QTest::addRow("%s two parents prefix", qPrintable(root)) << QString(root + "test/abc")
+ QTest::addRow("two parents prefix on %s", qPrintable(root)) << QString(root + "test/abc")
<< QByteArray()
<< QStringList()
<< QStringList(QLatin1String("123"))
<< QLocale::c()
<< qlonglong(0);
- QTest::addRow("%s test dir ", qPrintable(root)) << QString(root + "test")
+ QTest::addRow("test dir on %s", qPrintable(root)) << QString(root + "test")
<< QByteArray()
<< (QStringList() << QLatin1String("testdir.txt"))
<< (QStringList() << QLatin1String("abc") << QLatin1String("test"))
<< QLocale::c()
<< qlonglong(0);
- QTest::addRow("%s prefix no slashes", qPrintable(root)) << QString(root + "withoutslashes")
+ QTest::addRow("prefix no slashes on %s", qPrintable(root)) << QString(root + "withoutslashes")
<< QByteArray()
<< QStringList("blahblah.txt")
<< QStringList()
<< QLocale::c()
<< qlonglong(0);
- QTest::addRow("%s other dir", qPrintable(root)) << QString(root + "otherdir")
+ QTest::addRow("other dir on %s", qPrintable(root)) << QString(root + "otherdir")
<< QByteArray()
<< QStringList(QLatin1String("otherdir.txt"))
<< QStringList()
<< QLocale::c()
<< qlonglong(0);
- QTest::addRow("%s alias dir", qPrintable(root)) << QString(root + "aliasdir")
+ QTest::addRow("alias dir on %s", qPrintable(root)) << QString(root + "aliasdir")
<< QByteArray()
<< QStringList(QLatin1String("aliasdir.txt"))
<< QStringList()
<< QLocale::c()
<< qlonglong(0);
- QTest::addRow("%s second test dir", qPrintable(root)) << QString(root + "test/test")
+ QTest::addRow("second test dir on %s", qPrintable(root)) << QString(root + "test/test")
<< QByteArray()
<< (QStringList() << QLatin1String("test1.txt") << QLatin1String("test2.txt"))
<< QStringList()
@@ -269,7 +283,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(0);
info = QFileInfo(QFINDTESTDATA("testqrc/test/test/test1.txt"));
- QTest::addRow("%s test1 text", qPrintable(root)) << QString(root + "test/test/test1.txt")
+ QTest::addRow("test1 text on %s", qPrintable(root)) << QString(root + "test/test/test1.txt")
<< QByteArray("abc\n")
<< QStringList()
<< QStringList()
@@ -277,7 +291,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/blahblah.txt"));
- QTest::addRow("%s text no slashes", qPrintable(root)) << QString(root + "withoutslashes/blahblah.txt")
+ QTest::addRow("text no slashes on %s", qPrintable(root)) << QString(root + "withoutslashes/blahblah.txt")
<< QByteArray("qwerty\n")
<< QStringList()
<< QStringList()
@@ -286,7 +300,7 @@ void tst_QResourceEngine::checkStructure_data()
info = QFileInfo(QFINDTESTDATA("testqrc/test/test/test2.txt"));
- QTest::addRow("%s test2 text", qPrintable(root)) << QString(root + "test/test/test2.txt")
+ QTest::addRow("test2 text on %s", qPrintable(root)) << QString(root + "test/test/test2.txt")
<< QByteArray("def\n")
<< QStringList()
<< QStringList()
@@ -294,7 +308,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/currentdir.txt"));
- QTest::addRow("%s currentdir text", qPrintable(root)) << QString(root + "test/abc/123/+++/currentdir.txt")
+ QTest::addRow("currentdir text on %s", qPrintable(root)) << QString(root + "test/abc/123/+++/currentdir.txt")
<< QByteArray("\"This is the current dir\"\n")
<< QStringList()
<< QStringList()
@@ -302,7 +316,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/currentdir2.txt"));
- QTest::addRow("%s currentdir text2", qPrintable(root)) << QString(root + "test/abc/123/+++/currentdir2.txt")
+ QTest::addRow("currentdir text2 on %s", qPrintable(root)) << QString(root + "test/abc/123/+++/currentdir2.txt")
<< QByteArray("\"This is also the current dir\"\n")
<< QStringList()
<< QStringList()
@@ -310,7 +324,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("parentdir.txt"));
- QTest::addRow("%s parentdir text", qPrintable(root)) << QString(root + "test/abc/123/+++/parentdir.txt")
+ QTest::addRow("parentdir text on %s", qPrintable(root)) << QString(root + "test/abc/123/+++/parentdir.txt")
<< QByteArray("abcdefgihklmnopqrstuvwxyz \n")
<< QStringList()
<< QStringList()
@@ -318,7 +332,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/subdir/subdir.txt"));
- QTest::addRow("%s subdir text", qPrintable(root)) << QString(root + "test/abc/123/+++/subdir/subdir.txt")
+ QTest::addRow("subdir text on %s", qPrintable(root)) << QString(root + "test/abc/123/+++/subdir/subdir.txt")
<< QByteArray("\"This is in the sub directory\"\n")
<< QStringList()
<< QStringList()
@@ -326,7 +340,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/test/testdir.txt"));
- QTest::addRow("%s testdir text", qPrintable(root)) << QString(root + "test/testdir.txt")
+ QTest::addRow("testdir text on %s", qPrintable(root)) << QString(root + "test/testdir.txt")
<< QByteArray("\"This is in the test directory\"\n")
<< QStringList()
<< QStringList()
@@ -334,7 +348,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/otherdir/otherdir.txt"));
- QTest::addRow("%s otherdir text", qPrintable(root)) << QString(root + "otherdir/otherdir.txt")
+ QTest::addRow("otherdir text on %s", qPrintable(root)) << QString(root + "otherdir/otherdir.txt")
<< QByteArray("\"This is the other dir\"\n")
<< QStringList()
<< QStringList()
@@ -342,7 +356,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/test/testdir2.txt"));
- QTest::addRow("%s alias text", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
+ QTest::addRow("alias text on %s", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
<< QByteArray("\"This is another file in this directory\"\n")
<< QStringList()
<< QStringList()
@@ -350,7 +364,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/aliasdir/aliasdir.txt"));
- QTest::addRow("%s korean text", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
+ QTest::addRow("korean text on %s", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
<< QByteArray("\"This is a korean text file\"\n")
<< QStringList()
<< QStringList()
@@ -358,7 +372,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/aliasdir/aliasdir.txt"));
- QTest::addRow("%s korean text 2", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
+ QTest::addRow("korean text 2 on %s", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
<< QByteArray("\"This is a korean text file\"\n")
<< QStringList()
<< QStringList()
@@ -366,7 +380,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/test/german.txt"));
- QTest::addRow("%s german text", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
+ QTest::addRow("german text on %s", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
<< QByteArray("Deutsch\n")
<< QStringList()
<< QStringList()
@@ -374,7 +388,7 @@ void tst_QResourceEngine::checkStructure_data()
<< qlonglong(info.size());
info = QFileInfo(QFINDTESTDATA("testqrc/test/german.txt"));
- QTest::addRow("%s german text 2", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
+ QTest::addRow("german text 2 on %s", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
<< QByteArray("Deutsch\n")
<< QStringList()
<< QStringList()
@@ -384,8 +398,16 @@ void tst_QResourceEngine::checkStructure_data()
QFile file(QFINDTESTDATA("testqrc/aliasdir/compressme.txt"));
QVERIFY(file.open(QFile::ReadOnly));
info = QFileInfo(QFINDTESTDATA("testqrc/aliasdir/compressme.txt"));
- QTest::addRow("%s compressed text", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
- << file.readAll()
+ QByteArray compressmeContents = file.readAll();
+ QTest::addRow("compressed text on %s", qPrintable(root)) << QString(root + "aliasdir/aliasdir.txt")
+ << compressmeContents
+ << QStringList()
+ << QStringList()
+ << QLocale("de_CH")
+ << qlonglong(info.size());
+
+ QTest::addRow("non-compressed text on %s", qPrintable(root)) << QString(root + "uncompresseddir/uncompressed.txt")
+ << compressmeContents
<< QStringList()
<< QStringList()
<< QLocale("de_CH")
@@ -463,6 +485,18 @@ void tst_QResourceEngine::checkStructure()
// check that it is still valid after closing the file
file.close();
QCOMPARE(ba, contents);
+
+ // memory should be writable because we used MapPrivateOption
+ *ptr = '\0';
+
+ // but shouldn't affect the actual file or a new mapping
+ QFile file2(pathName);
+ QVERIFY(file2.open(QFile::ReadOnly));
+ QCOMPARE(file2.readAll(), contents);
+ ptr = file2.map(0, file.size(), QFile::MapPrivateOption);
+ QVERIFY2(ptr, qPrintable(file2.errorString()));
+ QByteArrayView bav(reinterpret_cast<const char *>(ptr), file.size());
+ QCOMPARE(bav, contents);
}
QLocale::setDefault(QLocale::system());
}
diff --git a/tests/auto/corelib/io/qsavefile/tst_qsavefile.cpp b/tests/auto/corelib/io/qsavefile/tst_qsavefile.cpp
index fbb6a29f26..c027f8a3c1 100644
--- a/tests/auto/corelib/io/qsavefile/tst_qsavefile.cpp
+++ b/tests/auto/corelib/io/qsavefile/tst_qsavefile.cpp
@@ -5,6 +5,7 @@
#include <QSaveFile>
#include <qcoreapplication.h>
#include <qstring.h>
+#include <qsystemdetection.h>
#include <qtemporaryfile.h>
#include <qfile.h>
#include <qdir.h>
@@ -89,17 +90,34 @@ void tst_QSaveFile::transactionalWrite()
QCOMPARE(file.fileName(), targetFile);
QVERIFY(!QFile::exists(targetFile));
- QCOMPARE(file.write("Hello"), Q_INT64_C(5));
+ const char *data = "Hello";
+ QCOMPARE(file.write(data), qint64(strlen(data)));
QCOMPARE(file.error(), QFile::NoError);
QVERIFY(!QFile::exists(targetFile));
+ QVERIFY(file.fileTime(QFile::FileModificationTime).isValid());
QVERIFY(file.commit());
QVERIFY(QFile::exists(targetFile));
QCOMPARE(file.fileName(), targetFile);
+#if defined(Q_OS_WIN)
+ // Without this delay, file.fileTime() and file.size() tests fail to
+ // pass on Windows in the CI. It passes locally in a VM, so it looks like
+ // it depends on how often different filesystems on different OSes, update
+ // their metadata.
+ // Interestingly, this delay is enough to fix similar tests in the rest
+ // of tst_QSaveFile's functions.
+ QTRY_VERIFY(file.fileTime(QFile::FileModificationTime).isValid());
+#else
+ QVERIFY(file.fileTime(QFile::FileModificationTime).isValid());
+#endif
+
+ QCOMPARE(file.size(), qint64(strlen(data)));
QFile reader(targetFile);
QVERIFY(reader.open(QIODevice::ReadOnly));
- QCOMPARE(QString::fromLatin1(reader.readAll()), QString::fromLatin1("Hello"));
+ QCOMPARE(QString::fromLatin1(reader.readAll()), QString::fromLatin1(data));
+ QCOMPARE(file.fileTime(QFile::FileModificationTime),
+ reader.fileTime(QFile::FileModificationTime));
// check that permissions are the same as for QFile
const QString otherFile = dir.path() + QString::fromLatin1("/otherfile");
@@ -124,12 +142,13 @@ void tst_QSaveFile::retryTransactionalWrite()
QTemporaryDir dir;
QVERIFY2(dir.isValid(), qPrintable(dir.errorString()));
+ const char *data = "Hello";
QString targetFile = dir.path() + QLatin1String("/outfile");
const QString readOnlyName = targetFile + QLatin1String(".ro");
{
QFile readOnlyFile(readOnlyName);
QVERIFY2(readOnlyFile.open(QIODevice::WriteOnly), msgCannotOpen(readOnlyFile).constData());
- readOnlyFile.write("Hello");
+ readOnlyFile.write(data);
readOnlyFile.close();
auto permissions = readOnlyFile.permissions();
permissions &= ~(QFileDevice::WriteOwner | QFileDevice::WriteGroup | QFileDevice::WriteUser);
@@ -142,13 +161,15 @@ void tst_QSaveFile::retryTransactionalWrite()
file.setFileName(targetFile);
QVERIFY2(file.open(QIODevice::WriteOnly), msgCannotOpen(file).constData());
QVERIFY(file.isOpen());
- QCOMPARE(file.write("Hello"), Q_INT64_C(5));
+ QCOMPARE(file.write(data), qint64(strlen(data)));
QCOMPARE(file.error(), QFile::NoError);
QVERIFY(file.commit());
+ QCOMPARE(file.size(), qint64(strlen(data)));
}
void tst_QSaveFile::saveTwice()
{
+ const char *hello = "Hello";
// Check that we can reuse a QSaveFile object
// (and test the case of an existing target file)
QTemporaryDir dir;
@@ -156,16 +177,19 @@ void tst_QSaveFile::saveTwice()
const QString targetFile = dir.path() + QString::fromLatin1("/outfile");
QSaveFile file(targetFile);
QVERIFY2(file.open(QIODevice::WriteOnly), msgCannotOpen(file).constData());
- QCOMPARE(file.write("Hello"), Q_INT64_C(5));
+ QCOMPARE(file.write(hello), qint64(strlen(hello)));
QVERIFY2(file.commit(), qPrintable(file.errorString()));
+ QCOMPARE(file.size(), qint64(strlen(hello)));
+ const char *world = "World";
QVERIFY2(file.open(QIODevice::WriteOnly), msgCannotOpen(file).constData());
- QCOMPARE(file.write("World"), Q_INT64_C(5));
+ QCOMPARE(file.write(world), qint64(strlen(world)));
QVERIFY2(file.commit(), qPrintable(file.errorString()));
+ QCOMPARE(file.size(), qint64(strlen(world)));
QFile reader(targetFile);
QVERIFY2(reader.open(QIODevice::ReadOnly), msgCannotOpen(reader).constData());
- QCOMPARE(QString::fromLatin1(reader.readAll()), QString::fromLatin1("World"));
+ QCOMPARE(QString::fromLatin1(reader.readAll()), QString::fromLatin1(world));
}
void tst_QSaveFile::textStreamManualFlush()
@@ -176,16 +200,18 @@ void tst_QSaveFile::textStreamManualFlush()
QSaveFile file(targetFile);
QVERIFY2(file.open(QIODevice::WriteOnly), msgCannotOpen(file).constData());
+ const char *data = "Manual flush";
QTextStream ts(&file);
- ts << "Manual flush";
+ ts << data;
ts.flush();
QCOMPARE(file.error(), QFile::NoError);
QVERIFY(!QFile::exists(targetFile));
QVERIFY(file.commit());
+ QCOMPARE(file.size(), qint64(strlen(data)));
QFile reader(targetFile);
QVERIFY(reader.open(QIODevice::ReadOnly));
- QCOMPARE(QString::fromLatin1(reader.readAll().constData()), QString::fromLatin1("Manual flush"));
+ QCOMPARE(QString::fromLatin1(reader.readAll().constData()), QString::fromLatin1(data));
QFile::remove(targetFile);
}
@@ -432,6 +458,7 @@ void tst_QSaveFile::symlink()
QVERIFY(saveFile.open(QIODevice::WriteOnly));
QCOMPARE(saveFile.write(someData), someData.size());
saveFile.commit();
+ QCOMPARE(saveFile.size(), someData.size());
QFile file(targetFile);
QVERIFY2(file.open(QIODevice::ReadOnly), msgCannotOpen(file).constData());
@@ -461,6 +488,7 @@ void tst_QSaveFile::symlink()
QVERIFY(saveFile.open(QIODevice::WriteOnly));
QCOMPARE(saveFile.write(someData), someData.size());
saveFile.commit();
+ QCOMPARE(saveFile.size(), someData.size());
// the explicit file becomes a file instead of a link
QVERIFY(!QFileInfo(cyclicLink + QLatin1Char('1')).isSymLink());
@@ -540,6 +568,7 @@ void tst_QSaveFile::alternateDataStream()
QVERIFY2(file.open(QIODevice::WriteOnly), qPrintable(file.errorString()));
file.write(newContent);
QVERIFY2(file.commit(), qPrintable(file.errorString()));
+ QCOMPARE(file.size(), qint64(strlen(newContent)));
// check the contents
QFile targetFile(adsName);
diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
index 4bb7042790..84d0a505a4 100644
--- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
+++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
@@ -430,7 +430,7 @@ void tst_qstandardpaths::testAppConfigLocation()
#endif
}
-#ifndef Q_OS_WIN
+#if !defined(Q_OS_WIN) && !defined(Q_OS_WASM)
// Find "sh" on Unix.
// It may exist twice, in /bin/sh and /usr/bin/sh, in that case use the PATH order.
static inline QFileInfo findSh()
@@ -484,6 +484,7 @@ void tst_qstandardpaths::testFindExecutable_data()
<< QString() << logo << logoPath;
}
#else
+# ifndef Q_OS_WASM
const QFileInfo shFi = findSh();
Q_ASSERT(shFi.exists());
const QString shPath = shFi.absoluteFilePath();
@@ -493,6 +494,7 @@ void tst_qstandardpaths::testFindExecutable_data()
<< QString() << shPath << shPath;
QTest::newRow("unix-sh-relativepath")
<< QString(shFi.absolutePath()) << QString::fromLatin1("./sh") << shPath;
+#endif /* !WASM */
#endif
QTest::newRow("idontexist")
<< QString() << QString::fromLatin1("idontexist") << QString();
@@ -524,6 +526,9 @@ void tst_qstandardpaths::testFindExecutable()
void tst_qstandardpaths::testFindExecutableLinkToDirectory()
{
+#ifdef Q_OS_WASM
+ QSKIP("No applicationdir on wasm");
+#else
// link to directory
const QString target = QDir::tempPath() + QDir::separator() + QLatin1String("link.lnk");
QFile::remove(target);
@@ -531,6 +536,7 @@ void tst_qstandardpaths::testFindExecutableLinkToDirectory()
QVERIFY(appFile.link(target));
QVERIFY(QStandardPaths::findExecutable(target).isEmpty());
QFile::remove(target);
+#endif
}
using RuntimeDirSetup = std::optional<QString> (*)(QDir &);
diff --git a/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp b/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp
index 6a6339a8ec..5242988fd1 100644
--- a/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp
+++ b/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp
@@ -262,7 +262,9 @@ void tst_QStorageInfo::freeSpaceUpdate()
FlushFileBuffers(HANDLE(_get_osfhandle(file.handle())));
#elif _POSIX_VERSION >= 200112L
fsync(file.handle());
+# ifndef Q_OS_VXWORKS
sync();
+# endif // Q_OS_VXWORKS
#endif
};
diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp
index 81cd94e4ed..2024968435 100644
--- a/tests/auto/corelib/io/qurl/tst_qurl.cpp
+++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp
@@ -3776,13 +3776,13 @@ void tst_QUrl::setComponents_data()
<< PrettyDecoded << QString() << "foo:/path";
QTest::newRow("host-empty") << QUrl("foo://example.com/path")
<< int(Host) << "" << Tolerant << true
- << PrettyDecoded << QString() << "foo:///path";
+ << PrettyDecoded << "" << "foo:///path";
QTest::newRow("authority-null") << QUrl("foo://example.com/path")
<< int(Authority) << QString() << Tolerant << true
<< PrettyDecoded << QString() << "foo:/path";
QTest::newRow("authority-empty") << QUrl("foo://example.com/path")
<< int(Authority) << "" << Tolerant << true
- << PrettyDecoded << QString() << "foo:///path";
+ << PrettyDecoded << "" << "foo:///path";
QTest::newRow("query-null") << QUrl("http://example.com/?q=foo")
<< int(Query) << QString() << Tolerant << true
<< PrettyDecoded << QString() << "http://example.com/";
@@ -3840,10 +3840,10 @@ void tst_QUrl::setComponents_data()
<< PrettyDecoded << QString() << QString();
QTest::newRow("invalid-authority-1") << QUrl("http://example.com")
<< int(Authority) << "-not-valid-" << Tolerant << false
- << PrettyDecoded << QString() << QString();
+ << PrettyDecoded << "" << QString();
QTest::newRow("invalid-authority-2") << QUrl("http://example.com")
<< int(Authority) << "%31%30.%30.%30.%31" << Strict << false
- << PrettyDecoded << QString() << QString();
+ << PrettyDecoded << "" << QString();
QTest::newRow("invalid-path-0") << QUrl("http://example.com")
<< int(Path) << "{}" << Strict << false
@@ -4126,14 +4126,30 @@ void tst_QUrl::testThreadingHelper()
void tst_QUrl::testThreading()
{
+ enum { Count = 100 };
+
if (QTestPrivate::isRunningArmOnX86())
QSKIP("This test fails in QEMU and looks like because of a data race, QTBUG-93176");
s_urlStorage = new UrlStorage;
- QThreadPool::globalInstance()->setMaxThreadCount(100);
- QFutureSynchronizer<void> sync;
- for (int i = 0; i < 100; ++i)
- sync.addFuture(QtConcurrent::run(&tst_QUrl::testThreadingHelper, this));
- sync.waitForFinished();
+ QThreadPool::globalInstance()->setMaxThreadCount(Count);
+
+ // Written this way because wasm need the eventloop
+ QList<QFuture<void>> futures;
+ futures.reserve(Count);
+
+ for (int i = 0; i < Count; ++i)
+ futures.push_back(QtConcurrent::run(&tst_QUrl::testThreadingHelper, this));
+
+ QEventLoop loop;
+ std::atomic<int> remaining = Count;
+ for (int i = 0; i < Count; ++i) {
+ futures[i].then([&]() {
+ if (!--remaining)
+ loop.quit();
+ });
+ }
+ loop.exec();
+
delete s_urlStorage;
}
diff --git a/tests/auto/corelib/io/qurlquery/tst_qurlquery.cpp b/tests/auto/corelib/io/qurlquery/tst_qurlquery.cpp
index 8a799fbf94..8360bdbe28 100644
--- a/tests/auto/corelib/io/qurlquery/tst_qurlquery.cpp
+++ b/tests/auto/corelib/io/qurlquery/tst_qurlquery.cpp
@@ -73,9 +73,12 @@ static QByteArray prettyList(const QueryItems &items)
static bool compare(const QueryItems &actual, const QueryItems &expected,
const char *actualStr, const char *expectedStr, const char *file, int line)
{
+ auto formatter = [](const void *val) -> const char * {
+ const QueryItems items = *static_cast<const QueryItems *>(val);
+ return qstrdup(prettyList(items).constData());
+ };
return QTest::compare_helper(actual == expected, "Compared values are not the same",
- [&actual] { return qstrdup(prettyList(actual).constData()); },
- [&expected] { return qstrdup(prettyList(expected).constData()); },
+ &actual, &expected, formatter, formatter,
actualStr, expectedStr, file, line);
}
diff --git a/tests/auto/corelib/itemmodels/CMakeLists.txt b/tests/auto/corelib/itemmodels/CMakeLists.txt
index 90211669d9..c0cd04df12 100644
--- a/tests/auto/corelib/itemmodels/CMakeLists.txt
+++ b/tests/auto/corelib/itemmodels/CMakeLists.txt
@@ -4,15 +4,17 @@
add_subdirectory(qstringlistmodel)
if(TARGET Qt::Gui)
add_subdirectory(qabstractitemmodel)
- add_subdirectory(qabstractproxymodel)
- add_subdirectory(qconcatenatetablesproxymodel)
- add_subdirectory(qidentityproxymodel)
+ if(QT_FEATURE_proxymodel)
+ add_subdirectory(qabstractproxymodel)
+ add_subdirectory(qconcatenatetablesproxymodel)
+ add_subdirectory(qidentityproxymodel)
+ add_subdirectory(qsortfilterproxymodel_recursive)
+ add_subdirectory(qsortfilterproxymodel_regularexpression)
+ add_subdirectory(qtransposeproxymodel)
+ endif()
add_subdirectory(qitemselectionmodel)
- add_subdirectory(qsortfilterproxymodel_recursive)
- add_subdirectory(qsortfilterproxymodel_regularexpression)
- add_subdirectory(qtransposeproxymodel)
endif()
-if(TARGET Qt::Widgets)
+if(TARGET Qt::Widgets AND QT_FEATURE_proxymodel)
add_subdirectory(qsortfilterproxymodel)
endif()
if(TARGET Qt::Sql AND TARGET Qt::Widgets)
diff --git a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
index 36eb9320a4..6b1e4ce9ba 100644
--- a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
+++ b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
@@ -6,7 +6,9 @@
#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QtCore/QCoreApplication>
+#if QT_CONFIG(sortfilterproxymodel)
#include <QtCore/QSortFilterProxyModel>
+#endif
#include <QtCore/QStringListModel>
#include <QtGui/QStandardItemModel>
@@ -80,9 +82,11 @@ private slots:
void testMoveWithinOwnRange_data();
void testMoveWithinOwnRange();
+#if QT_CONFIG(sortfilterproxymodel)
void testMoveThroughProxy();
void testReset();
+#endif
void testDataChanged();
@@ -1239,6 +1243,7 @@ void tst_QAbstractItemModel::testMoveSameParentUp()
}
}
+#if QT_CONFIG(sortfilterproxymodel)
void tst_QAbstractItemModel::testMoveThroughProxy()
{
QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);
@@ -1257,6 +1262,7 @@ void tst_QAbstractItemModel::testMoveThroughProxy()
moveCommand->setDestRow(0);
moveCommand->doCommand();
}
+#endif
void tst_QAbstractItemModel::testMoveToGrandParent_data()
{
@@ -1804,6 +1810,7 @@ void tst_QAbstractItemModel::testMoveWithinOwnRange()
QCOMPARE(afterSpy.size(), 0);
}
+#if QT_CONFIG(proxymodel)
class ListenerObject : public QObject
{
Q_OBJECT
@@ -1822,7 +1829,7 @@ private:
QList<QPersistentModelIndex> m_persistentIndexes;
QModelIndexList m_nonPersistentIndexes;
};
-
+#endif
class ModelWithCustomRole : public QStringListModel
{
@@ -1836,6 +1843,7 @@ public:
}
};
+#if QT_CONFIG(proxymodel)
ListenerObject::ListenerObject(QAbstractProxyModel *parent)
: QObject(parent), m_model(parent)
{
@@ -1876,7 +1884,9 @@ void ListenerObject::slotReset()
QVERIFY(!idx.isValid());
}
}
+#endif
+#if QT_CONFIG(sortfilterproxymodel)
void tst_QAbstractItemModel::testReset()
{
QSignalSpy beforeResetSpy(m_model, &DynamicTreeModel::modelAboutToBeReset);
@@ -1931,6 +1941,7 @@ void tst_QAbstractItemModel::testReset()
// After being reset the proxy must be queried again.
QCOMPARE(nullProxy->roleNames().value(Qt::UserRole + 1), QByteArray());
}
+#endif
class CustomRoleModel : public QStringListModel
{
diff --git a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp
index 45f7a6c08d..08233a1f7b 100644
--- a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp
+++ b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp
@@ -57,8 +57,10 @@ private slots:
void merge();
void isRowSelected();
void childrenDeselectionSignal();
+#if QT_CONFIG(proxymodel)
void layoutChangedWithAllSelected1();
void layoutChangedWithAllSelected2();
+#endif
void layoutChangedTreeSelection();
void deselectRemovedMiddleRange();
void setModel();
@@ -75,7 +77,9 @@ private slots:
void QTBUG48402();
void QTBUG58851_data();
+#if QT_CONFIG(proxymodel)
void QTBUG58851();
+#endif
void QTBUG18001_data();
void QTBUG18001();
@@ -2260,6 +2264,7 @@ void tst_QItemSelectionModel::childrenDeselectionSignal()
QVERIFY(selectionModel.selection().contains(sel2));
}
+#if QT_CONFIG(proxymodel)
void tst_QItemSelectionModel::layoutChangedWithAllSelected1()
{
QStringListModel model( QStringList() << "foo" << "bar" << "foo2");
@@ -2338,6 +2343,7 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected2()
for (const auto &index : indexList)
QVERIFY(selection.isSelected(index));
}
+#endif
// This test is a regression test for QTBUG-2804.
void tst_QItemSelectionModel::layoutChangedTreeSelection()
@@ -2752,6 +2758,7 @@ void tst_QItemSelectionModel::QTBUG58851_data()
<< IntPair(2, 3));
}
+#if QT_CONFIG(proxymodel)
void tst_QItemSelectionModel::QTBUG58851()
{
using IntPair = std::pair<int, int>;
@@ -2796,6 +2803,7 @@ void tst_QItemSelectionModel::QTBUG58851()
QVERIFY(selections.isSelected(i));
}
}
+#endif
void tst_QItemSelectionModel::QTBUG18001_data()
{
@@ -2973,7 +2981,7 @@ void tst_QItemSelectionModel::destroyModel()
selectionModel->setCurrentIndex(itemModel->index(1, 0), QItemSelectionModel::Select);
QVERIFY(selectionModel->currentIndex().isValid());
- QTest::failOnWarning(QRegularExpression(".*"));
+ QTest::failOnWarning();
itemModel.reset();
QVERIFY(!selectionModel->currentIndex().isValid());
QVERIFY(selectionModel->selection().isEmpty());
diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
index 5a06a4a605..0e027461aa 100644
--- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
+++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
@@ -247,13 +247,16 @@ void tst_QSortFilterProxyModel::sort()
QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
}
- // restore the unsorted order
- m_proxy->sort(-1);
+ // restore the unsorted order in the given order
+ m_proxy->sort(-1, sortOrder);
- // make sure the proxy is unsorted again
+ // make sure the proxy is sorted by source row in the given order
+ int sourceIndex = sortOrder == Qt::AscendingOrder ? 0 : initial.size() - 1;
+ int adjustmentValue = sortOrder == Qt::AscendingOrder ? 1 : -1;
for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
QModelIndex index = m_proxy->index(row, 0, QModelIndex());
- QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(sourceIndex));
+ sourceIndex += adjustmentValue;
}
}
diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
index 0745ea6ceb..8f8ab33e64 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
+++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
@@ -1041,7 +1041,7 @@ void tst_QCoreApplication::addRemoveLibPaths()
static bool theMainThreadIsSet()
{
// QCoreApplicationPrivate::mainThread() has a Q_ASSERT we'd trigger
- return QCoreApplicationPrivate::theMainThread.loadRelaxed() != nullptr;
+ return QCoreApplicationPrivate::theMainThreadId.loadRelaxed() != nullptr;
}
static bool theMainThreadWasUnset = !theMainThreadIsSet(); // global static
@@ -1053,8 +1053,8 @@ void tst_QCoreApplication::theMainThread()
int argc = 1;
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
TestApplication app(argc, argv);
- QVERIFY(QCoreApplicationPrivate::theMainThread.loadRelaxed());
- QCOMPARE(QCoreApplicationPrivate::theMainThread.loadRelaxed(), thread());
+ QVERIFY(QCoreApplicationPrivate::theMainThreadId.loadRelaxed());
+ QVERIFY(QThread::isMainThread());
QCOMPARE(app.thread(), thread());
QCOMPARE(app.thread(), QThread::currentThread());
}
@@ -1067,7 +1067,7 @@ static void createQObjectOnDestruction()
#if !defined(QT_QGUIAPPLICATIONTEST) && !defined(Q_OS_WIN)
// QCoreApplicationData's global static destructor has run and cleaned up
- // the QAdoptedThrad.
+ // the QAdoptedThread.
if (theMainThreadIsSet())
qFatal("theMainThreadIsSet() returned true; some QObject must have leaked");
#endif
diff --git a/tests/auto/corelib/kernel/qelapsedtimer/CMakeLists.txt b/tests/auto/corelib/kernel/qelapsedtimer/CMakeLists.txt
index 9a40a2f905..eccde38df2 100644
--- a/tests/auto/corelib/kernel/qelapsedtimer/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/qelapsedtimer/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qelapsedtimer
SOURCES
tst_qelapsedtimer.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp
index 7623fd2e43..7a2b12b2eb 100644
--- a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp
+++ b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp
@@ -5,6 +5,7 @@
#include <QtCore/QString>
#include <QtCore/QElapsedTimer>
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QTimer>
static const int minResolution = 100; // the minimum resolution for the tests
@@ -22,6 +23,7 @@ class tst_QElapsedTimer : public QObject
Q_OBJECT
private Q_SLOTS:
+ void compareCompiles();
void statics();
void validity();
void basics();
@@ -29,6 +31,11 @@ private Q_SLOTS:
void msecsTo();
};
+void tst_QElapsedTimer::compareCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QElapsedTimer>();
+}
+
void tst_QElapsedTimer::statics()
{
// these have been required since Qt 6.6
@@ -77,6 +84,7 @@ void tst_QElapsedTimer::basics()
QVERIFY(!(t1 < t1));
QCOMPARE(t1.msecsTo(t1), qint64(0));
QCOMPARE(t1.secsTo(t1), qint64(0));
+ QT_TEST_ALL_COMPARISON_OPS(t1, t1, Qt::strong_ordering::equal);
quint64 value1 = t1.msecsSinceReference();
qDebug() << "value1:" << value1 << "t1:" << t1;
@@ -141,10 +149,16 @@ void tst_QElapsedTimer::msecsTo()
QTest::qSleep(minResolution);
QElapsedTimer t2;
t2.start();
-
- QVERIFY(t1 != t2);
- QVERIFY(!(t1 == t2));
- QVERIFY(t1 < t2);
+ QTest::qSleep(minResolution);
+ QElapsedTimer t3;
+ t3.start();
+
+ QT_TEST_EQUALITY_OPS(t1, t2, false);
+ QT_TEST_EQUALITY_OPS(QElapsedTimer(), QElapsedTimer(), true);
+ QT_TEST_EQUALITY_OPS(QElapsedTimer(), t2, false);
+ QT_TEST_ALL_COMPARISON_OPS(t1, t2, Qt::strong_ordering::less);
+ QT_TEST_ALL_COMPARISON_OPS(t3, t2, Qt::strong_ordering::greater);
+ QT_TEST_ALL_COMPARISON_OPS(t3, QElapsedTimer(), Qt::strong_ordering::greater);
auto diff = t1.msecsTo(t2);
QVERIFY2(diff > 0, QString("difference t1 and t2 is %1").arg(diff).toLatin1());
diff --git a/tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt b/tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt
index a9ebcdf72f..fb58aebe73 100644
--- a/tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt
@@ -16,4 +16,5 @@ qt_internal_add_test(tst_qmetacontainer
tst_qmetacontainer.cpp
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp b/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp
index dff2176a11..cc1d8baa8e 100644
--- a/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp
+++ b/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/qtest.h>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QtCore/qcontainerinfo.h>
#include <QtCore/qmetacontainer.h>
#include <QtCore/QMap>
@@ -157,6 +158,7 @@ private:
private slots:
void init();
+ void compareCompiles();
void testSequence_data();
void testSequence();
@@ -203,6 +205,12 @@ void tst_QMetaContainer::init()
};
}
+void tst_QMetaContainer::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QMetaSequence>();
+ QTestPrivate::testEqualityOperatorsCompile<QMetaAssociation>();
+}
+
void tst_QMetaContainer::cleanup()
{
qvector.clear();
@@ -501,6 +509,9 @@ void tst_QMetaContainer::testSequence()
QVERIFY(metaSequence.iface() != nullptr);
QMetaSequence defaultConstructed;
QVERIFY(defaultConstructed.iface() == nullptr);
+ QT_TEST_EQUALITY_OPS(QMetaSequence(), defaultConstructed, true);
+ QT_TEST_EQUALITY_OPS(QMetaSequence(), QMetaSequence(), true);
+ QT_TEST_EQUALITY_OPS(defaultConstructed, metaSequence, false);
}
void tst_QMetaContainer::testAssociation_data()
@@ -728,8 +739,10 @@ void tst_QMetaContainer::testAssociation()
metaAssociation.destroyConstIterator(constEnd);
QVERIFY(metaAssociation.iface() != nullptr);
- QMetaSequence defaultConstructed;
+ QMetaAssociation defaultConstructed;
QVERIFY(defaultConstructed.iface() == nullptr);
+ QT_TEST_EQUALITY_OPS(QMetaAssociation(), QMetaAssociation(), true);
+ QT_TEST_EQUALITY_OPS(QMetaAssociation(), metaAssociation, false);
}
QTEST_MAIN(tst_QMetaContainer)
diff --git a/tests/auto/corelib/kernel/qmetamethod/CMakeLists.txt b/tests/auto/corelib/kernel/qmetamethod/CMakeLists.txt
index 29a6e3c64b..0d46aef8bd 100644
--- a/tests/auto/corelib/kernel/qmetamethod/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/qmetamethod/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qmetamethod
SOURCES
tst_qmetamethod.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
index 47012f9a28..59fb747524 100644
--- a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
+++ b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
@@ -4,6 +4,7 @@
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QTypeRevision>
#include <qobject.h>
@@ -14,6 +15,7 @@ class tst_QMetaMethod : public QObject
Q_OBJECT
private slots:
+ void compareCompiles();
void method_data();
void method();
@@ -166,6 +168,11 @@ QVariant MethodTestObject::qvariantSlotBoolIntUIntLonglongULonglongDoubleLongSho
}
void MethodTestObject::voidSlotNoParameterNames(bool, int) {}
+void tst_QMetaMethod::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QMetaMethod>();
+}
+
void tst_QMetaMethod::method_data()
{
QTest::addColumn<QByteArray>("signature");
@@ -647,6 +654,8 @@ void tst_QMetaMethod::method()
// Bogus indexes
QCOMPARE(method.parameterType(-1), 0);
QCOMPARE(method.parameterType(parameterTypes.size()), 0);
+ QT_TEST_EQUALITY_OPS(method, QMetaMethod(), false);
+ QT_TEST_EQUALITY_OPS(QMetaMethod(), QMetaMethod(), true);
}
void tst_QMetaMethod::invalidMethod()
@@ -659,6 +668,9 @@ void tst_QMetaMethod::invalidMethod()
QMetaMethod method3 = staticMetaObject.method(-1);
QVERIFY(!method3.isValid());
+ QT_TEST_EQUALITY_OPS(method, method2, true);
+ QT_TEST_EQUALITY_OPS(method2, method3, true);
+ QT_TEST_EQUALITY_OPS(method, method3, true);
}
void tst_QMetaMethod::comparisonOperators()
@@ -673,16 +685,9 @@ void tst_QMetaMethod::comparisonOperators()
QMetaMethod other = x ? mo->constructor(j) : mo->method(j);
bool expectedEqual = ((methodMo == other.enclosingMetaObject())
&& (i == j));
- QCOMPARE(method == other, expectedEqual);
- QCOMPARE(method != other, !expectedEqual);
- QCOMPARE(other == method, expectedEqual);
- QCOMPARE(other != method, !expectedEqual);
+ QT_TEST_EQUALITY_OPS(method, other, expectedEqual);
}
-
- QVERIFY(method != QMetaMethod());
- QVERIFY(QMetaMethod() != method);
- QVERIFY(!(method == QMetaMethod()));
- QVERIFY(!(QMetaMethod() == method));
+ QT_TEST_EQUALITY_OPS(method, QMetaMethod(), false);
}
}
@@ -691,8 +696,7 @@ void tst_QMetaMethod::comparisonOperators()
for (int i = 0; i < qMin(mo->methodCount(), mo->constructorCount()); ++i) {
QMetaMethod method = mo->method(i);
QMetaMethod constructor = mo->constructor(i);
- QVERIFY(method != constructor);
- QVERIFY(!(method == constructor));
+ QT_TEST_EQUALITY_OPS(method, constructor, false);
}
}
@@ -748,6 +752,7 @@ void tst_QMetaMethod::gadget()
QMetaMethod getValueMethod = MyGadget::staticMetaObject.method(idx);
QVERIFY(getValueMethod.isValid());
+ QT_TEST_EQUALITY_OPS(setValueMethod, getValueMethod, false);
{
MyGadget gadget;
QString string;
diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
index ee13c32353..182ec6daae 100644
--- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
+++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
@@ -3,11 +3,15 @@
#include <QTest>
#include <QSignalSpy>
+#if QT_CONFIG(sortfilterproxymodel)
#include <QSortFilterProxyModel>
+#endif
#include <qobject.h>
#include <qmetaobject.h>
+#if QT_CONFIG(proxymodel)
#include <qabstractproxymodel.h>
+#endif
#include <private/qmetaobject_p.h>
Q_DECLARE_METATYPE(const QMetaObject *)
@@ -1906,6 +1910,7 @@ void tst_QMetaObject::invokeBlockingQueuedPointer()
void tst_QMetaObject::qtMetaObjectInheritance()
{
QVERIFY(!QObject::staticMetaObject.superClass());
+#if QT_CONFIG(sortfilterproxymodel)
QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("Qt::CaseSensitivity"), -1);
QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("CaseSensitivity"), -1);
int indexOfSortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.indexOfProperty("sortCaseSensitivity");
@@ -1913,6 +1918,7 @@ void tst_QMetaObject::qtMetaObjectInheritance()
QMetaProperty sortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.property(indexOfSortCaseSensitivity);
QVERIFY(sortCaseSensitivity.isValid());
QCOMPARE(sortCaseSensitivity.enumerator().name(), "CaseSensitivity");
+#endif
}
struct MyType
@@ -2515,7 +2521,9 @@ void tst_QMetaObject::metaType()
{
QCOMPARE(QObject::staticMetaObject.metaType(), QMetaType::fromType<QObject>());
QCOMPARE(MyGadget::staticMetaObject.metaType(), QMetaType::fromType<MyGadget>());
+#if QT_CONFIG(proxymodel)
QCOMPARE(QAbstractProxyModel::staticMetaObject.metaType(), QMetaType::fromType<QAbstractProxyModel>());
+#endif
auto qtNameSpaceMetaType = Qt::staticMetaObject.metaType();
QVERIFY2(!qtNameSpaceMetaType.isValid(), qtNameSpaceMetaType.name());
}
diff --git a/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp b/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp
index c8053ca43a..3bf6211a53 100644
--- a/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp
+++ b/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp
@@ -170,11 +170,55 @@ public:
{}
};
+enum FreeEnum {
+ FreeEnumValue1,
+ FreeEnumValue2
+};
+
+namespace MySpace {
+ enum NamespacedEnum {
+ NamespacedEnumValue1,
+ NamespacedEnumValue2
+ };
+};
+
+namespace MyQtSpace {
+ Q_NAMESPACE
+ enum NamespacedEnum {
+ NamespacedEnumValue1,
+ NamespacedEnumValue2
+ };
+ Q_DECLARE_FLAGS(NamespacedFlags, NamespacedEnum)
+ Q_FLAG_NS(NamespacedFlags)
+};
+
+namespace SeparateEnumNamespace {
+ Q_NAMESPACE
+ enum Enum {
+ Value1,
+ Value2
+ };
+ Q_ENUM_NS(Enum)
+};
+namespace SeparateFlagsNamespace {
+ Q_NAMESPACE
+ Q_DECLARE_FLAGS(Flags, SeparateEnumNamespace::Enum)
+ Q_FLAG_NS(Flags)
+}
+
class EnumFlagsTester : public QObject
{
Q_OBJECT
Q_PROPERTY(TestEnum enumProperty READ enumProperty WRITE setEnumProperty)
Q_PROPERTY(TestFlags flagProperty READ flagProperty WRITE setFlagProperty)
+
+ Q_PROPERTY(FreeEnum freeEnumProperty READ freeEnumProperty WRITE setFreeEnumProperty)
+ Q_PROPERTY(MySpace::NamespacedEnum namespacedEnumProperty READ namespacedEnumProperty WRITE setNamespacedEnumProperty)
+ Q_PROPERTY(MyQtSpace::NamespacedEnum qtNamespacedEnumProperty READ qtNamespacedEnumProperty WRITE setQtNamespacedEnumProperty)
+ Q_PROPERTY(MyQtSpace::NamespacedFlags qtNamespacedFlagProperty READ qtNamespacedFlagProperty WRITE setQtNamespacedFlagProperty)
+
+ Q_PROPERTY(SeparateEnumNamespace::Enum sepEnum READ sepEnum WRITE setSepEnum)
+ Q_PROPERTY(SeparateFlagsNamespace::Flags sepFlags READ sepFlags WRITE setSepFlags)
public:
enum TestEnum { e1, e2 };
Q_ENUM(TestEnum)
@@ -190,9 +234,35 @@ public:
TestFlags flagProperty() const { return m_flags; }
void setFlagProperty(TestFlags f) { m_flags = f; }
+ FreeEnum freeEnumProperty() const { return m_freeEnum; }
+ void setFreeEnumProperty(FreeEnum e) { m_freeEnum = e; }
+
+ MySpace::NamespacedEnum namespacedEnumProperty() const { return m_namespacedEnum; }
+ void setNamespacedEnumProperty(MySpace::NamespacedEnum e) { m_namespacedEnum = e; }
+
+ MyQtSpace::NamespacedEnum qtNamespacedEnumProperty() const { return m_qtNamespaceEnum; }
+ void setQtNamespacedEnumProperty(MyQtSpace::NamespacedEnum e) { m_qtNamespaceEnum = e; }
+
+ MyQtSpace::NamespacedFlags qtNamespacedFlagProperty() const { return m_qtNamespaceFlags; }
+ void setQtNamespacedFlagProperty(MyQtSpace::NamespacedFlags f) { m_qtNamespaceFlags = f; }
+
+ SeparateEnumNamespace::Enum sepEnum() const { return m_sepEnum; }
+ void setSepEnum(SeparateEnumNamespace::Enum e) { m_sepEnum = e; }
+
+ SeparateFlagsNamespace::Flags sepFlags() const { return m_sepFlags; }
+ void setSepFlags(SeparateFlagsNamespace::Flags f) { m_sepFlags = f; }
+
private:
TestEnum m_enum = e1;
TestFlags m_flags;
+
+ FreeEnum m_freeEnum = FreeEnum::FreeEnumValue1;
+ MySpace::NamespacedEnum m_namespacedEnum = MySpace::NamespacedEnumValue1;
+ MyQtSpace::NamespacedEnum m_qtNamespaceEnum = MyQtSpace::NamespacedEnumValue1;
+ MyQtSpace::NamespacedFlags m_qtNamespaceFlags;
+
+ SeparateEnumNamespace::Enum m_sepEnum = SeparateEnumNamespace::Value1;
+ SeparateFlagsNamespace::Flags m_sepFlags;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(EnumFlagsTester::TestFlags)
@@ -265,7 +335,7 @@ void tst_QMetaProperty::conversion()
void tst_QMetaProperty::enumsFlags()
{
// QTBUG-83689, verify that enumerations and flags can be assigned from int,
- // which is important for Qt Designer.
+ // which is important for Qt Widgets Designer.
EnumFlagsTester t;
auto mo = t.metaObject();
@@ -276,6 +346,7 @@ void tst_QMetaProperty::enumsFlags()
QVERIFY(enumProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
QVERIFY(enumProperty.write(&t, QVariant(int(EnumFlagsTester::e2))));
QCOMPARE(t.enumProperty(), EnumFlagsTester::e2);
+ QVERIFY(enumProperty.enumerator().isValid()); // OK: Q_ENUM
const int flagsIndex = mo->indexOfProperty("flagProperty");
QVERIFY(flagsIndex >= 0);
@@ -283,6 +354,55 @@ void tst_QMetaProperty::enumsFlags()
QVERIFY(flagsProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
QVERIFY(flagsProperty.write(&t, QVariant(int(EnumFlagsTester::flag2))));
QCOMPARE(t.flagProperty(), EnumFlagsTester::flag2);
+ QVERIFY(!flagsProperty.enumerator().isValid()); // Not using Q_FLAG
+
+ const int freeEnumIndex = mo->indexOfProperty("freeEnumProperty");
+ QVERIFY(freeEnumIndex >= 0);
+ auto freeEnumProperty = mo->property(freeEnumIndex);
+ QVERIFY(freeEnumProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
+ QVERIFY(freeEnumProperty.write(&t, QVariant(FreeEnumValue2)));
+ QCOMPARE(t.freeEnumProperty(), FreeEnumValue2);
+ QVERIFY(!freeEnumProperty.enumerator().isValid()); // Not using Q_ENUM
+
+ const int namespacedEnumIndex = mo->indexOfProperty("namespacedEnumProperty");
+ QVERIFY(namespacedEnumIndex >= 0);
+ auto namespacedEnumProperty = mo->property(namespacedEnumIndex);
+ QVERIFY(namespacedEnumProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
+ QVERIFY(namespacedEnumProperty.write(&t, QVariant(MySpace::NamespacedEnumValue2)));
+ QCOMPARE(t.namespacedEnumProperty(), MySpace::NamespacedEnumValue2);
+ QVERIFY(!namespacedEnumProperty.enumerator().isValid()); // Not using Q_NAMESPACE/Q_ENUM_NS
+
+ const int qtNamespacedEnumIndex = mo->indexOfProperty("qtNamespacedEnumProperty");
+ QVERIFY(qtNamespacedEnumIndex >= 0);
+ auto qtNamespacedEnumProperty = mo->property(qtNamespacedEnumIndex);
+ QVERIFY(qtNamespacedEnumProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
+ QVERIFY(qtNamespacedEnumProperty.write(&t, QVariant(MyQtSpace::NamespacedEnumValue2)));
+ QCOMPARE(t.qtNamespacedEnumProperty(), MyQtSpace::NamespacedEnumValue2);
+ QVERIFY(qtNamespacedEnumProperty.enumerator().isValid()); // OK: Q_ENUM_NS
+
+ const int qtNamespacedFlagIndex = mo->indexOfProperty("qtNamespacedFlagProperty");
+ QVERIFY(qtNamespacedFlagIndex >= 0);
+ auto qtNamespacedFlagProperty = mo->property(qtNamespacedFlagIndex);
+ QVERIFY(qtNamespacedFlagProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
+ QVERIFY(qtNamespacedFlagProperty.write(&t, QVariant(MyQtSpace::NamespacedFlags(MyQtSpace::NamespacedEnumValue2))));
+ QCOMPARE(t.qtNamespacedFlagProperty(), MyQtSpace::NamespacedFlags(MyQtSpace::NamespacedEnumValue2));
+ QVERIFY(qtNamespacedFlagProperty.enumerator().isValid()); // OK: Q_FLAG
+
+ const int sepEnumIndex = mo->indexOfProperty("sepEnum");
+ QVERIFY(sepEnumIndex >= 0);
+ auto sepEnumProperty = mo->property(sepEnumIndex);
+ QVERIFY(sepEnumProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
+ QVERIFY(sepEnumProperty.write(&t, QVariant(SeparateEnumNamespace::Value2)));
+ QCOMPARE(t.sepEnum(), SeparateEnumNamespace::Value2);
+ QVERIFY(sepEnumProperty.enumerator().isValid()); // OK: Q_ENUM_NS
+
+ const int sepFlagsIndex = mo->indexOfProperty("sepFlags");
+ QVERIFY(sepFlagsIndex >= 0);
+ auto sepFlagsProperty = mo->property(sepFlagsIndex);
+ QVERIFY(sepFlagsProperty.metaType().flags().testFlag(QMetaType::IsEnumeration));
+ QVERIFY(sepFlagsProperty.write(&t, QVariant(SeparateEnumNamespace::Value1)));
+ QCOMPARE(t.sepFlags(), SeparateEnumNamespace::Value1);
+ QVERIFY(!sepFlagsProperty.enumerator().isValid()); // NOK: the meta object is empty
}
diff --git a/tests/auto/corelib/kernel/qmetatype/CMakeLists.txt b/tests/auto/corelib/kernel/qmetatype/CMakeLists.txt
index b93d961109..65bec3e187 100644
--- a/tests/auto/corelib/kernel/qmetatype/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/qmetatype/CMakeLists.txt
@@ -51,6 +51,7 @@ qt_internal_add_test(tst_qmetatype
../../../other/qvariant_common
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
Qt::Gui
qmetatype_lib1
qmetatype_lib2
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h
index 1694e49491..bcd2fe2def 100644
--- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h
+++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h
@@ -111,6 +111,7 @@ private slots:
void customDebugStream();
void unknownType();
void fromType();
+ void compareCompiles();
void operatorEq_data();
void operatorEq();
void operatorEq2_data();
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp
index 68bcb53056..661c1f6072 100644
--- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp
+++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp
@@ -5,6 +5,7 @@
#include "tst_qmetatype_libs.h"
#include <QtCore/private/qmetaobjectbuilder_p.h>
+#include <QtTest/private/qcomparisontesthelper_p.h>
void tst_QMetaType::constRefs()
{
@@ -418,6 +419,11 @@ struct CharTemplate
} y;
};
+void tst_QMetaType::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QMetaType>();
+}
+
void tst_QMetaType::operatorEq_data()
{
QTest::addColumn<QMetaType>("typeA");
@@ -447,10 +453,7 @@ void tst_QMetaType::operatorEq()
QFETCH(QMetaType, typeB);
QFETCH(bool, eq);
- QCOMPARE(typeA == typeB, eq);
- QCOMPARE(typeB == typeA, eq);
- QCOMPARE(typeA != typeB, !eq);
- QCOMPARE(typeB != typeA, !eq);
+ QT_TEST_EQUALITY_OPS(typeA, typeB, eq);
#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
// for built-in types or locally-defined types, this must also hold true
@@ -487,10 +490,10 @@ FOR_EACH_CORE_METATYPE(GET_METATYPE_FROM_TYPE)
QCOMPARE(fromId2.id(), type);
// confirm that they're all equal
- QCOMPARE(fromId1, fromId2);
- QCOMPARE(fromType1, fromType2);
- QCOMPARE(fromType1, fromId1);
- QCOMPARE(fromType2, fromId2);
+ QT_TEST_EQUALITY_OPS(fromId1, fromId2, true);
+ QT_TEST_EQUALITY_OPS(fromType1, fromType2, true);
+ QT_TEST_EQUALITY_OPS(fromType1, fromId1, true);
+ QT_TEST_EQUALITY_OPS(fromType2, fromId2, true);
#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
// for built-in types (other than void), this must be true
@@ -541,7 +544,7 @@ void tst_QMetaType::operatorEqAcrossLibs()
// DO THIS FIRST:
// if this isn't a built-in type, then the QMetaTypeInterface::typeId is
// initially set to 0
- QCOMPARE(lib1Type, lib2Type);
+ QT_TEST_EQUALITY_OPS(lib1Type, lib2Type, true);
int actualTypeId = localType.id();
bool builtinTypeExpected = builtinTypeId != QMetaType::UnknownType;
@@ -559,8 +562,8 @@ void tst_QMetaType::operatorEqAcrossLibs()
QCOMPARE(lib2Type.id(), actualTypeId);
QCOMPARE(QByteArray(lib1Type.name()), QByteArray(localType.name()));
QCOMPARE(QByteArray(lib2Type.name()), QByteArray(localType.name()));
- QCOMPARE(lib1Type, localType);
- QCOMPARE(lib2Type, localType);
+ QT_TEST_EQUALITY_OPS(lib1Type, localType, true);
+ QT_TEST_EQUALITY_OPS(lib2Type, localType, true);
#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
if (actualTypeId < QMetaType::FirstGuiType && actualTypeId != QMetaType::Void) {
diff --git a/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp b/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp
index c9c8734353..e28a2e98cc 100644
--- a/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp
+++ b/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp
@@ -85,6 +85,14 @@ void tst_QMimeData::data() const
QCOMPARE(mimeData.data("text/markdown"), QByteArray("vikings"));
QCOMPARE(mimeData.data("text/html"), QByteArray("ninjas"));
QCOMPARE(mimeData.data("text/plain"), QByteArray("pirates"));
+
+ // URI list
+ QByteArray list = "https://example.com/\r\nhttps://example.net/\r\nhttps://example.org/\r\n";
+ mimeData.setData("text/uri-list", list);
+ QCOMPARE(mimeData.data("text/uri-list"), list);
+
+ mimeData.setData("text/uri-list", list.chopped(2)); // without the ending CRLF
+ QCOMPARE(mimeData.data("text/uri-list"), list);
}
void tst_QMimeData::formats() const
diff --git a/tests/auto/corelib/mimetypes/qmimetype/CMakeLists.txt b/tests/auto/corelib/mimetypes/qmimetype/CMakeLists.txt
index e1781d450e..605cdccc3f 100644
--- a/tests/auto/corelib/mimetypes/qmimetype/CMakeLists.txt
+++ b/tests/auto/corelib/mimetypes/qmimetype/CMakeLists.txt
@@ -16,4 +16,5 @@ qt_internal_add_test(tst_qmimetype
tst_qmimetype.cpp
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp b/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp
index 79304e4420..b96e8feffa 100644
--- a/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp
+++ b/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp
@@ -8,7 +8,7 @@
#include <QVariantMap>
#include <QTest>
-
+#include <QtTest/private/qcomparisontesthelper_p.h>
class tst_qmimetype : public QObject
{
@@ -17,7 +17,9 @@ class tst_qmimetype : public QObject
private slots:
void initTestCase();
+ void compareCompiles();
void isValid();
+ void compareQMimetypes();
void name();
void genericIconName();
void iconName();
@@ -41,6 +43,28 @@ static QString qMimeTypeName()
// ------------------------------------------------------------------------------------------------
+void tst_qmimetype::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QMimeType>();
+}
+
+// ------------------------------------------------------------------------------------------------
+
+void tst_qmimetype::compareQMimetypes()
+{
+ QMimeType instantiatedQMimeType{ QMimeTypePrivate(qMimeTypeName()) };
+ QMimeType otherQMimeType (instantiatedQMimeType);
+ QMimeType defaultQMimeType;
+
+ QVERIFY(!defaultQMimeType.isValid());
+ QT_TEST_EQUALITY_OPS(defaultQMimeType, QMimeType(), true);
+ QT_TEST_EQUALITY_OPS(QMimeType(), QMimeType(), true);
+ QT_TEST_EQUALITY_OPS(instantiatedQMimeType, QMimeType(), false);
+ QT_TEST_EQUALITY_OPS(otherQMimeType, defaultQMimeType, false);
+}
+
+// ------------------------------------------------------------------------------------------------
+
void tst_qmimetype::isValid()
{
QMimeType instantiatedQMimeType{ QMimeTypePrivate(qMimeTypeName()) };
@@ -49,7 +73,7 @@ void tst_qmimetype::isValid()
QMimeType otherQMimeType (instantiatedQMimeType);
QVERIFY(otherQMimeType.isValid());
- QCOMPARE(instantiatedQMimeType, otherQMimeType);
+ QT_TEST_EQUALITY_OPS(instantiatedQMimeType, otherQMimeType, true);
QMimeType defaultQMimeType;
@@ -66,8 +90,7 @@ void tst_qmimetype::name()
// Verify that the Name is part of the equality test:
QCOMPARE(instantiatedQMimeType.name(), qMimeTypeName());
- QVERIFY(instantiatedQMimeType != otherQMimeType);
- QVERIFY(!(instantiatedQMimeType == otherQMimeType));
+ QT_TEST_EQUALITY_OPS(instantiatedQMimeType, otherQMimeType, false);
}
// ------------------------------------------------------------------------------------------------
diff --git a/tests/auto/corelib/platform/android/tst_android.cpp b/tests/auto/corelib/platform/android/tst_android.cpp
index 07b939969c..76811a31ad 100644
--- a/tests/auto/corelib/platform/android/tst_android.cpp
+++ b/tests/auto/corelib/platform/android/tst_android.cpp
@@ -353,6 +353,9 @@ void tst_Android::orientationChange()
QFETCH(Qt::ScreenOrientation, expected);
QFETCH(QSize, screenSize);
+ if (QNativeInterface::QAndroidApplication::sdkVersion() == __ANDROID_API_P__)
+ QSKIP("Android 9 orientation changes callbacks are buggy (QTBUG-124890).");
+
// For QTBUG-94459 to check that the widget size are consistent after orientation changes
QWidget widget;
widget.show();
diff --git a/tests/auto/corelib/platform/windows/qcomobject/tst_qcomobject.cpp b/tests/auto/corelib/platform/windows/qcomobject/tst_qcomobject.cpp
index 5ad961ee66..3c609238fc 100644
--- a/tests/auto/corelib/platform/windows/qcomobject/tst_qcomobject.cpp
+++ b/tests/auto/corelib/platform/windows/qcomobject/tst_qcomobject.cpp
@@ -69,6 +69,7 @@ struct QComObjectTraits<IDirect>
};
} // namespace QtPrivate
+QT_END_NAMESPACE
class tst_QComObject : public QObject
{
@@ -263,6 +264,4 @@ void tst_QComObject::Release_decrementsReferenceCountByOne()
QTEST_MAIN(tst_QComObject)
# include "tst_qcomobject.moc"
-QT_END_NAMESPACE
-
#endif // Q_OS_WIN
diff --git a/tests/auto/corelib/serialization/CMakeLists.txt b/tests/auto/corelib/serialization/CMakeLists.txt
index 3792336255..45965114cc 100644
--- a/tests/auto/corelib/serialization/CMakeLists.txt
+++ b/tests/auto/corelib/serialization/CMakeLists.txt
@@ -3,7 +3,9 @@
add_subdirectory(json)
add_subdirectory(qcborstreamreader)
-add_subdirectory(qcborstreamwriter)
+if(QT_FEATURE_cborstreamwriter)
+ add_subdirectory(qcborstreamwriter)
+endif()
if(NOT WASM)
add_subdirectory(qcborvalue)
endif()
diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
index 23b25834b9..e480b033e1 100644
--- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
+++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
@@ -7,7 +7,9 @@
#include <QBuffer>
#include <QCborStreamReader>
+#if QT_CONFIG(cborstreamwriter)
#include <QCborStreamWriter>
+#endif
#include <QDateTime>
#include <QtEndian>
#include <QTimeZone>
@@ -86,9 +88,11 @@ private slots:
void comparisonMap();
void toCbor_data();
+#if QT_CONFIG(cborstreamwriter)
void toCbor();
void toCborStreamWriter_data() { toCbor_data(); }
void toCborStreamWriter();
+#endif
void fromCbor_data();
void fromCbor();
void fromCborStreamReaderByteArray_data() { fromCbor_data(); }
@@ -2311,6 +2315,7 @@ void tst_QCborValue::toCbor_data()
QTest::newRow("UseInteger:-2^65") << QCborValue(-2 * 18446744073709551616.0) << raw("\xfb\xc4\0\0\0""\0\0\0\0") << QCborValue::EncodingOptions(QCborValue::UseIntegers);
}
+#if QT_CONFIG(cborstreamwriter)
void tst_QCborValue::toCbor()
{
QFETCH(QCborValue, v);
@@ -2350,6 +2355,7 @@ void tst_QCborValue::toCborStreamWriter()
QCOMPARE(buffer.pos(), result.size());
QCOMPARE(output, result);
}
+#endif
void tst_QCborValue::fromCbor_data()
{
@@ -2667,12 +2673,14 @@ void tst_QCborValue::extendedTypeValidation()
QCOMPARE(error.offset, data.size());
QT_TEST_EQUALITY_OPS(decoded, expected, true);
+#if QT_CONFIG(cborstreamwriter)
QByteArray encoded = decoded.toCbor();
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
// behavior change, see qdatetime.cpp:fromIsoTimeString
QEXPECT_FAIL("DateTime:Null-at-19", "QDateTime parsing fixed, but only in 6.0", Abort);
#endif
QCOMPARE(encoded, data);
+#endif
}
void tst_QCborValue::hugeDeviceValidation_data()
@@ -3000,7 +3008,9 @@ template <typename ValueRef> static void cborValueRef_template()
else
QCOMPARE(ref.toVariant(), v.toVariant());
QCOMPARE(ref.toJsonValue(), v.toJsonValue());
+#if QT_CONFIG(cborstreamwriter)
QCOMPARE(ref.toCbor(), v.toCbor());
+#endif
QCOMPARE(ref.toDiagnosticNotation(), v.toDiagnosticNotation());
}
@@ -3160,6 +3170,7 @@ void tst_QCborValue::datastreamSerialization_data()
void tst_QCborValue::datastreamSerialization()
{
+#if QT_CONFIG(cborstreamwriter)
QFETCH(QCborValue, v);
QByteArray buffer;
{
@@ -3187,6 +3198,7 @@ void tst_QCborValue::datastreamSerialization()
load >> output;
QCOMPARE(output, map);
}
+#endif
}
void tst_QCborValue::streamVariantSerialization()
diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
index 77ca884897..9a227c782d 100644
--- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
@@ -143,9 +143,11 @@ private slots:
void stream_QJsonObject();
void stream_QJsonValue();
+#if QT_CONFIG(cborstreamwriter)
void stream_QCborArray();
void stream_QCborMap();
void stream_QCborValue();
+#endif
void setVersion_data();
void setVersion();
@@ -2326,6 +2328,7 @@ void tst_QDataStream::stream_QJsonValue()
}
}
+#if QT_CONFIG(cborstreamwriter)
void tst_QDataStream::stream_QCborArray()
{
QByteArray buffer;
@@ -2361,6 +2364,7 @@ void tst_QDataStream::stream_QCborValue()
load >> valueLoad;
QCOMPARE(valueLoad, valueSave);
}
+#endif
void tst_QDataStream::setVersion_data()
{
@@ -3254,11 +3258,13 @@ void tst_QDataStream::streamRealDataTypes()
// Generate QPicture from pixmap.
QPixmap pm(open_xpm);
QVERIFY(!pm.isNull());
+#ifndef QT_NO_PICTURE
QPicture picture;
picture.setBoundingRect(QRect(QPoint(0, 0), pm.size()));
QPainter painter(&picture);
painter.drawPixmap(0, 0, pm);
painter.end();
+#endif
// Generate path
QPainterPath path;
@@ -3296,7 +3302,9 @@ void tst_QDataStream::streamRealDataTypes()
stream << QPointF(3, 5) << QRectF(-1, -2, 3, 4) << (QPolygonF() << QPointF(0, 0) << QPointF(1, 2));
stream << QTransform().rotate(90).scale(2, 2).asAffineMatrix();
stream << path;
+#ifndef QT_NO_PICTURE
stream << picture;
+#endif
stream << QTextLength(QTextLength::VariableLength, 1.5);
stream << color;
stream << radialBrush << conicalBrush;
@@ -3310,7 +3318,9 @@ void tst_QDataStream::streamRealDataTypes()
QPolygonF polygon {{3, 4}, {5, 6}};
QTransform transform;
QPainterPath p = otherPath;
+#ifndef QT_NO_PICTURE
QPicture pict;
+#endif
QTextLength textLength(QTextLength::FixedLength, 2.5);
QColor col(128, 128, 127);
QBrush rGrad(Qt::CrossPattern);
@@ -3363,6 +3373,7 @@ void tst_QDataStream::streamRealDataTypes()
QCOMPARE(transform, QTransform().rotate(90).scale(2, 2));
stream >> p;
QCOMPARE(p, path);
+#ifndef QT_NO_PICTURE
if (i == 1) {
stream >> pict;
@@ -3376,6 +3387,7 @@ void tst_QDataStream::streamRealDataTypes()
QCOMPARE(pictA, pictB);
}
+#endif
stream >> textLength;
QCOMPARE(textLength, QTextLength(QTextLength::VariableLength, 1.5));
stream >> col;
diff --git a/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp b/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp
index 82e12bdfca..ba098fd23c 100644
--- a/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp
+++ b/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp
@@ -25,6 +25,7 @@ class tst_QLatin1StringMatcher : public QObject
private slots:
void overloads();
void staticOverloads();
+ void staticOverloads_QStringViewHaystack();
void interface();
void indexIn();
void haystacksWithMoreThan4GiBWork();
@@ -44,6 +45,12 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("Hellohello"_L1), 5);
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1, 1), -1);
+
+ QCOMPARE(m.indexIn(u"hello"), 0);
+ QCOMPARE(m.indexIn(u"Hello"), -1);
+ QCOMPARE(m.indexIn(u"Hellohello"), 5);
+ QCOMPARE(m.indexIn(u"helloHello"), 0);
+ QCOMPARE(m.indexIn(u"helloHello", 1), -1);
}
{
QLatin1StringMatcher m("Hello"_L1, Qt::CaseSensitive);
@@ -53,6 +60,12 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("Hellohello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1), 5);
QCOMPARE(m.indexIn("helloHello"_L1, 6), -1);
+
+ QCOMPARE(m.indexIn(u"hello"), -1);
+ QCOMPARE(m.indexIn(u"Hello"), 0);
+ QCOMPARE(m.indexIn(u"Hellohello"), 0);
+ QCOMPARE(m.indexIn(u"helloHello"), 5);
+ QCOMPARE(m.indexIn(u"helloHello", 6), -1);
}
{
QLatin1StringMatcher m("hello"_L1, Qt::CaseInsensitive);
@@ -63,6 +76,13 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1, 1), 5);
QCOMPARE(m.indexIn("helloHello"_L1, 6), -1);
+
+ QCOMPARE(m.indexIn(u"hello"), 0);
+ QCOMPARE(m.indexIn(u"Hello"), 0);
+ QCOMPARE(m.indexIn(u"Hellohello"), 0);
+ QCOMPARE(m.indexIn(u"helloHello"), 0);
+ QCOMPARE(m.indexIn(u"helloHello", 1), 5);
+ QCOMPARE(m.indexIn(u"helloHello", 6), -1);
}
{
QLatin1StringMatcher m("Hello"_L1, Qt::CaseInsensitive);
@@ -73,6 +93,13 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1, 1), 5);
QCOMPARE(m.indexIn("helloHello"_L1, 6), -1);
+
+ QCOMPARE(m.indexIn(u"hello"), 0);
+ QCOMPARE(m.indexIn(u"Hello"), 0);
+ QCOMPARE(m.indexIn(u"Hellohello"), 0);
+ QCOMPARE(m.indexIn(u"helloHello"), 0);
+ QCOMPARE(m.indexIn(u"helloHello", 1), 5);
+ QCOMPARE(m.indexIn(u"helloHello", 6), -1);
}
{
QLatin1StringMatcher m(hello, Qt::CaseSensitive);
@@ -81,6 +108,11 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn(hello, 1), -1);
QCOMPARE(m.indexIn(hello2, 1), hello.size());
QCOMPARE(m.indexIn(hello2, 6), -1);
+
+ QCOMPARE(m.indexIn(QString::fromLatin1(hello)), 0);
+ QCOMPARE(m.indexIn(QString::fromLatin1(hello), 1), -1);
+ QCOMPARE(m.indexIn(QString::fromLatin1(hello2), 1), hello.size());
+ QCOMPARE(m.indexIn(QString::fromLatin1(hello2), 6), -1);
}
}
@@ -206,6 +238,129 @@ void tst_QLatin1StringMatcher::staticOverloads()
#endif
}
+void tst_QLatin1StringMatcher::staticOverloads_QStringViewHaystack()
+{
+#ifdef QT_STATIC_BOYER_MOORE_NOT_SUPPORTED
+ QSKIP("Test is only valid on an OS that supports static latin1 string matcher");
+#else
+ constexpr QStringView hello = u"hello";
+ QString hello2B = QStringView(hello).toString().repeated(2);
+ hello2B += QStringView(u"🍉");
+ QStringView hello2(hello2B);
+ {
+ static constexpr auto m = qMakeStaticCaseSensitiveLatin1StringMatcher("hel");
+ QCOMPARE(m.indexIn(QStringView(u"hello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"Hello🍉")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"Hellohello🍉")), 5);
+ QCOMPARE(m.indexIn(QStringView(u"helloHello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"he🍉")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"hel🍉")), 0);
+ QCOMPARE(m.indexIn(hello), 0);
+ QCOMPARE(m.indexIn(hello, 1), -1); // from is 1
+ QCOMPARE(m.indexIn(hello2, 2), hello.size()); // from is 2
+ QCOMPARE(m.indexIn(hello2, 3), hello.size()); // from is 3
+ QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
+ static_assert(m.indexIn(QStringView(u"hello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"Hello🍉")) == -1);
+ static_assert(m.indexIn(QStringView(u"Hellohello🍉")) == 5);
+ static_assert(m.indexIn(QStringView(u"helloHello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"he🍉")) == -1);
+ static_assert(m.indexIn(QStringView(u"hel🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 2) == 5); // from is 2
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 3) == 5); // from is 3
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 6) == -1); // from is 6
+ }
+ {
+ static constexpr auto m = qMakeStaticCaseSensitiveLatin1StringMatcher("Hel");
+ QCOMPARE(m.indexIn(QStringView(u"hello🍉")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"Hello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"Hellohello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"helloHello🍉")), 5);
+ QCOMPARE(m.indexIn(QStringView(u"helloHello🍉"), 6), -1);
+ QCOMPARE(m.indexIn(QStringView(u"He🍉")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"Hel🍉")), 0);
+ QCOMPARE(m.indexIn(hello), -1);
+ QCOMPARE(m.indexIn(hello2, 2), -1); // from is 2
+ QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
+ static_assert(m.indexIn(QStringView(u"hello🍉")) == -1);
+ static_assert(m.indexIn(QStringView(u"Hello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"Hellohello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"helloHello🍉")) == 5);
+ static_assert(m.indexIn(QStringView(u"helloHello🍉"), 6) == -1);
+ static_assert(m.indexIn(QStringView(u"He🍉")) == -1);
+ static_assert(m.indexIn(QStringView(u"Hel🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 2) == -1); // from is 2
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 6) == -1); // from is 6
+ }
+ {
+ static constexpr auto m = qMakeStaticCaseInsensitiveLatin1StringMatcher("hel");
+ QCOMPARE(m.indexIn(QStringView(u"hello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"Hello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"Hellohello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"helloHello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"he🍉")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"hel🍉")), 0);
+ QCOMPARE(m.indexIn(hello), 0);
+ QCOMPARE(m.indexIn(hello, 1), -1);
+ QCOMPARE(m.indexIn(hello2, 2), hello.size()); // from is 2
+ QCOMPARE(m.indexIn(hello2, 3), hello.size()); // from is 3
+ QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
+ static_assert(m.indexIn(QStringView(u"hello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"Hello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"Hellohello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"helloHello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"he🍉")) == -1);
+ static_assert(m.indexIn(QStringView(u"hel🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 2) == 5); // from is 2
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 3) == 5); // from is 3
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 6) == -1); // from is 6
+ }
+ {
+ static constexpr auto m = qMakeStaticCaseInsensitiveLatin1StringMatcher("Hel");
+ QCOMPARE(m.indexIn(QStringView(u"hello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"Hello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"Hellohello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"helloHello🍉")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"he🍉")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"hel🍉")), 0);
+ QCOMPARE(m.indexIn(hello), 0);
+ QCOMPARE(m.indexIn(hello, 1), -1);
+ QCOMPARE(m.indexIn(hello2, 2), hello.size()); // from is 2
+ QCOMPARE(m.indexIn(hello2, 3), hello.size()); // from is 3
+ QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
+ static_assert(m.indexIn(QStringView(u"hello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"Hello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"Hellohello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"helloHello🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"he🍉")) == -1);
+ static_assert(m.indexIn(QStringView(u"hel🍉")) == 0);
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 2) == 5); // from is 2
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 3) == 5); // from is 3
+ static_assert(m.indexIn(QStringView(u"hellohello🍉"), 6) == -1); // from is 6
+ }
+ {
+ static constexpr auto m = qMakeStaticCaseInsensitiveLatin1StringMatcher("b\xF8");
+ QCOMPARE(m.indexIn(QStringView(u"B\xD8")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"B\xF8")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"b\xD8")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"b\xF8")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"b\xF8lle")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"m\xF8lle")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"Si b\xF8")), 3);
+ }
+ {
+ static constexpr auto m = qMakeStaticCaseSensitiveLatin1StringMatcher("b\xF8");
+ QCOMPARE(m.indexIn(QStringView(u"B\xD8")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"B\xF8")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"b\xD8")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"b\xF8")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"b\xF8lle")), 0);
+ QCOMPARE(m.indexIn(QStringView(u"m\xF8lle")), -1);
+ QCOMPARE(m.indexIn(QStringView(u"Si b\xF8")), 3);
+ }
+#endif
+}
+
void tst_QLatin1StringMatcher::interface()
{
QLatin1StringView needle = "abc123"_L1;
@@ -387,25 +542,35 @@ void tst_QLatin1StringMatcher::haystacksWithMoreThan4GiBWork()
QCOMPARE(large.size(), BaseSize + needle.size());
qDebug("created dataset in %lld ms", timer.elapsed());
- using MaybeThread = std::thread;
-
- //
- // WHEN: trying to match an occurrence past the 4GiB mark
- //
-
- qsizetype dynamicResult;
-
- auto t = MaybeThread{ [&] {
- QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive);
- dynamicResult = m.indexIn(QLatin1StringView(large));
- } };
- t.join();
+ {
+ //
+ // WHEN: trying to match an occurrence past the 4GiB mark
+ //
+ qsizetype dynamicResult;
+ auto t = std::thread{ [&] {
+ QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive);
+ dynamicResult = m.indexIn(QLatin1StringView(large));
+ } };
+ t.join();
+
+ //
+ // THEN: the result index is not truncated
+ //
+
+ QCOMPARE(dynamicResult, qsizetype(BaseSize));
+ }
- //
- // THEN: the result index is not trucated
- //
+ {
+ qsizetype dynamicResult;
+ auto t = std::thread{ [&] {
+ QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive);
+ dynamicResult = m.indexIn(QStringView(QString::fromLatin1(large)));
+ } };
+ t.join();
+
+ QCOMPARE(dynamicResult, qsizetype(BaseSize));
+ }
- QCOMPARE(dynamicResult, qsizetype(BaseSize));
#else
QSKIP("This test is 64-bit only.");
#endif
diff --git a/tests/auto/corelib/text/qlocale/CMakeLists.txt b/tests/auto/corelib/text/qlocale/CMakeLists.txt
index 3e6693d12b..a91dd44ea5 100644
--- a/tests/auto/corelib/text/qlocale/CMakeLists.txt
+++ b/tests/auto/corelib/text/qlocale/CMakeLists.txt
@@ -8,4 +8,6 @@ if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
endif()
add_subdirectory(test)
-add_subdirectory(syslocaleapp)
+if(QT_FEATURE_jalalicalendar)
+ add_subdirectory(syslocaleapp)
+endif()
diff --git a/tests/auto/corelib/text/qlocale/test/CMakeLists.txt b/tests/auto/corelib/text/qlocale/test/CMakeLists.txt
index 54ab71ea81..fc3e1488cd 100644
--- a/tests/auto/corelib/text/qlocale/test/CMakeLists.txt
+++ b/tests/auto/corelib/text/qlocale/test/CMakeLists.txt
@@ -11,6 +11,7 @@ qt_internal_add_test(tst_qlocale
../tst_qlocale.cpp
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
## Scopes:
diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
index 946a7e6821..eb2d73b9b2 100644
--- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
+++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QLocale>
#include <QDateTime>
@@ -40,6 +41,7 @@ public:
private slots:
void initTestCase();
+ void compareCompiles();
#if defined(Q_OS_WIN)
void windowsDefaultLocale();
#endif
@@ -189,6 +191,11 @@ tst_QLocale::tst_QLocale()
qRegisterMetaType<QLocale::FormatType>("QLocale::FormatType");
}
+void tst_QLocale::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QLocale>();
+}
+
void tst_QLocale::initTestCase()
{
#ifdef Q_OS_ANDROID
@@ -741,8 +748,8 @@ void tst_QLocale::legacyNames()
void tst_QLocale::consistentC()
{
const QLocale c(QLocale::C);
- QCOMPARE(c, QLocale::c());
- QCOMPARE(c, QLocale(QLocale::C, QLocale::AnyScript, QLocale::AnyTerritory));
+ QT_TEST_EQUALITY_OPS(c, QLocale::c(), true);
+ QT_TEST_EQUALITY_OPS(c, QLocale(QLocale::C, QLocale::AnyScript, QLocale::AnyTerritory), true);
QVERIFY(QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
QLocale::AnyTerritory).contains(c));
}
@@ -751,6 +758,7 @@ void tst_QLocale::matchingLocales()
{
const QLocale c(QLocale::C);
const QLocale ru_RU(QLocale::Russian, QLocale::Russia);
+ QT_TEST_EQUALITY_OPS(c, ru_RU, false);
QList<QLocale> locales = QLocale::matchingLocales(QLocale::C, QLocale::AnyScript, QLocale::AnyTerritory);
QCOMPARE(locales.size(), 1);
@@ -1618,6 +1626,11 @@ void tst_QLocale::infNaN()
{
// TODO: QTBUG-95460 -- could support localized forms of inf/NaN
const QLocale c(QLocale::C);
+
+ QT_TEST_EQUALITY_OPS(QLocale(), QLocale(QLocale::C), false);
+ QT_TEST_EQUALITY_OPS(QLocale(), QLocale(), true);
+ QT_TEST_EQUALITY_OPS(QLocale(QLocale::C), c, true);
+
QCOMPARE(c.toString(qQNaN()), u"nan");
QCOMPARE(c.toString(qQNaN(), 'e'), u"nan");
QCOMPARE(c.toString(qQNaN(), 'f'), u"nan");
@@ -2966,6 +2979,7 @@ void tst_QLocale::numberOptions()
QVERIFY(ok);
locale.toDouble(QString("12.400"), &ok);
QVERIFY(!ok);
+ QT_TEST_EQUALITY_OPS(locale, locale2, false);
}
void tst_QLocale::negativeNumbers()
@@ -3030,6 +3044,7 @@ void tst_QLocale::negativeNumbers()
i = farsi.toInt(u"\u200e+\u06f4\u06f0\u06f3"_s, &ok);
QVERIFY(ok);
QCOMPARE(i, 403);
+ QT_TEST_EQUALITY_OPS(egypt, farsi, false);
}
#include <private/qlocale_p.h>
@@ -3288,6 +3303,11 @@ void tst_QLocale::dateFormat()
const QLocale ir("ga_IE");
QCOMPARE(ir.dateFormat(QLocale::ShortFormat), QLatin1String("dd/MM/yyyy"));
+ QT_TEST_EQUALITY_OPS(c, no, false);
+ QT_TEST_EQUALITY_OPS(ca, ja, false);
+ QT_TEST_EQUALITY_OPS(ca, ir, false);
+ QT_TEST_EQUALITY_OPS(ir, ja, false);
+
const auto sys = QLocale::system(); // QTBUG-92018, ru_RU on MS
const QDate date(2021, 3, 17);
QCOMPARE(sys.toString(date, sys.dateFormat(QLocale::LongFormat)), sys.toString(date));
@@ -3327,24 +3347,29 @@ void tst_QLocale::timeFormat()
const QLocale no("no_NO");
QCOMPARE(no.timeFormat(QLocale::NarrowFormat), QLatin1String("HH:mm"));
QCOMPARE(no.timeFormat(QLocale::ShortFormat), QLatin1String("HH:mm"));
- QCOMPARE(no.timeFormat(QLocale::LongFormat), QLatin1String("HH:mm:ss t"));
+ QCOMPARE(no.timeFormat(QLocale::LongFormat), "HH:mm:ss tttt"_L1);
const QLocale id("id_ID");
QCOMPARE(id.timeFormat(QLocale::ShortFormat), QLatin1String("HH.mm"));
- QCOMPARE(id.timeFormat(QLocale::LongFormat), QLatin1String("HH.mm.ss t"));
+ QCOMPARE(id.timeFormat(QLocale::LongFormat), "HH.mm.ss tttt"_L1);
const QLocale cat("ca_ES");
QCOMPARE(cat.timeFormat(QLocale::ShortFormat), QLatin1String("H:mm"));
- QCOMPARE(cat.timeFormat(QLocale::LongFormat), QLatin1String("H:mm:ss (t)"));
+ QCOMPARE(cat.timeFormat(QLocale::LongFormat), "H:mm:ss (tttt)"_L1);
const QLocale bra("pt_BR");
QCOMPARE(bra.timeFormat(QLocale::ShortFormat), QLatin1String("HH:mm"));
- QCOMPARE(bra.timeFormat(QLocale::LongFormat), QLatin1String("HH:mm:ss t"));
+ QCOMPARE(bra.timeFormat(QLocale::LongFormat), "HH:mm:ss tttt"_L1);
// QTBUG-123872 - we kludge CLDR's B to Ap:
const QLocale tw("zh_TW");
QCOMPARE(tw.timeFormat(QLocale::ShortFormat), "Aph:mm"_L1);
- QCOMPARE(tw.timeFormat(QLocale::LongFormat), "Aph:mm:ss [t]"_L1);
+ QCOMPARE(tw.timeFormat(QLocale::LongFormat), "Aph:mm:ss [tttt]"_L1);
+
+ QT_TEST_EQUALITY_OPS(c, no, false);
+ QT_TEST_EQUALITY_OPS(id, no, false);
+ QT_TEST_EQUALITY_OPS(c, cat, false);
+ QT_TEST_EQUALITY_OPS(bra, no, false);
}
void tst_QLocale::dateTimeFormat()
@@ -3356,7 +3381,9 @@ void tst_QLocale::dateTimeFormat()
const QLocale no("no_NO");
QCOMPARE(no.dateTimeFormat(QLocale::NarrowFormat), QLatin1String("dd.MM.yyyy HH:mm"));
QCOMPARE(no.dateTimeFormat(QLocale::ShortFormat), QLatin1String("dd.MM.yyyy HH:mm"));
- QCOMPARE(no.dateTimeFormat(QLocale::LongFormat), QLatin1String("dddd d. MMMM yyyy HH:mm:ss t"));
+ QCOMPARE(no.dateTimeFormat(QLocale::LongFormat), "dddd d. MMMM yyyy HH:mm:ss tttt"_L1);
+
+ QT_TEST_EQUALITY_OPS(c, no, false);
}
void tst_QLocale::monthName()
@@ -3616,6 +3643,7 @@ void tst_QLocale::currency()
const QLocale system = QLocale::system();
QVERIFY(system.toCurrencyString(1, QLatin1String("FOO")).contains(QLatin1String("FOO")));
+ QT_TEST_EQUALITY_OPS(system, es_CR, false);
}
void tst_QLocale::quoteString()
@@ -3630,6 +3658,7 @@ void tst_QLocale::quoteString()
QCOMPARE(de_CH.quoteString(someText), QString::fromUtf8("\xe2\x80\x9e" "text" "\xe2\x80\x9c"));
QCOMPARE(de_CH.quoteString(someText, QLocale::AlternateQuotation),
QString::fromUtf8("\xe2\x80\x9a" "text" "\xe2\x80\x98"));
+ QT_TEST_EQUALITY_OPS(de_CH, c, false);
}
void tst_QLocale::uiLanguages_data()
@@ -4011,6 +4040,7 @@ void tst_QLocale::bcp47Name()
QTest::ignoreMessage(QtWarningMsg, "QLocale::bcp47Name(): "
"Using non-ASCII separator '\u00ff' (ff) is unsupported");
QCOMPARE(locale.bcp47Name(QLocale::TagSeparator{'\xff'}), QString());
+ QT_TEST_EQUALITY_OPS(locale, QLocale(QLatin1String(QTest::currentDataTag())), true);
}
#ifndef QT_NO_SYSTEMLOCALE
@@ -4148,12 +4178,14 @@ void tst_QLocale::mySystemLocale()
qDebug("\n\t%s", qPrintable(QLocale::system().uiLanguages().join(u"\n\t")));
});
QCOMPARE(QLocale::system().uiLanguages(), uiLanguages);
+ QCOMPARE(QLocale::system().uiLanguages(QLocale::TagSeparator::Underscore),
+ uiLanguages.replaceInStrings(u"-", u"_"));
reporter.dismiss();
}
// Verify MySystemLocale tidy-up restored prior state:
- QCOMPARE(QLocale(), originalLocale);
- QCOMPARE(QLocale::system(), originalSystemLocale);
+ QT_TEST_EQUALITY_OPS(QLocale(), originalLocale, true);
+ QT_TEST_EQUALITY_OPS(QLocale::system(), originalSystemLocale, true);
}
# endif // QT_BUILD_INTERNAL
diff --git a/tests/auto/corelib/text/qregularexpression/CMakeLists.txt b/tests/auto/corelib/text/qregularexpression/CMakeLists.txt
index b1d3ed0a8d..a7a7fe298f 100644
--- a/tests/auto/corelib/text/qregularexpression/CMakeLists.txt
+++ b/tests/auto/corelib/text/qregularexpression/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qregularexpression
SOURCES
tst_qregularexpression.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
index ad41ae331e..d0ce414095 100644
--- a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
+++ b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <qstring.h>
#include <qlist.h>
#include <qstringlist.h>
@@ -27,6 +28,7 @@ public:
static void initMain();
private slots:
+ void compareCompiles();
void defaultConstructors();
void moveSemantics();
void moveSemanticsMatch();
@@ -460,6 +462,11 @@ void tst_QRegularExpression::initMain()
}
}
+void tst_QRegularExpression::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QRegularExpression>();
+}
+
void tst_QRegularExpression::defaultConstructors()
{
QRegularExpression re;
@@ -564,12 +571,12 @@ void tst_QRegularExpression::moveSemanticsMatchIterator()
QRegularExpressionMatchIterator it1 = re.globalMatch("some test");
QVERIFY(it1.isValid());
QVERIFY(it1.hasNext());
- QCOMPARE(it1.regularExpression(), re);
+ QT_TEST_EQUALITY_OPS(it1.regularExpression(), re, true);
QRegularExpressionMatchIterator it2(std::move(it1));
QVERIFY(it2.isValid());
QVERIFY(it2.hasNext());
- QCOMPARE(it2.regularExpression(), re);
+ QT_TEST_EQUALITY_OPS(it2.regularExpression(), re, true);
consistencyCheck(it2);
if (QTest::currentTestFailed())
return;
@@ -578,13 +585,13 @@ void tst_QRegularExpression::moveSemanticsMatchIterator()
QRegularExpressionMatchIterator it3 = re2.globalMatch("123test456");
QVERIFY(it3.isValid());
QVERIFY(it3.hasNext());
- QCOMPARE(it3.regularExpression(), re2);
+ QT_TEST_EQUALITY_OPS(it3.regularExpression(), re2, true);
// check that (move)assigning to the moved-from object is ok
it1 = std::move(it3);
QVERIFY(it1.isValid());
QVERIFY(it1.hasNext());
- QCOMPARE(it1.regularExpression(), re2);
+ QT_TEST_EQUALITY_OPS(it1.regularExpression(), re2, true);
consistencyCheck(it1);
if (QTest::currentTestFailed())
return;
@@ -1680,38 +1687,23 @@ void tst_QRegularExpression::serialize()
static void verifyEquality(const QRegularExpression &re1, const QRegularExpression &re2)
{
- QVERIFY(re1 == re2);
- QVERIFY(re2 == re1);
+ QT_TEST_EQUALITY_OPS(re1, re2, true);
QCOMPARE(qHash(re1), qHash(re2));
- QVERIFY(!(re1 != re2));
- QVERIFY(!(re2 != re1));
QRegularExpression re3(re1);
- QVERIFY(re1 == re3);
- QVERIFY(re3 == re1);
QCOMPARE(qHash(re1), qHash(re3));
- QVERIFY(!(re1 != re3));
- QVERIFY(!(re3 != re1));
+ QT_TEST_EQUALITY_OPS(re1, re3, true);
- QVERIFY(re2 == re3);
- QVERIFY(re3 == re2);
QCOMPARE(qHash(re2), qHash(re3));
- QVERIFY(!(re2 != re3));
- QVERIFY(!(re3 != re2));
+ QT_TEST_EQUALITY_OPS(re2, re3, true);
re3 = re2;
- QVERIFY(re1 == re3);
- QVERIFY(re3 == re1);
QCOMPARE(qHash(re1), qHash(re3));
- QVERIFY(!(re1 != re3));
- QVERIFY(!(re3 != re1));
+ QT_TEST_EQUALITY_OPS(re1, re3, true);
- QVERIFY(re2 == re3);
- QVERIFY(re3 == re2);
QCOMPARE(qHash(re2), qHash(re3));
- QVERIFY(!(re2 != re3));
- QVERIFY(!(re3 != re2));
+ QT_TEST_EQUALITY_OPS(re2, re3, true);
}
void tst_QRegularExpression::operatoreq_data()
@@ -1874,12 +1866,14 @@ void tst_QRegularExpression::captureNamesNul()
QString captureName("name");
QCOMPARE(m.captured(captureName), "456");
QCOMPARE(m.captured(QStringView(captureName)), "456");
+ QCOMPARE(m.captured(QAnyStringView(captureName)), "456");
QCOMPARE(m.captured(qToStringViewIgnoringNull(captureName)), "456");
QCOMPARE(m.captured(u"name"), "456");
captureName = "anotherName";
QCOMPARE(m.captured(captureName), "789");
QCOMPARE(m.captured(QStringView(captureName)), "789");
+ QCOMPARE(m.captured(QAnyStringView(captureName)), "789");
QCOMPARE(m.captured(qToStringViewIgnoringNull(captureName)), "789");
QCOMPARE(m.captured(u"anotherName"), "789");
}
diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp
index 35bddf16a4..d56a9ebd20 100644
--- a/tests/auto/corelib/text/qstring/tst_qstring.cpp
+++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp
@@ -6721,9 +6721,15 @@ void tst_QString::arg()
str = str.arg(u"ahoy"_s, u"there"_s);
QCOMPARE(str, "one 2 3 4 5 6 7 8 9 foo ahoy there bar"_L1);
- QString str2(u"%123 %234 %345 %456 %567 %999 %1000 %1230"_s);
- str2 = str2.arg(u"A"_s, u"B"_s, u"C"_s, u"D"_s, u"E"_s, u"F"_s);
- QCOMPARE(str2, QLatin1String("A B C D E F %1000 %1230"));
+ // Make sure the single- and multi-arg expand the same sequences: at most
+ // two digits. The sequence below has four replacements: %01, %10 (twice),
+ // %11, and %12.
+ QString str2 = u"%100 %101 %110 %12 %0100"_s;
+ QLatin1StringView str2expected = "B0 B1 C0 D A00"_L1;
+ QCOMPARE(str2.arg(QChar(u'A')).arg(QChar(u'B')).arg(QChar(u'C')).arg(QChar(u'D')), str2expected);
+ QCOMPARE(str2.arg(QChar(u'A'), QChar(u'B')).arg(QChar(u'C')).arg(QChar(u'D')), str2expected);
+ QCOMPARE(str2.arg(QChar(u'A'), QChar(u'B'), QChar(u'C')).arg(QChar(u'D')), str2expected);
+ QCOMPARE(str2.arg(QChar(u'A'), QChar(u'B'), QChar(u'C'), QChar(u'D')), str2expected);
QCOMPARE(u"%1"_s.arg(-1, 3, 10, QChar(u'0')), "-01"_L1);
QCOMPARE(u"%1"_s.arg(-100, 3, 10, QChar(u'0')), "-100"_L1);
diff --git a/tests/auto/corelib/thread/CMakeLists.txt b/tests/auto/corelib/thread/CMakeLists.txt
index 68110b652b..d25d0205f5 100644
--- a/tests/auto/corelib/thread/CMakeLists.txt
+++ b/tests/auto/corelib/thread/CMakeLists.txt
@@ -17,11 +17,20 @@ if(QT_FEATURE_thread)
add_subdirectory(qatomicint)
add_subdirectory(qatomicinteger)
add_subdirectory(qatomicpointer)
- add_subdirectory(qresultstore)
- if(QT_FEATURE_concurrent AND NOT INTEGRITY)
- add_subdirectory(qfuture)
+ if(QT_FEATURE_future)
+ if(QT_FEATURE_concurrent AND NOT INTEGRITY)
+ add_subdirectory(qfuture)
+ endif()
+ add_subdirectory(qresultstore)
+ add_subdirectory(qfuturesynchronizer)
+ if(NOT INTEGRITY)
+ add_subdirectory(qpromise)
+ endif()
+ # QTBUG-87431
+ if(TARGET Qt::Concurrent AND NOT INTEGRITY)
+ add_subdirectory(qfuturewatcher)
+ endif()
endif()
- add_subdirectory(qfuturesynchronizer)
add_subdirectory(qmutex)
add_subdirectory(qmutexlocker)
add_subdirectory(qreadlocker)
@@ -36,12 +45,5 @@ if(QT_FEATURE_thread)
add_subdirectory(qthreadstorage)
add_subdirectory(qwaitcondition)
add_subdirectory(qwritelocker)
- if(NOT INTEGRITY)
- add_subdirectory(qpromise)
- endif()
endif()
-# QTBUG-87431
-if(TARGET Qt::Concurrent AND NOT INTEGRITY)
- add_subdirectory(qfuturewatcher)
-endif()
diff --git a/tests/auto/corelib/thread/qfuture/CMakeLists.txt b/tests/auto/corelib/thread/qfuture/CMakeLists.txt
index aa989f3df1..ba5730d5cf 100644
--- a/tests/auto/corelib/thread/qfuture/CMakeLists.txt
+++ b/tests/auto/corelib/thread/qfuture/CMakeLists.txt
@@ -16,6 +16,7 @@ qt_internal_add_test(tst_qfuture
tst_qfuture.cpp
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
qt_internal_extend_target(tst_qfuture CONDITION MSVC
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index 3fc796514d..4cb29c514a 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -17,6 +17,7 @@
#include <private/qobject_p.h>
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <qfuture.h>
#include <qfuturewatcher.h>
#include <qresultstore.h>
@@ -161,6 +162,7 @@ class tst_QFuture: public QObject
{
Q_OBJECT
private slots:
+ void compareCompiles();
void resultStore();
void future();
void futureToVoid();
@@ -273,6 +275,12 @@ private:
QtPrivate::ResultStoreBase &store;
};
+void tst_QFuture::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QFuture<int>::const_iterator>();
+ QTestPrivate::testEqualityOperatorsCompile<QFuture<QString>::const_iterator>();
+}
+
void tst_QFuture::resultStore()
{
int int0 = 0;
@@ -1359,16 +1367,16 @@ void tst_QFuture::iterators()
QFuture<int>::const_iterator i1 = f.begin(), i2 = i1 + 1;
QFuture<int>::const_iterator c1 = i1, c2 = c1 + 1;
- QCOMPARE(i1, i1);
- QCOMPARE(i1, c1);
- QCOMPARE(c1, i1);
- QCOMPARE(c1, c1);
- QCOMPARE(i2, i2);
- QCOMPARE(i2, c2);
- QCOMPARE(c2, i2);
- QCOMPARE(c2, c2);
- QCOMPARE(1 + i1, i1 + 1);
- QCOMPARE(1 + c1, c1 + 1);
+ QT_TEST_EQUALITY_OPS(i1, i1, true);
+ QT_TEST_EQUALITY_OPS(i1, c1, true);
+ QT_TEST_EQUALITY_OPS(c1, i1, true);
+ QT_TEST_EQUALITY_OPS(c1, c1, true);
+ QT_TEST_EQUALITY_OPS(i2, i2, true);
+ QT_TEST_EQUALITY_OPS(i2, c2, true);
+ QT_TEST_EQUALITY_OPS(c2, i2, true);
+ QT_TEST_EQUALITY_OPS(c2, c2, true);
+ QT_TEST_EQUALITY_OPS(1 + i1, i1 + 1, true);
+ QT_TEST_EQUALITY_OPS(1 + c1, c1 + 1, true);
QVERIFY(i1 != i2);
QVERIFY(i1 != c2);
diff --git a/tests/auto/corelib/thread/qresultstore/CMakeLists.txt b/tests/auto/corelib/thread/qresultstore/CMakeLists.txt
index 0f9d8d9e52..5abfc14ac6 100644
--- a/tests/auto/corelib/thread/qresultstore/CMakeLists.txt
+++ b/tests/auto/corelib/thread/qresultstore/CMakeLists.txt
@@ -16,4 +16,5 @@ qt_internal_add_test(tst_qresultstore
tst_qresultstore.cpp
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp b/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp
index 265b2cd1f6..722184a72a 100644
--- a/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp
+++ b/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
-
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <qresultstore.h>
using namespace QtPrivate;
@@ -23,6 +23,7 @@ class tst_QtConcurrentResultStore : public QObject
public slots:
void init();
private slots:
+ void compareCompiles();
void construction();
void iterators();
void addResult();
@@ -52,6 +53,11 @@ void tst_QtConcurrentResultStore::init()
vec1 = QList<int> { 4, 5 };
}
+void tst_QtConcurrentResultStore::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<ResultIteratorBase>();
+}
+
void tst_QtConcurrentResultStore::construction()
{
ResultStoreBase store;
@@ -74,17 +80,20 @@ void tst_QtConcurrentResultStore::iterators()
storebase.addResult(1, &int1); // ResultStoreBase does not take ownership, only ResultStore<> does.
ResultIteratorBase it = storebase.begin();
QCOMPARE(it.resultIndex(), 0);
- QCOMPARE(it, storebase.begin());
+ QT_TEST_EQUALITY_OPS(it, storebase.begin(), true);
QVERIFY(it != storebase.end());
++it;
QCOMPARE(it.resultIndex(), 1);
QVERIFY(it != storebase.begin());
QVERIFY(it != storebase.end());
+ QT_TEST_EQUALITY_OPS(it, storebase.begin(), false);
+ QT_TEST_EQUALITY_OPS(it, storebase.end(), false);
++it;
QVERIFY(it != storebase.begin());
QCOMPARE(it, storebase.end());
+ QT_TEST_EQUALITY_OPS(it, storebase.end(), true);
}
}
@@ -147,8 +156,8 @@ void tst_QtConcurrentResultStore::addResults()
store.addResults(-1, &vec1);
ResultIteratorBase it = store.begin();
QCOMPARE(it.resultIndex(), 0);
- QCOMPARE(it, store.begin());
- QVERIFY(it != store.end());
+ QT_TEST_EQUALITY_OPS(it, store.begin(), true);
+ QT_TEST_EQUALITY_OPS(it, store.end(), false);
++it;
QCOMPARE(it.resultIndex(), 1);
@@ -162,7 +171,7 @@ void tst_QtConcurrentResultStore::addResults()
QCOMPARE(it.resultIndex(), 3);
++it;
- QCOMPARE(it, store.end());
+ QT_TEST_EQUALITY_OPS(it, store.end(), true);
QList<int> empty;
const auto countBefore = store.count();
@@ -184,22 +193,22 @@ void tst_QtConcurrentResultStore::resultIndex()
ResultIteratorBase it = store.begin();
QCOMPARE(it.resultIndex(), 0);
- QVERIFY(it == store.begin());
- QVERIFY(it != store.end());
+ QT_TEST_EQUALITY_OPS(it, store.begin(), true);
+ QT_TEST_EQUALITY_OPS(it, store.end(), false);
++it;
QCOMPARE(it.resultIndex(), 1);
- QVERIFY(it != store.begin());
- QVERIFY(it != store.end());
+ QT_TEST_EQUALITY_OPS(it, store.begin(), false);
+ QT_TEST_EQUALITY_OPS(it, store.end(), false);
++it;
QCOMPARE(it.resultIndex(), 2);
- QVERIFY(it != store.end());
+ QT_TEST_EQUALITY_OPS(it, store.end(), false);
++it;
QCOMPARE(it.resultIndex(), 3);
- QVERIFY(it != store.end());
+ QT_TEST_EQUALITY_OPS(it, store.end(), false);
++it;
- QVERIFY(it == store.end());
+ QT_TEST_EQUALITY_OPS(it, store.end(), true);
QCOMPARE(store.resultAt(0).value<int>(), int0);
QCOMPARE(store.resultAt(1).value<int>(), vec0[0]);
diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
index a7194d4442..18c8d5fbd5 100644
--- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp
+++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
@@ -53,6 +53,7 @@ private slots:
void setStackSize();
void exit();
void start();
+ void startSlotUsedInStringBasedLookups();
void terminate();
void quit();
void started();
@@ -136,11 +137,13 @@ class Current_Thread : public QThread
public:
Qt::HANDLE id;
QThread *thread;
+ bool runCalledInCurrentThread = false;
void run() override
{
id = QThread::currentThreadId();
thread = QThread::currentThread();
+ runCalledInCurrentThread = thread->isCurrentThread();
}
};
@@ -275,6 +278,11 @@ void tst_QThread::currentThreadId()
QVERIFY(thread.wait(five_minutes));
QVERIFY(thread.id != nullptr);
QVERIFY(thread.id != QThread::currentThreadId());
+ QVERIFY(!thread.isCurrentThread());
+ QVERIFY(!thread.thread->isCurrentThread());
+ QVERIFY(thread.QThread::thread()->isCurrentThread());
+ QVERIFY(thread.runCalledInCurrentThread);
+ QVERIFY(qApp->thread()->isCurrentThread());
}
void tst_QThread::currentThread()
@@ -466,6 +474,56 @@ void tst_QThread::start()
}
}
+class QThreadStarter : public QObject
+{
+ Q_OBJECT
+public:
+ using QObject::QObject;
+Q_SIGNALS:
+ void start(QThread::Priority);
+};
+
+class QThreadSelfStarter : public QThread
+{
+ Q_OBJECT
+public:
+ using QThread::QThread;
+
+ void check()
+ {
+ QVERIFY(connect(this, SIGNAL(starting(Priority)),
+ this, SLOT(start(Priority))));
+ QVERIFY(QMetaObject::invokeMethod(this, "start", Q_ARG(Priority, IdlePriority)));
+ }
+
+Q_SIGNALS:
+ void starting(Priority);
+};
+
+void tst_QThread::startSlotUsedInStringBasedLookups()
+{
+ // QTBUG-124723
+
+ QThread thread;
+ {
+ QThreadStarter starter;
+ QVERIFY(QObject::connect(&starter, SIGNAL(start(QThread::Priority)),
+ &thread, SLOT(start(QThread::Priority))));
+ }
+ {
+ QThreadSelfStarter selfStarter;
+ selfStarter.check();
+ if (QTest::currentTestFailed())
+ return;
+ selfStarter.exit();
+ selfStarter.wait(30s);
+ }
+ QVERIFY(QMetaObject::invokeMethod(&thread, "start",
+ Q_ARG(QThread::Priority, QThread::IdlePriority)));
+ thread.exit();
+ thread.wait(30s);
+}
+
void tst_QThread::terminate()
{
#if defined(Q_OS_ANDROID)
@@ -1241,8 +1299,16 @@ public:
}
void registerSocketNotifier(QSocketNotifier *) override {}
void unregisterSocketNotifier(QSocketNotifier *) override {}
- void registerTimer(Qt::TimerId, Duration, Qt::TimerType, QObject *) override {}
- bool unregisterTimer(Qt::TimerId) override { return false; }
+ void registerTimer(Qt::TimerId id, Duration, Qt::TimerType, QObject *) override
+ {
+ if (registeredTimerId <= Qt::TimerId::Invalid)
+ registeredTimerId = id;
+ }
+ bool unregisterTimer(Qt::TimerId id) override
+ {
+ Qt::TimerId oldId = std::exchange(registeredTimerId, Qt::TimerId::Invalid);
+ return id == oldId;
+ }
bool unregisterTimers(QObject *) override { return false; }
QList<TimerInfoV2> timersForObject(QObject *) const override { return {}; }
Duration remainingTime(Qt::TimerId) const override { return 0s; }
@@ -1255,25 +1321,47 @@ public:
#endif
QBasicAtomicInt visited; // bool
+ Qt::TimerId registeredTimerId = Qt::TimerId::Invalid;
};
-class ThreadObj : public QObject
+struct ThreadLocalContent
{
- Q_OBJECT
-public slots:
- void visit() {
- emit visited();
+ static inline const QMetaObject *atStart;
+ static inline const QMetaObject *atEnd;
+ QSemaphore *sem;
+ QBasicTimer timer;
+
+ ThreadLocalContent(QObject *obj, QSemaphore *sem)
+ : sem(sem)
+ {
+ ensureEventDispatcher();
+ atStart = QAbstractEventDispatcher::instance()->metaObject();
+ timer.start(10s, obj);
+ }
+ ~ThreadLocalContent()
+ {
+ ensureEventDispatcher();
+ atEnd = QAbstractEventDispatcher::instance()->metaObject();
+ timer.stop();
+ sem->release();
+ }
+
+ void ensureEventDispatcher()
+ {
+ // QEventLoop's constructor has a call to QThreadData::ensureEventDispatcher()
+ QEventLoop dummy;
}
-signals:
- void visited();
};
void tst_QThread::customEventDispatcher()
{
+ ThreadLocalContent::atStart = ThreadLocalContent::atEnd = nullptr;
+
QThread thr;
// there should be no ED yet
QVERIFY(!thr.eventDispatcher());
DummyEventDispatcher *ed = new DummyEventDispatcher;
+ QPointer<DummyEventDispatcher> weak_ed(ed);
thr.setEventDispatcher(ed);
// the new ED should be set
QCOMPARE(thr.eventDispatcher(), ed);
@@ -1282,25 +1370,39 @@ void tst_QThread::customEventDispatcher()
thr.start();
// start() should not overwrite the ED
QCOMPARE(thr.eventDispatcher(), ed);
+ QVERIFY(!weak_ed.isNull());
- ThreadObj obj;
+ QObject obj;
obj.moveToThread(&thr);
// move was successful?
QCOMPARE(obj.thread(), &thr);
- QEventLoop loop;
- connect(&obj, SIGNAL(visited()), &loop, SLOT(quit()), Qt::QueuedConnection);
- QMetaObject::invokeMethod(&obj, "visit", Qt::QueuedConnection);
- loop.exec();
+
+ QSemaphore threadLocalSemaphore;
+ QMetaObject::invokeMethod(&obj, [&]() {
+#ifndef Q_OS_WIN
+ // On Windows, the thread_locals are unsequenced between DLLs, so this
+ // could run after QThreadPrivate::finish()
+ static thread_local
+#endif
+ ThreadLocalContent d(&obj, &threadLocalSemaphore);
+ }, Qt::BlockingQueuedConnection);
+
// test that the ED has really been used
QVERIFY(ed->visited.loadRelaxed());
+ // and it's ours
+ QCOMPARE(ThreadLocalContent::atStart->className(), "DummyEventDispatcher");
- QPointer<DummyEventDispatcher> weak_ed(ed);
QVERIFY(!weak_ed.isNull());
thr.quit();
+
// wait for thread to be stopped
QVERIFY(thr.wait(30000));
+ QVERIFY(threadLocalSemaphore.tryAcquire(1, 30s));
+
// test that ED has been deleted
QVERIFY(weak_ed.isNull());
+ // test that ED was ours
+ QCOMPARE(ThreadLocalContent::atEnd->className(), "DummyEventDispatcher");
}
class Job : public QObject
diff --git a/tests/auto/corelib/time/CMakeLists.txt b/tests/auto/corelib/time/CMakeLists.txt
index f2dfbfa527..1fb95e9245 100644
--- a/tests/auto/corelib/time/CMakeLists.txt
+++ b/tests/auto/corelib/time/CMakeLists.txt
@@ -4,6 +4,10 @@
add_subdirectory(qcalendar)
add_subdirectory(qdate)
add_subdirectory(qdatetime)
-add_subdirectory(qdatetimeparser)
+if(QT_FEATURE_datetimeparser)
+ add_subdirectory(qdatetimeparser)
+endif()
add_subdirectory(qtime)
-add_subdirectory(qtimezone)
+if(QT_FEATURE_timezone)
+ add_subdirectory(qtimezone)
+endif()
diff --git a/tests/auto/corelib/time/qdate/tst_qdate.cpp b/tests/auto/corelib/time/qdate/tst_qdate.cpp
index cacdad307f..5b715e8c55 100644
--- a/tests/auto/corelib/time/qdate/tst_qdate.cpp
+++ b/tests/auto/corelib/time/qdate/tst_qdate.cpp
@@ -1179,7 +1179,7 @@ void tst_QDate::operator_insert_extract()
QCOMPARE(deserialised, date);
}
-#if QT_CONFIG(datetimeparser)
+#if QT_CONFIG(datestring)
void tst_QDate::fromStringDateFormat_data()
{
QTest::addColumn<QString>("dateStr");
@@ -1303,6 +1303,7 @@ void tst_QDate::fromStringDateFormat()
QCOMPARE(QDate::fromString(dateStr, dateFormat), expectedDate);
}
+# if QT_CONFIG(datetimeparser)
void tst_QDate::fromStringFormat_data()
{
QTest::addColumn<QString>("string");
@@ -1490,7 +1491,6 @@ void tst_QDate::fromStringFormat()
}
#endif // datetimeparser
-#if QT_CONFIG(datestring)
void tst_QDate::toStringFormat_data()
{
QTest::addColumn<QDate>("t");
diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
index a350ffeb04..7f6bc96aa6 100644
--- a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
+++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
@@ -584,7 +584,7 @@ void tst_QTimeZone::utcOffsetId_data()
#define ROW(name, valid, offset) \
QTest::newRow(name) << QByteArray(name) << valid << offset
- // See qtbase/util/locale_database/cldr2qtimezone.py for source
+ // See qtbase/util/locale_database/zonedata.py for source
// CLDR v35.1 IDs:
ROW("UTC", true, 0);
ROW("UTC-14:00", true, -50400);
@@ -1280,7 +1280,7 @@ void tst_QTimeZone::utcTest()
void tst_QTimeZone::icuTest()
{
-#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(icu)
+#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(icu) && !defined(Q_OS_UNIX)
// Known datetimes
qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0), QTimeZone::UTC).toMSecsSinceEpoch();
@@ -1323,7 +1323,7 @@ void tst_QTimeZone::icuTest()
if (QTest::currentTestFailed())
return;
testEpochTranPrivate(QIcuTimeZonePrivate("America/Toronto"));
-#endif // icu
+#endif // ICU not on Unix
}
void tst_QTimeZone::tzTest()
@@ -1527,7 +1527,7 @@ void tst_QTimeZone::tzTest()
QDateTime dt(QDate(2016, 3, 28), QTime(0, 0), UTC);
QCOMPARE(tzBarnaul.data(dt.toMSecsSinceEpoch()).abbreviation, QString("+07"));
}
-#endif // QT_BUILD_INTERNAL && Q_OS_UNIX && !Q_OS_DARWIN
+#endif // QT_BUILD_INTERNAL && Q_OS_UNIX && !Q_OS_DARWIN && !Q_OS_ANDROID
}
void tst_QTimeZone::macTest()
diff --git a/tests/auto/corelib/tools/qbitarray/CMakeLists.txt b/tests/auto/corelib/tools/qbitarray/CMakeLists.txt
index 802d647abb..ac3bd24bd5 100644
--- a/tests/auto/corelib/tools/qbitarray/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qbitarray/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qbitarray
SOURCES
tst_qbitarray.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp b/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp
index 5fcf444485..f52a368aa9 100644
--- a/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp
+++ b/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QtCore/QBuffer>
#include <QtCore/QDataStream>
@@ -39,6 +40,7 @@ class tst_QBitArray : public QObject
{
Q_OBJECT
private slots:
+ void compareCompiles();
void canHandleIntMaxBits();
void size_data();
void size();
@@ -85,6 +87,11 @@ private slots:
void toUInt32();
};
+void tst_QBitArray::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QBitArray>();
+}
+
void tst_QBitArray::canHandleIntMaxBits()
{
QElapsedTimer timer;
@@ -126,7 +133,7 @@ void tst_QBitArray::canHandleIntMaxBits()
QBitArray ba2;
ds >> ba2;
QCOMPARE(ds.status(), QDataStream::Status::Ok);
- QCOMPARE(ba, ba2);
+ QT_TEST_EQUALITY_OPS(ba, ba2, true);
}
} catch (const std::bad_alloc &) {
QSKIP("Failed to allocate sufficient memory");
@@ -266,14 +273,20 @@ void tst_QBitArray::isEmpty()
QVERIFY(!a1.isEmpty());
QVERIFY(!a1.isNull());
QVERIFY(a1.size() == 2);
+
+ QT_TEST_EQUALITY_OPS(a1, a2, false);
+ QT_TEST_EQUALITY_OPS(a2, a3, false);
+ QT_TEST_EQUALITY_OPS(QBitArray(), QBitArray(), true);
+ a3 = a2;
+ QT_TEST_EQUALITY_OPS(a2, a3, true);
}
void tst_QBitArray::swap()
{
QBitArray b1 = QStringToQBitArray("1"), b2 = QStringToQBitArray("10");
b1.swap(b2);
- QCOMPARE(b1,QStringToQBitArray("10"));
- QCOMPARE(b2,QStringToQBitArray("1"));
+ QT_TEST_EQUALITY_OPS(b1,QStringToQBitArray("10"), true);
+ QT_TEST_EQUALITY_OPS(b2,QStringToQBitArray("1"), true);
}
void tst_QBitArray::fill()
@@ -323,7 +336,7 @@ void tst_QBitArray::toggleBit()
input.toggleBit(index);
- QCOMPARE(input, res);
+ QT_TEST_EQUALITY_OPS(input, res, true);
}
void tst_QBitArray::operator_andeq_data()
@@ -370,32 +383,32 @@ void tst_QBitArray::operator_andeq()
QBitArray result = input1;
result &= input2;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1;
result &= std::move(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1;
result &= detached(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is commutative
result = input2;
result &= input1;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2;
result &= std::move(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2;
result &= detached(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is idempotent
result &= result;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result &= std::move(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result &= detached(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
}
void tst_QBitArray::operator_and()
@@ -405,27 +418,27 @@ void tst_QBitArray::operator_and()
QFETCH(QBitArray, res);
QBitArray result = input1 & input2;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1 & QBitArray(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1 & detached(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is commutative
result = input2 & input1;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2 & QBitArray(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2 & detached(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is idempotent
result = result & result;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = result & QBitArray(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = result & detached(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
}
void tst_QBitArray::operator_oreq_data()
@@ -476,32 +489,32 @@ void tst_QBitArray::operator_oreq()
QBitArray result = input1;
result |= input2;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1;
result |= QBitArray(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1;
result |= detached(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is commutative
result = input2;
result |= input1;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2;
result |= QBitArray(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2;
result |= detached(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is idempotent
result |= result;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result |= QBitArray(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result |= detached(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
}
void tst_QBitArray::operator_or()
@@ -511,27 +524,27 @@ void tst_QBitArray::operator_or()
QFETCH(QBitArray, res);
QBitArray result = input1 | input2;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1 | QBitArray(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1 | detached(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is commutative
result = input2 | input1;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2 | QBitArray(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2 | detached(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is idempotent
result = result | result;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = result | QBitArray(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = result | detached(result);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
}
void tst_QBitArray::operator_xoreq_data()
@@ -580,55 +593,55 @@ void tst_QBitArray::operator_xoreq()
QBitArray result = input1;
result ^= input2;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1;
result ^= QBitArray(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1;
result ^= detached(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is commutative
result = input2;
result ^= input1;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2;
result ^= QBitArray(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2;
result ^= detached(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// XORing with oneself is nilpotent
result = input1;
result ^= input1;
- QCOMPARE(result, QBitArray(input1.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
result = input1;
result ^= QBitArray(result);
- QCOMPARE(result, QBitArray(input1.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
result = input1;
result ^= detached(result);
- QCOMPARE(result, QBitArray(input1.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
result = input2;
result ^= input2;
- QCOMPARE(result, QBitArray(input2.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
result = input2;
result ^= QBitArray(input2);
- QCOMPARE(result, QBitArray(input2.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
result = input2;
result ^= detached(input2);
- QCOMPARE(result, QBitArray(input2.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
result = res;
result ^= res;
- QCOMPARE(result, QBitArray(res.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
result = res;
result ^= QBitArray(res);
- QCOMPARE(result, QBitArray(res.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
result = res;
result ^= detached(res);
- QCOMPARE(result, QBitArray(res.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
}
void tst_QBitArray::operator_xor()
@@ -638,41 +651,41 @@ void tst_QBitArray::operator_xor()
QFETCH(QBitArray, res);
QBitArray result = input1 ^ input2;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1 ^ QBitArray(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input1 ^ detached(input2);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// operation is commutative
result = input2 ^ input1;
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2 ^ QBitArray(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
result = input2 ^ detached(input1);
- QCOMPARE(result, res);
+ QT_TEST_EQUALITY_OPS(result, res, true);
// XORing with oneself is nilpotent
result = input1 ^ input1;
- QCOMPARE(result, QBitArray(input1.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
result = input1 ^ QBitArray(input1);
- QCOMPARE(result, QBitArray(input1.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
result = input1 ^ detached(input1);
- QCOMPARE(result, QBitArray(input1.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
result = input2 ^ input2;
- QCOMPARE(result, QBitArray(input2.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
result = input2 ^ QBitArray(input2);
- QCOMPARE(result, QBitArray(input2.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
result = input2 ^ detached(input2);
- QCOMPARE(result, QBitArray(input2.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
result = res ^ res;
- QCOMPARE(result, QBitArray(res.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
result = res ^ QBitArray(res);
- QCOMPARE(result, QBitArray(res.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
result = res ^ detached(res);
- QCOMPARE(result, QBitArray(res.size()));
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
}
void tst_QBitArray::operator_neg_data()
@@ -721,8 +734,8 @@ void tst_QBitArray::operator_neg()
input = ~input;
- QCOMPARE(input, res);
- QCOMPARE(~~input, res); // performs two in-place negations
+ QT_TEST_EQUALITY_OPS(input, res, true);
+ QT_TEST_EQUALITY_OPS(~~input, res, true); // performs two in-place negations
}
void tst_QBitArray::datastream_data()
@@ -782,15 +795,15 @@ void tst_QBitArray::datastream()
QCOMPARE(array1.count(true), onBits);
QCOMPARE(array1.count(false), numBits - onBits);
- QCOMPARE(array1, bits);
- QCOMPARE(array2, bits);
- QCOMPARE(array3, bits);
+ QT_TEST_EQUALITY_OPS(array1, bits, true);
+ QT_TEST_EQUALITY_OPS(array2, bits, true);
+ QT_TEST_EQUALITY_OPS(array3, bits, true);
}
void tst_QBitArray::invertOnNull() const
{
QBitArray a;
- QCOMPARE(a = ~a, QBitArray());
+ QT_TEST_EQUALITY_OPS(a = ~a, QBitArray(), true);
}
void tst_QBitArray::operator_noteq_data()
@@ -831,7 +844,7 @@ void tst_QBitArray::operator_noteq()
QFETCH(bool, res);
bool b = input1 != input2;
- QCOMPARE(b, res);
+ QT_TEST_EQUALITY_OPS(b, res, true);
}
void tst_QBitArray::resize()
@@ -840,22 +853,22 @@ void tst_QBitArray::resize()
QBitArray a = QStringToQBitArray(QString("11"));
a.resize(10);
QVERIFY(a.size() == 10);
- QCOMPARE( a, QStringToQBitArray(QString("1100000000")) );
+ QT_TEST_EQUALITY_OPS( a, QStringToQBitArray(QString("1100000000")), true);
a.setBit(9);
a.resize(9);
// now the bit in a should have been gone:
- QCOMPARE( a, QStringToQBitArray(QString("110000000")) );
+ QT_TEST_EQUALITY_OPS( a, QStringToQBitArray(QString("110000000")), true);
// grow the array back and check the new bit
a.resize(10);
- QCOMPARE( a, QStringToQBitArray(QString("1100000000")) );
+ QT_TEST_EQUALITY_OPS( a, QStringToQBitArray(QString("1100000000")), true);
// other test with and
a.resize(9);
QBitArray b = QStringToQBitArray(QString("1111111111"));
b &= a;
- QCOMPARE( b, QStringToQBitArray(QString("1100000000")) );
+ QT_TEST_EQUALITY_OPS( b, QStringToQBitArray(QString("1100000000")), true);
}
@@ -909,9 +922,9 @@ void tst_QBitArray::fromBits()
QFETCH(QBitArray, expected);
QBitArray fromBits = QBitArray::fromBits(data, size);
- QCOMPARE(fromBits, expected);
+ QT_TEST_EQUALITY_OPS(fromBits, expected, true);
- QCOMPARE(QBitArray::fromBits(fromBits.bits(), fromBits.size()), expected);
+ QT_TEST_EQUALITY_OPS(QBitArray::fromBits(fromBits.bits(), fromBits.size()), expected, true);
}
void tst_QBitArray::toUInt32_data()
diff --git a/tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt b/tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt
index 3f76f8a38f..2569e0c7a9 100644
--- a/tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qeasingcurve
SOURCES
tst_qeasingcurve.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
index fc8c1a3e5c..0a933a1e2b 100644
--- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
+++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
+#include <private/qcomparisontesthelper_p.h>
#include <qeasingcurve.h>
@@ -16,6 +17,7 @@ private slots:
void valueForProgress_data();
void valueForProgress();
void setCustomType();
+ void comparisonCompiles();
void operators();
void properties();
void metaTypes();
@@ -420,6 +422,11 @@ void tst_QEasingCurve::setCustomType()
QCOMPARE(curve.valueForProgress(0.99), 0.99);
}
+void tst_QEasingCurve::comparisonCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QEasingCurve>();
+}
+
void tst_QEasingCurve::operators()
{
{ // member-swap()
@@ -447,28 +454,28 @@ void tst_QEasingCurve::operators()
curve2 = curve;
curve2.setOvershoot(qreal(1.70158));
QCOMPARE(curve.overshoot(), curve2.overshoot());
- QVERIFY(curve2 == curve);
+ QT_TEST_EQUALITY_OPS(curve2, curve, true);
curve.setOvershoot(3.0);
- QVERIFY(curve2 != curve);
+ QT_TEST_EQUALITY_OPS(curve2, curve, false);
curve2.setOvershoot(3.0);
- QVERIFY(curve2 == curve);
+ QT_TEST_EQUALITY_OPS(curve2, curve, true);
curve2.setType(QEasingCurve::Linear);
QCOMPARE(curve.overshoot(), curve2.overshoot());
- QVERIFY(curve2 != curve);
+ QT_TEST_EQUALITY_OPS(curve2, curve, false);
curve2.setType(QEasingCurve::InBack);
QCOMPARE(curve.overshoot(), curve2.overshoot());
- QVERIFY(curve2 == curve);
+ QT_TEST_EQUALITY_OPS(curve2, curve, true);
QEasingCurve curve3;
QEasingCurve curve4;
curve4.setAmplitude(curve4.amplitude());
QEasingCurve curve5;
curve5.setAmplitude(0.12345);
- QVERIFY(curve3 == curve4); // default value and not assigned
- QVERIFY(curve3 != curve5); // unassinged and other value
- QVERIFY(curve4 != curve5);
+ QT_TEST_EQUALITY_OPS(curve3, curve4, true); // default value and not assigned
+ QT_TEST_EQUALITY_OPS(curve3, curve5, false); // unassinged and other value
+ QT_TEST_EQUALITY_OPS(curve4, curve5, false);
}
class tst_QEasingProperties : public QObject
@@ -890,7 +897,7 @@ void tst_QEasingCurve::streamInOut()
dsw << orig;
dsr >> copy;
- QCOMPARE(copy == orig, equality);
+ QT_TEST_EQUALITY_OPS(copy, orig, equality);
}
QTEST_MAIN(tst_QEasingCurve)
diff --git a/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp b/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp
index 99fc7c5772..e004a560a2 100644
--- a/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp
+++ b/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp
@@ -21,7 +21,7 @@ private Q_SLOTS:
void deterministicSeed();
void reseeding();
void quality();
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && QT_DEPRECATED_SINCE(6,6)
void compatibilityApi();
void deterministicSeed_compat();
#endif
@@ -157,7 +157,7 @@ void tst_QHashSeed::quality()
"seedsToMinus1 = " + QByteArray::number(seedsToMinus1));
}
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && QT_DEPRECATED_SINCE(6,6)
QT_WARNING_DISABLE_DEPRECATED
void tst_QHashSeed::compatibilityApi()
{
diff --git a/tests/auto/corelib/tools/qline/CMakeLists.txt b/tests/auto/corelib/tools/qline/CMakeLists.txt
index 17a3a1bcef..7d9fdf51a9 100644
--- a/tests/auto/corelib/tools/qline/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qline/CMakeLists.txt
@@ -14,6 +14,8 @@ endif()
qt_internal_add_test(tst_qline
SOURCES
tst_qline.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
## Scopes:
diff --git a/tests/auto/corelib/tools/qline/tst_qline.cpp b/tests/auto/corelib/tools/qline/tst_qline.cpp
index 51f1f8ac79..10069e821b 100644
--- a/tests/auto/corelib/tools/qline/tst_qline.cpp
+++ b/tests/auto/corelib/tools/qline/tst_qline.cpp
@@ -4,6 +4,7 @@
#include <QTest>
#include <qline.h>
#include <qmath.h>
+#include <private/qcomparisontesthelper_p.h>
#include <array>
@@ -11,6 +12,16 @@ class tst_QLine : public QObject
{
Q_OBJECT
private slots:
+ void testComparisonCompiles();
+ void testComparison_data();
+ void testComparison();
+
+ void testFuzzyCompare_data();
+ void testFuzzyCompare();
+
+ void testIsNull_data();
+ void testIsNull();
+
void testIntersection();
void testIntersection_data();
@@ -41,6 +52,120 @@ private slots:
};
const qreal epsilon = sizeof(qreal) == sizeof(double) ? 1e-8 : 1e-4;
+constexpr static qreal qreal_min = std::numeric_limits<qreal>::min();
+
+void tst_QLine::testComparisonCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QLine>();
+ QTestPrivate::testEqualityOperatorsCompile<QLineF>();
+ QTestPrivate::testEqualityOperatorsCompile<QLineF, QLine>();
+}
+
+void tst_QLine::testComparison_data()
+{
+ QTest::addColumn<double>("xa1");
+ QTest::addColumn<double>("ya1");
+ QTest::addColumn<double>("xa2");
+ QTest::addColumn<double>("ya2");
+ QTest::addColumn<double>("xb1");
+ QTest::addColumn<double>("yb1");
+ QTest::addColumn<double>("xb2");
+ QTest::addColumn<double>("yb2");
+ QTest::addColumn<bool>("result");
+ QTest::addColumn<bool>("floatResult");
+ QTest::addColumn<bool>("mixedResult");
+
+ auto row = [&](double xa1, double ya1, double xa2, double ya2,
+ double xb1, double yb1, double xb2, double yb2,
+ bool result, bool floatResult, bool mixedResult)
+ {
+ QString str;
+ QDebug dbg(&str);
+ dbg.nospace() << "[(" << xa1 << ", " << ya1 << "); (" << xa2 << ", " << ya2 << ")] vs [("
+ << xb1 << ", " << yb1 << "); (" << xb2 << ", " << yb2 << ")]";
+ QTest::addRow("%s", str.toLatin1().constData())
+ << xa1 << ya1 << xa2 << ya2 << xb1 << yb1 << xb2 << yb2
+ << result << floatResult << mixedResult;
+ };
+
+ row(-1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, true, true, true);
+ row(-1.1, -0.9, 1.1, 0.9, -1.0, -1.0, 1.0, 1.0, true, false, false);
+ row(-1.0, -1.0, 1.0, 1.0, -0.9, -1.1, 0.9, 1.1, true, false, true);
+ row(-qreal_min, -1.0, 1.0, qreal_min, 0.0, -1.1, 0.9, 0.0, true, false, true);
+}
+
+void tst_QLine::testComparison()
+{
+ QFETCH(double, xa1);
+ QFETCH(double, ya1);
+ QFETCH(double, xa2);
+ QFETCH(double, ya2);
+ QFETCH(double, xb1);
+ QFETCH(double, yb1);
+ QFETCH(double, xb2);
+ QFETCH(double, yb2);
+ QFETCH(bool, result);
+ QFETCH(bool, floatResult);
+ QFETCH(bool, mixedResult);
+
+ const QLineF l1f(xa1, ya1, xa2, ya2);
+ const QLine l1 = l1f.toLine();
+
+ const QLineF l2f(xb1, yb1, xb2, yb2);
+ const QLine l2 = l2f.toLine();
+
+ QT_TEST_EQUALITY_OPS(l1, l2, result);
+ QT_TEST_EQUALITY_OPS(l1f, l2f, floatResult);
+ QT_TEST_EQUALITY_OPS(l1f, l2, mixedResult);
+}
+
+void tst_QLine::testFuzzyCompare_data()
+{
+ testComparison_data();
+}
+
+void tst_QLine::testFuzzyCompare()
+{
+ QFETCH(double, xa1);
+ QFETCH(double, ya1);
+ QFETCH(double, xa2);
+ QFETCH(double, ya2);
+ QFETCH(double, xb1);
+ QFETCH(double, yb1);
+ QFETCH(double, xb2);
+ QFETCH(double, yb2);
+ QFETCH(bool, floatResult);
+
+ const QLineF l1f(xa1, ya1, xa2, ya2);
+ const QLineF l2f(xb1, yb1, xb2, yb2);
+
+ QCOMPARE_EQ(qFuzzyCompare(l1f, l2f), floatResult);
+}
+
+void tst_QLine::testIsNull_data()
+{
+ QTest::addColumn<QLineF>("lineF");
+ QTest::addColumn<bool>("result");
+ QTest::addColumn<bool>("floatResult");
+
+ QTest::newRow("non-null") << QLineF(1.0, 1.0, 2.0, 2.0) << false << false;
+ QTest::newRow("null") << QLineF(1.0, 1.0, 1.0, 1.0) << true << true;
+ QTest::newRow("null_int_non-null_float") << QLineF(1.0, 1.0, 1.1, 1.1) << true << false;
+ QTest::newRow("with_qreal_min") << QLineF(-qreal_min, qreal_min, 0.0, 0.0) << true << true;
+}
+
+void tst_QLine::testIsNull()
+{
+ QFETCH(QLineF, lineF);
+ QFETCH(bool, result);
+ QFETCH(bool, floatResult);
+
+ const QLine line = lineF.toLine();
+
+ QCOMPARE_EQ(line.isNull(), result);
+ QCOMPARE_EQ(lineF.isNull(), floatResult);
+ QCOMPARE_EQ(qFuzzyIsNull(lineF), floatResult);
+}
void tst_QLine::testSet()
{
diff --git a/tests/auto/corelib/tools/qmargins/CMakeLists.txt b/tests/auto/corelib/tools/qmargins/CMakeLists.txt
index 2e0ea797ff..b0adf63f40 100644
--- a/tests/auto/corelib/tools/qmargins/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qmargins/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qmargins
SOURCES
tst_qmargins.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp b/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp
index 2611f62f01..dc0b0e4085 100644
--- a/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp
+++ b/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp
@@ -32,15 +32,28 @@ CHECK(const &&);
#include <QTest>
#include <qmargins.h>
+#include <private/qcomparisontesthelper_p.h>
#include <array>
Q_DECLARE_METATYPE(QMargins)
+constexpr static qreal qreal_min = std::numeric_limits<qreal>::min();
+
class tst_QMargins : public QObject
{
Q_OBJECT
private slots:
+ void comparisonCompiles();
+ void comparison_data();
+ void comparison();
+
+ void fuzzyComparison_data();
+ void fuzzyComparison();
+
+ void isNull_data();
+ void isNull();
+
void getSetCheck();
#ifndef QT_NO_DATASTREAM
void dataStreamCheck();
@@ -65,6 +78,92 @@ private slots:
void toMarginsF();
};
+void tst_QMargins::comparisonCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QMargins>();
+ QTestPrivate::testEqualityOperatorsCompile<QMarginsF>();
+ QTestPrivate::testEqualityOperatorsCompile<QMarginsF, QMargins>();
+}
+
+void tst_QMargins::comparison_data()
+{
+ QTest::addColumn<QMarginsF>("lhs");
+ QTest::addColumn<QMarginsF>("rhs");
+ QTest::addColumn<bool>("result");
+ QTest::addColumn<bool>("floatResult");
+ QTest::addColumn<bool>("mixedResult");
+
+ auto row = [](const QMarginsF &lhs, const QMarginsF &rhs, bool res, bool fRes, bool mRes) {
+ QString str;
+ QDebug dbg(&str);
+ dbg.nospace() << "(" << lhs.left() << ", " << lhs.top() << ", " << lhs.right() << ", "
+ << lhs.bottom() << ") vs (" << rhs.left() << ", " << rhs.top() << ", "
+ << rhs.right() << ", " << rhs.bottom() << ")";
+ QTest::addRow("%s", str.toLatin1().constData()) << lhs << rhs << res << fRes << mRes;
+ };
+
+ row(QMarginsF(0.0, 0.0, 0.0, 0.0), QMarginsF(0.0, 0.0, 0.0, 0.0), true, true, true);
+ row(QMarginsF(qreal_min, -qreal_min, -qreal_min, qreal_min), QMarginsF(0.0, 0.0, 0.0, 0.0), true, true, true);
+ row(QMarginsF(1.0, 2.0, 3.0, 4.0), QMarginsF(1.1, 2.1, 2.9, 3.9), true, false, true);
+ row(QMarginsF(1.5, 2.5, 3.0, 4.0), QMarginsF(1.1, 2.1, 2.9, 3.9), false, false, false);
+}
+
+void tst_QMargins::comparison()
+{
+ QFETCH(const QMarginsF, lhs);
+ QFETCH(const QMarginsF, rhs);
+ QFETCH(const bool, result);
+ QFETCH(const bool, floatResult);
+ QFETCH(const bool, mixedResult);
+
+ QT_TEST_EQUALITY_OPS(lhs, rhs, floatResult);
+
+ const QMargins lhsInt = lhs.toMargins();
+ const QMargins rhsInt = rhs.toMargins();
+ QT_TEST_EQUALITY_OPS(lhsInt, rhsInt, result);
+
+ QT_TEST_EQUALITY_OPS(lhs, rhsInt, mixedResult);
+}
+
+void tst_QMargins::fuzzyComparison_data()
+{
+ comparison_data();
+}
+
+void tst_QMargins::fuzzyComparison()
+{
+ QFETCH(const QMarginsF, lhs);
+ QFETCH(const QMarginsF, rhs);
+ QFETCH(const bool, floatResult);
+
+ QCOMPARE_EQ(qFuzzyCompare(lhs, rhs), floatResult);
+}
+
+void tst_QMargins::isNull_data()
+{
+ QTest::addColumn<QMarginsF>("margins");
+ QTest::addColumn<bool>("result");
+
+ QTest::newRow("null") << QMarginsF(0.0, 0.0, 0.0, 0.0) << true;
+ QTest::newRow("non_null_left") << QMarginsF(1.0, 0.0, 0.0, 0.0) << false;
+ QTest::newRow("non_null_top") << QMarginsF(0.0, 0.5, 0.0, 0.0) << false;
+ QTest::newRow("non_null_right") << QMarginsF(0.0, 0.0, -2.0, 0.0) << false;
+ QTest::newRow("non_null_bottom") << QMarginsF(0.0, 0.0, 0.0, -0.6) << false;
+ QTest::newRow("almost_null") << QMarginsF(qreal_min, -qreal_min, qreal_min, -qreal_min) << true;
+}
+
+void tst_QMargins::isNull()
+{
+ QFETCH(const QMarginsF, margins);
+ QFETCH(const bool, result);
+
+ QCOMPARE_EQ(margins.isNull(), result);
+ QCOMPARE_EQ(qFuzzyIsNull(margins), result);
+
+ const QMargins marginsInt = margins.toMargins();
+ QCOMPARE_EQ(marginsInt.isNull(), result);
+}
+
// Testing get/set functions
void tst_QMargins::getSetCheck()
{
diff --git a/tests/auto/corelib/tools/qpoint/CMakeLists.txt b/tests/auto/corelib/tools/qpoint/CMakeLists.txt
index f1402d8815..82ece1fc15 100644
--- a/tests/auto/corelib/tools/qpoint/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qpoint/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qpoint
SOURCES
tst_qpoint.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp b/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp
index 7fea787131..4763c1bf07 100644
--- a/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp
+++ b/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp
@@ -5,6 +5,7 @@
#ifdef QVARIANT_H
# error "This test requires qpoint.h to not include qvariant.h"
#endif
+#include <private/qcomparisontesthelper_p.h>
// don't assume <type_traits>
template <typename T, typename U>
@@ -71,6 +72,7 @@ private slots:
void operator_unary_minus_data();
void operator_unary_minus();
+ void operatorsCompile();
void operator_eq_data();
void operator_eq();
@@ -155,6 +157,8 @@ void tst_QPoint::toPointF()
QFETCH(const QPointF, result);
QCOMPARE(input.toPointF(), result);
+ // test also mixed-type comparison
+ QT_TEST_EQUALITY_OPS(input, result, true);
}
void tst_QPoint::transposed()
@@ -350,6 +354,12 @@ void tst_QPoint::operator_unary_minus()
QCOMPARE(-point, expected);
}
+void tst_QPoint::operatorsCompile()
+{
+ // Mixed-type comparison is tested in tst_QPointF.
+ QTestPrivate::testEqualityOperatorsCompile<QPoint>();
+}
+
void tst_QPoint::operator_eq_data()
{
QTest::addColumn<QPoint>("point1");
@@ -371,12 +381,9 @@ void tst_QPoint::operator_eq()
QFETCH(QPoint, point2);
QFETCH(bool, expectEqual);
- bool equal = point1 == point2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = point1 != point2;
- QCOMPARE(notEqual, !expectEqual);
+ QT_TEST_EQUALITY_OPS(point1, point2, expectEqual);
- if (equal)
+ if (expectEqual)
QCOMPARE(qHash(point1), qHash(point2));
}
diff --git a/tests/auto/corelib/tools/qpointf/CMakeLists.txt b/tests/auto/corelib/tools/qpointf/CMakeLists.txt
index 16e5a9036a..28cbe185b2 100644
--- a/tests/auto/corelib/tools/qpointf/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qpointf/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qpointf
SOURCES
tst_qpointf.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp b/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp
index 392c22c70a..ebbac4ec7c 100644
--- a/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp
+++ b/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp
@@ -5,6 +5,7 @@
#ifdef QVARIANT_H
# error "This test requires qpoint.h to not include qvariant.h"
#endif
+#include <private/qcomparisontesthelper_p.h>
// don't assume <type_traits>
template <typename T, typename U>
@@ -71,9 +72,13 @@ private slots:
void operator_unary_minus_data();
void operator_unary_minus();
+ void operatorsCompile();
void operator_eq_data();
void operator_eq();
+ void fuzzyCompare_data();
+ void fuzzyCompare();
+
void toPoint_data();
void toPoint();
@@ -101,15 +106,19 @@ void tst_QPointF::isNull()
{
QPointF point(0, 0);
QVERIFY(point.isNull());
+ QVERIFY(qFuzzyIsNull(point));
++point.rx();
QVERIFY(!point.isNull());
+ QVERIFY(!qFuzzyIsNull(point));
point.rx() -= 2;
QVERIFY(!point.isNull());
+ QVERIFY(!qFuzzyIsNull(point));
QPointF nullNegativeZero(qreal(-0.0), qreal(-0.0));
QCOMPARE(nullNegativeZero.x(), (qreal)-0.0f);
QCOMPARE(nullNegativeZero.y(), (qreal)-0.0f);
QVERIFY(nullNegativeZero.isNull());
+ QVERIFY(qFuzzyIsNull(nullNegativeZero));
}
void tst_QPointF::manhattanLength_data()
@@ -345,21 +354,29 @@ void tst_QPointF::operator_unary_minus()
QCOMPARE(-point, expected);
}
+void tst_QPointF::operatorsCompile()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QPointF>();
+ QTestPrivate::testEqualityOperatorsCompile<QPointF, QPoint>();
+}
+
void tst_QPointF::operator_eq_data()
{
QTest::addColumn<QPointF>("point1");
QTest::addColumn<QPointF>("point2");
QTest::addColumn<bool>("expectEqual");
-
- QTest::newRow("(0, 0) == (0, 0)") << QPointF(0, 0) << QPointF(0, 0) << true;
- QTest::newRow("(-1, 0) == (-1, 0)") << QPointF(-1, 0) << QPointF(-1, 0) << true;
- QTest::newRow("(-1, 0) != (0, 0)") << QPointF(-1, 0) << QPointF(0, 0) << false;
- QTest::newRow("(-1, 0) != (0, -1)") << QPointF(-1, 0) << QPointF(0, -1) << false;
- QTest::newRow("(-1.125, 0.25) == (-1.125, 0.25)") << QPointF(-1.125, 0.25) << QPointF(-1.125, 0.25) << true;
+ QTest::addColumn<bool>("expectIntEqual");
+
+ QTest::newRow("(0, 0) == (0, 0)") << QPointF(0, 0) << QPointF(0, 0) << true << true;
+ QTest::newRow("(-1, 0) == (-1, 0)") << QPointF(-1, 0) << QPointF(-1, 0) << true << true;
+ QTest::newRow("(-1, 0) != (0, 0)") << QPointF(-1, 0) << QPointF(0, 0) << false << false;
+ QTest::newRow("(-1, 0) != (0, -1)") << QPointF(-1, 0) << QPointF(0, -1) << false << false;
+ QTest::newRow("(-1.125, 0.25) == (-1.125, 0.25)")
+ << QPointF(-1.125, 0.25) << QPointF(-1.125, 0.25) << true << false;
QTest::newRow("(QREAL_MIN, QREAL_MIN) == (QREAL_MIN, QREAL_MIN)")
- << QPointF(QREAL_MIN, QREAL_MIN) << QPointF(QREAL_MIN, QREAL_MIN) << true;
+ << QPointF(QREAL_MIN, QREAL_MIN) << QPointF(QREAL_MIN, QREAL_MIN) << true << true;
QTest::newRow("(QREAL_MAX, QREAL_MAX) == (QREAL_MAX, QREAL_MAX)")
- << QPointF(QREAL_MAX, QREAL_MAX) << QPointF(QREAL_MAX, QREAL_MAX) << true;
+ << QPointF(QREAL_MAX, QREAL_MAX) << QPointF(QREAL_MAX, QREAL_MAX) << true << false;
}
void tst_QPointF::operator_eq()
@@ -367,11 +384,26 @@ void tst_QPointF::operator_eq()
QFETCH(QPointF, point1);
QFETCH(QPointF, point2);
QFETCH(bool, expectEqual);
+ QFETCH(bool, expectIntEqual);
+
+ QT_TEST_EQUALITY_OPS(point1, point2, expectEqual);
+
+ const QPoint intPoint2 = point2.toPoint();
+ QT_TEST_EQUALITY_OPS(point1, intPoint2, expectIntEqual);
+}
+
+void tst_QPointF::fuzzyCompare_data()
+{
+ operator_eq_data();
+}
+
+void tst_QPointF::fuzzyCompare()
+{
+ QFETCH(QPointF, point1);
+ QFETCH(QPointF, point2);
+ QFETCH(bool, expectEqual);
- bool equal = point1 == point2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = point1 != point2;
- QCOMPARE(notEqual, !expectEqual);
+ QCOMPARE_EQ(qFuzzyCompare(point1, point2), expectEqual);
}
void tst_QPointF::toPoint_data()
diff --git a/tests/auto/corelib/tools/qrect/CMakeLists.txt b/tests/auto/corelib/tools/qrect/CMakeLists.txt
index a02e1c33a5..c98c836379 100644
--- a/tests/auto/corelib/tools/qrect/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qrect/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qrect
SOURCES
tst_qrect.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qrect/tst_qrect.cpp b/tests/auto/corelib/tools/qrect/tst_qrect.cpp
index 0f3dd1a0ef..c7c8b3a560 100644
--- a/tests/auto/corelib/tools/qrect/tst_qrect.cpp
+++ b/tests/auto/corelib/tools/qrect/tst_qrect.cpp
@@ -7,6 +7,8 @@
#include <limits.h>
#include <qdebug.h>
+#include <private/qcomparisontesthelper_p.h>
+
#include <array>
class tst_QRect : public QObject
@@ -33,8 +35,14 @@ public:
static QPoint getQPointCase( QPointCases p );
private slots:
+ void comparisonCompiles();
+ void comparison_data();
+ void comparison();
+ void fuzzyComparison_data();
+ void fuzzyComparison();
void isNull_data();
void isNull();
+ void fuzzyIsNull();
void newIsEmpty_data();
void newIsEmpty();
void newIsValid_data();
@@ -160,6 +168,8 @@ private slots:
#define LARGE 1000000000
static bool isLarge(int x) { return x > LARGE || x < -LARGE; }
+static constexpr qreal qreal_min = std::numeric_limits<qreal>::min();
+
QRect tst_QRect::getQRectCase( QRectCases c )
{
// Should return the best variety of possible QRects, if a
@@ -242,6 +252,80 @@ QPoint tst_QRect::getQPointCase( QPointCases p )
}
}
+void tst_QRect::comparisonCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QRect>();
+ QTestPrivate::testEqualityOperatorsCompile<QRectF>();
+ QTestPrivate::testEqualityOperatorsCompile<QRectF, QRect>();
+}
+
+void tst_QRect::comparison_data()
+{
+ QTest::addColumn<QRectF>("lhsF");
+ QTest::addColumn<QRectF>("rhsF");
+ QTest::addColumn<bool>("result");
+ QTest::addColumn<bool>("floatResult");
+ QTest::addColumn<bool>("mixedResult");
+
+ QTest::newRow("Invalid_vs_Invalid") << getQRectCase(InvalidQRect).toRectF()
+ << getQRectCase(InvalidQRect).toRectF()
+ << true << true << true;
+
+ QTest::newRow("Null_vs_Null") << getQRectCase(NullQRect).toRectF()
+ << getQRectCase(NullQRect).toRectF()
+ << true << true << true;
+
+ QTest::newRow("Empty_vs_Empty") << getQRectCase(EmptyQRect).toRectF()
+ << getQRectCase(EmptyQRect).toRectF()
+ << true << true << true;
+
+ QTest::newRow("NegativeSize_vs_NegativeSize") << getQRectCase(NegativeSizeQRect).toRectF()
+ << getQRectCase(NegativeSizeQRect).toRectF()
+ << true << true << true;
+
+ QTest::newRow("Invalid_vs_Null") << getQRectCase(InvalidQRect).toRectF()
+ << getQRectCase(NullQRect).toRectF()
+ << false << false << false;
+
+ QTest::newRow("NearlySimilar") << QRectF(QPointF(1.1, 9.9), QPointF(9.9, 1.1))
+ << QRectF(QPointF(1., 10.), QPointF(10., 1.))
+ << true << false << true;
+
+ QTest::newRow("WithQREAL_MIN") << QRectF(QPointF(0., -10.), QPointF(-1., 0.))
+ << QRectF(QPointF(-qreal_min, -10.), QPointF(-1., qreal_min))
+ << true << true << true;
+}
+
+void tst_QRect::comparison()
+{
+ QFETCH(const QRectF, lhsF);
+ QFETCH(const QRectF, rhsF);
+ QFETCH(const bool, result);
+ QFETCH(const bool, floatResult);
+ QFETCH(const bool, mixedResult);
+
+ const QRect lhs = lhsF.toRect();
+ const QRect rhs = rhsF.toRect();
+
+ QT_TEST_EQUALITY_OPS(lhs, rhs, result);
+ QT_TEST_EQUALITY_OPS(lhsF, rhsF, floatResult);
+ QT_TEST_EQUALITY_OPS(lhs, rhsF, mixedResult);
+}
+
+void tst_QRect::fuzzyComparison_data()
+{
+ comparison_data();
+}
+
+void tst_QRect::fuzzyComparison()
+{
+ QFETCH(const QRectF, lhsF);
+ QFETCH(const QRectF, rhsF);
+ QFETCH(const bool, floatResult);
+
+ QCOMPARE_EQ(qFuzzyCompare(lhsF, rhsF), floatResult);
+}
+
void tst_QRect::isNull_data()
{
QTest::addColumn<QRect>("r");
@@ -271,6 +355,14 @@ void tst_QRect::isNull()
QVERIFY( rf.isNull() == isNull );
}
+void tst_QRect::fuzzyIsNull()
+{
+ QRectF rf(QPointF(-qreal_min, qreal_min), QPointF(qreal_min, -qreal_min));
+
+ QVERIFY(!rf.isNull()); // QRectF::isNull() does strict comparison
+ QVERIFY(qFuzzyIsNull(rf));
+}
+
void tst_QRect::newIsEmpty_data()
{
QTest::addColumn<QRect>("r");
diff --git a/tests/auto/corelib/tools/qsize/CMakeLists.txt b/tests/auto/corelib/tools/qsize/CMakeLists.txt
index 91de696ddd..4a4c96b52c 100644
--- a/tests/auto/corelib/tools/qsize/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qsize/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qsize
SOURCES
tst_qsize.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qsize/tst_qsize.cpp b/tests/auto/corelib/tools/qsize/tst_qsize.cpp
index c9699c5e76..d379275dd8 100644
--- a/tests/auto/corelib/tools/qsize/tst_qsize.cpp
+++ b/tests/auto/corelib/tools/qsize/tst_qsize.cpp
@@ -24,6 +24,7 @@ CHECK(const &&);
#undef CHECK
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <qsize.h>
#include <array>
@@ -34,6 +35,10 @@ class tst_QSize : public QObject
{
Q_OBJECT
private slots:
+ void compareCompiles();
+ void compare_data();
+ void compare();
+
void getSetCheck();
void scale();
@@ -55,6 +60,38 @@ private slots:
void structuredBinding();
};
+void tst_QSize::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QSize>();
+}
+
+void tst_QSize::compare_data()
+{
+ QTest::addColumn<QSize>("lhs");
+ QTest::addColumn<QSize>("rhs");
+ QTest::addColumn<bool>("result");
+
+ auto row = [](QSize lhs, QSize rhs, bool res) {
+ QTest::addRow("(%d, %d) vs (%d, %d)", lhs.width(), lhs.height(), rhs.width(), rhs.height())
+ << lhs << rhs << res;
+ };
+
+ row(QSize(0, 0), QSize(0, 0), true);
+ row(QSize(1, 0), QSize(0, 1), false);
+ row(QSize(-1, -1), QSize(-1, -1), true);
+ row(QSize(-1, -1), QSize(1, 1), false);
+ row(QSize(INT_MIN, INT_MAX), QSize(INT_MAX, INT_MIN), false);
+}
+
+void tst_QSize::compare()
+{
+ QFETCH(QSize, lhs);
+ QFETCH(QSize, rhs);
+ QFETCH(bool, result);
+
+ QT_TEST_EQUALITY_OPS(lhs, rhs, result);
+}
+
// Testing get/set functions
void tst_QSize::getSetCheck()
{
diff --git a/tests/auto/corelib/tools/qsizef/CMakeLists.txt b/tests/auto/corelib/tools/qsizef/CMakeLists.txt
index 9adaafe2ea..d8a1c7f46e 100644
--- a/tests/auto/corelib/tools/qsizef/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qsizef/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qsizef
SOURCES
tst_qsizef.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp
index ee33fa13b6..bb087e89de 100644
--- a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp
+++ b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp
@@ -24,17 +24,30 @@ CHECK(const &&);
#undef CHECK
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <qsize.h>
Q_DECLARE_METATYPE(QMarginsF)
+static constexpr qreal qreal_min = std::numeric_limits<qreal>::min();
+
class tst_QSizeF : public QObject
{
Q_OBJECT
private slots:
+ void compareCompiles();
+ void compare_data();
+ void compare();
+
+ void fuzzyCompare_data();
+ void fuzzyCompare();
+
void isNull_data();
void isNull();
+ void fuzzyIsNull_data();
+ void fuzzyIsNull();
+
void scale();
void expandedTo();
@@ -52,6 +65,61 @@ private slots:
void structuredBinding();
};
+void tst_QSizeF::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QSizeF>();
+ QTestPrivate::testEqualityOperatorsCompile<QSizeF, QSize>();
+}
+
+void tst_QSizeF::compare_data()
+{
+ QTest::addColumn<QSizeF>("lhs");
+ QTest::addColumn<QSizeF>("rhs");
+ QTest::addColumn<bool>("result");
+ QTest::addColumn<bool>("mixedResult");
+
+ auto row = [&](QSizeF lhs, QSizeF rhs, bool res, bool mixedRes) {
+ QString str;
+ QDebug dbg(&str);
+ dbg.nospace() << "(" << lhs.width() << ", " << lhs.height() << ") vs "
+ << "(" << rhs.width() << ", " << rhs.height() << ")";
+ QTest::addRow("%s", str.toLatin1().constData()) << lhs << rhs << res << mixedRes;
+ };
+
+ row(QSizeF(0.0, 0.0), QSizeF(0.0, 0.0), true, true);
+ row(QSizeF(1.0, 2.0), QSizeF(1.0, 2.0), true, true);
+ row(QSizeF(1.0, -1.0), QSizeF(-1.0, 1.0), false, false);
+ row(QSizeF(0.1, 1.1), QSizeF(0.1, 1.1), true, false);
+ row(QSizeF(qreal_min, 0.0), QSizeF(0.0, -qreal_min), true, true);
+}
+
+void tst_QSizeF::compare()
+{
+ QFETCH(QSizeF, lhs);
+ QFETCH(QSizeF, rhs);
+ QFETCH(bool, result);
+ QFETCH(bool, mixedResult);
+
+ QT_TEST_EQUALITY_OPS(lhs, rhs, result);
+
+ const QSize rhsFixed = rhs.toSize();
+ QT_TEST_EQUALITY_OPS(lhs, rhsFixed, mixedResult);
+}
+
+void tst_QSizeF::fuzzyCompare_data()
+{
+ compare_data();
+}
+
+void tst_QSizeF::fuzzyCompare()
+{
+ QFETCH(QSizeF, lhs);
+ QFETCH(QSizeF, rhs);
+ QFETCH(bool, result);
+
+ QCOMPARE_EQ(qFuzzyCompare(lhs, rhs), result);
+}
+
void tst_QSizeF::isNull_data()
{
QTest::addColumn<qreal>("width");
@@ -66,6 +134,7 @@ void tst_QSizeF::isNull_data()
QTest::newRow("0, -0.1") << qreal(0) << qreal(-0.1) << false;
QTest::newRow("0.1, 0") << qreal(0.1) << qreal(0) << false;
QTest::newRow("0, 0.1") << qreal(0) << qreal(0.1) << false;
+ QTest::newRow("qreal_min, -qreal_min") << qreal_min << -qreal_min << false;
}
void tst_QSizeF::isNull()
@@ -80,6 +149,33 @@ void tst_QSizeF::isNull()
QCOMPARE(size.isNull(), isNull);
}
+void tst_QSizeF::fuzzyIsNull_data()
+{
+ QTest::addColumn<qreal>("width");
+ QTest::addColumn<qreal>("height");
+ QTest::addColumn<bool>("fuzzyNull");
+
+ QTest::newRow("0, 0") << qreal(0.0) << qreal(0.0) << true;
+ QTest::newRow("-0, -0") << qreal(-0.0) << qreal(-0.0) << true;
+ QTest::newRow("0, -0") << qreal(0) << qreal(-0.0) << true;
+ QTest::newRow("-0, 0") << qreal(-0.0) << qreal(0) << true;
+ QTest::newRow("-0.1, 0") << qreal(-0.1) << qreal(0) << false;
+ QTest::newRow("0, -0.1") << qreal(0) << qreal(-0.1) << false;
+ QTest::newRow("0.1, 0") << qreal(0.1) << qreal(0) << false;
+ QTest::newRow("0, 0.1") << qreal(0) << qreal(0.1) << false;
+ QTest::newRow("qreal_min, -qreal_min") << qreal_min << -qreal_min << true;
+}
+
+void tst_QSizeF::fuzzyIsNull()
+{
+ QFETCH(qreal, width);
+ QFETCH(qreal, height);
+ QFETCH(bool, fuzzyNull);
+
+ QSizeF size(width, height);
+ QCOMPARE(qFuzzyIsNull(size), fuzzyNull);
+}
+
void tst_QSizeF::scale() {
QSizeF t1(10.4, 12.8);
t1.scale(60.6, 60.6, Qt::IgnoreAspectRatio);
diff --git a/tests/auto/corelib/tools/qversionnumber/CMakeLists.txt b/tests/auto/corelib/tools/qversionnumber/CMakeLists.txt
index 8f6ed66841..5b9fa60c64 100644
--- a/tests/auto/corelib/tools/qversionnumber/CMakeLists.txt
+++ b/tests/auto/corelib/tools/qversionnumber/CMakeLists.txt
@@ -14,6 +14,8 @@ endif()
qt_internal_add_test(tst_qversionnumber
SOURCES
tst_qversionnumber.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
## Scopes:
diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
index da9dcc9366..5ccf56c1d1 100644
--- a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
+++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QtCore/qversionnumber.h>
#include <QtCore/qlibraryinfo.h>
@@ -16,24 +17,15 @@ private:
private slots:
void initTestCase();
+ void compareCompiles();
void constructorDefault();
void constructorVersioned_data();
void constructorVersioned();
void constructorExplicit();
void constructorCopy_data();
void constructorCopy();
- void compareGreater_data();
- void compareGreater();
- void compareGreaterEqual_data();
- void compareGreaterEqual();
- void compareLess_data();
- void compareLess();
- void compareLessEqual_data();
- void compareLessEqual();
- void compareEqual_data();
- void compareEqual();
- void compareNotEqual_data();
- void compareNotEqual();
+ void comparisonOperators_data();
+ void comparisonOperators();
void compare_data();
void compare();
void isPrefixOf_data();
@@ -121,74 +113,69 @@ void tst_QVersionNumber::comparisonData()
{
QTest::addColumn<QVersionNumber>("lhs");
QTest::addColumn<QVersionNumber>("rhs");
- QTest::addColumn<bool>("equal");
- QTest::addColumn<bool>("notEqual");
- QTest::addColumn<bool>("lessThan");
- QTest::addColumn<bool>("lessThanOrEqual");
- QTest::addColumn<bool>("greaterThan");
- QTest::addColumn<bool>("greaterThanOrEqual");
+ QTest::addColumn<Qt::strong_ordering>("ordering");
QTest::addColumn<int>("compareResult");
QTest::addColumn<bool>("isPrefix");
QTest::addColumn<QVersionNumber>("common");
- // LHS RHS == != < <= > >= compareResult isPrefixOf commonPrefix
- QTest::newRow("null, null") << QVersionNumber() << QVersionNumber() << true << false << false << true << false << true << 0 << true << QVersionNumber();
- QTest::newRow("null, 0") << QVersionNumber() << QVersionNumber(0) << false << true << true << true << false << false << -1 << true << QVersionNumber();
- QTest::newRow("0, null") << QVersionNumber(0) << QVersionNumber() << false << true << false << false << true << true << 1 << false << QVersionNumber();
- QTest::newRow("0, 0") << QVersionNumber(0) << QVersionNumber(0) << true << false << false << true << false << true << 0 << true << QVersionNumber(0);
- QTest::newRow("1.0, 1.0") << QVersionNumber(1, 0) << QVersionNumber(1, 0) << true << false << false << true << false << true << 0 << true << QVersionNumber(1, 0);
- QTest::newRow("1, 1.0") << QVersionNumber(1) << QVersionNumber(1, 0) << false << true << true << true << false << false << -1 << true << QVersionNumber(1);
- QTest::newRow("1.0, 1") << QVersionNumber(1, 0) << QVersionNumber(1) << false << true << false << false << true << true << 1 << false << QVersionNumber(1);
-
- QTest::newRow("0.1.2, 0.1") << QVersionNumber(0, 1, 2) << QVersionNumber(0, 1) << false << true << false << false << true << true << 2 << false << QVersionNumber(0, 1);
- QTest::newRow("0.1, 0.1.2") << QVersionNumber(0, 1) << QVersionNumber(0, 1, 2) << false << true << true << true << false << false << -2 << true << QVersionNumber(0, 1);
- QTest::newRow("0.1.2, 0.1.2") << QVersionNumber(0, 1, 2) << QVersionNumber(0, 1, 2) << true << false << false << true << false << true << 0 << true << QVersionNumber(0, 1, 2);
- QTest::newRow("0.1.2, 1.1.2") << QVersionNumber(0, 1, 2) << QVersionNumber(1, 1, 2) << false << true << true << true << false << false << -1 << false << QVersionNumber();
- QTest::newRow("1.1.2, 0.1.2") << QVersionNumber(1, 1, 2) << QVersionNumber(0, 1, 2) << false << true << false << false << true << true << 1 << false << QVersionNumber();
- QTest::newRow("1, -1") << QVersionNumber(1) << QVersionNumber(-1) << false << true << false << false << true << true << 2 << false << QVersionNumber();
- QTest::newRow("-1, 1") << QVersionNumber(-1) << QVersionNumber(1) << false << true << true << true << false << false << -2 << false << QVersionNumber();
- QTest::newRow("0.1, 0.-1") << QVersionNumber(0, 1) << QVersionNumber(0, -1) << false << true << false << false << true << true << 2 << false << QVersionNumber(0);
- QTest::newRow("0.-1, 0.1") << QVersionNumber(0, -1) << QVersionNumber(0, 1) << false << true << true << true << false << false << -2 << false << QVersionNumber(0);
- QTest::newRow("0.-1, 0") << QVersionNumber(0, -1) << QVersionNumber(0) << false << true << true << true << false << false << -1 << false << QVersionNumber(0);
- QTest::newRow("0, 0.-1") << QVersionNumber(0) << QVersionNumber(0, -1) << false << true << false << false << true << true << 1 << true << QVersionNumber(0);
-
- QTest::newRow("0.127.2, 0.127") << QVersionNumber(0, 127, 2) << QVersionNumber(0, 127) << false << true << false << false << true << true << 2 << false << QVersionNumber(0, 127);
- QTest::newRow("0.127, 0.127.2") << QVersionNumber(0, 127) << QVersionNumber(0, 127, 2) << false << true << true << true << false << false << -2 << true << QVersionNumber(0, 127);
- QTest::newRow("0.127.2, 0.127.2") << QVersionNumber(0, 127, 2) << QVersionNumber(0, 127, 2) << true << false << false << true << false << true << 0 << true << QVersionNumber(0, 127, 2);
- QTest::newRow("0.127.2, 127.127.2") << QVersionNumber(0, 127, 2) << QVersionNumber(127, 127, 2) << false << true << true << true << false << false << -127 << false << QVersionNumber();
- QTest::newRow("127.127.2, 0.127.2") << QVersionNumber(127, 127, 2) << QVersionNumber(0, 127, 2) << false << true << false << false << true << true << 127 << false << QVersionNumber();
- QTest::newRow("127, -128") << QVersionNumber(127) << QVersionNumber(-128) << false << true << false << false << true << true << 255 << false << QVersionNumber();
- QTest::newRow("-128, 127") << QVersionNumber(-128) << QVersionNumber(127) << false << true << true << true << false << false << -255 << false << QVersionNumber();
- QTest::newRow("0.127, 0.-128") << QVersionNumber(0, 127) << QVersionNumber(0, -128) << false << true << false << false << true << true << 255 << false << QVersionNumber(0);
- QTest::newRow("0.-128, 0.127") << QVersionNumber(0, -128) << QVersionNumber(0, 127) << false << true << true << true << false << false << -255 << false << QVersionNumber(0);
- QTest::newRow("0.-128, 0") << QVersionNumber(0, -128) << QVersionNumber(0) << false << true << true << true << false << false << -128 << false << QVersionNumber(0);
- QTest::newRow("0, 0.-128") << QVersionNumber(0) << QVersionNumber(0, -128) << false << true << false << false << true << true << 128 << true << QVersionNumber(0);
-
- QTest::newRow("0.128.2, 0.128") << QVersionNumber(0, 128, 2) << QVersionNumber(0, 128) << false << true << false << false << true << true << 2 << false << QVersionNumber(0, 128);
- QTest::newRow("0.128, 0.128.2") << QVersionNumber(0, 128) << QVersionNumber(0, 128, 2) << false << true << true << true << false << false << -2 << true << QVersionNumber(0, 128);
- QTest::newRow("0.128.2, 0.128.2") << QVersionNumber(0, 128, 2) << QVersionNumber(0, 128, 2) << true << false << false << true << false << true << 0 << true << QVersionNumber(0, 128, 2);
- QTest::newRow("0.128.2, 128.128.2") << QVersionNumber(0, 128, 2) << QVersionNumber(128, 128, 2) << false << true << true << true << false << false << -128 << false << QVersionNumber();
- QTest::newRow("128.128.2, 0.128.2") << QVersionNumber(128, 128, 2) << QVersionNumber(0, 128, 2) << false << true << false << false << true << true << 128 << false << QVersionNumber();
- QTest::newRow("128, -129") << QVersionNumber(128) << QVersionNumber(-129) << false << true << false << false << true << true << 257 << false << QVersionNumber();
- QTest::newRow("-129, 128") << QVersionNumber(-129) << QVersionNumber(128) << false << true << true << true << false << false << -257 << false << QVersionNumber();
- QTest::newRow("0.128, 0.-129") << QVersionNumber(0, 128) << QVersionNumber(0, -129) << false << true << false << false << true << true << 257 << false << QVersionNumber(0);
- QTest::newRow("0.-129, 0.128") << QVersionNumber(0, -129) << QVersionNumber(0, 128) << false << true << true << true << false << false << -257 << false << QVersionNumber(0);
- QTest::newRow("0.-129, 0") << QVersionNumber(0, -129) << QVersionNumber(0) << false << true << true << true << false << false << -129 << false << QVersionNumber(0);
- QTest::newRow("0, 0.-129") << QVersionNumber(0) << QVersionNumber(0, -129) << false << true << false << false << true << true << 129 << true << QVersionNumber(0);
+ // LHS RHS ordering compareResult isPrefixOf commonPrefix
+ QTest::newRow("null, null") << QVersionNumber() << QVersionNumber() << Qt::strong_ordering::equal << 0 << true << QVersionNumber();
+ QTest::newRow("null, 0") << QVersionNumber() << QVersionNumber(0) << Qt::strong_ordering::less << -1 << true << QVersionNumber();
+ QTest::newRow("0, null") << QVersionNumber(0) << QVersionNumber() << Qt::strong_ordering::greater << 1 << false << QVersionNumber();
+ QTest::newRow("0, 0") << QVersionNumber(0) << QVersionNumber(0) << Qt::strong_ordering::equal << 0 << true << QVersionNumber(0);
+ QTest::newRow("1.0, 1.0") << QVersionNumber(1, 0) << QVersionNumber(1, 0) << Qt::strong_ordering::equal << 0 << true << QVersionNumber(1, 0);
+ QTest::newRow("1, 1.0") << QVersionNumber(1) << QVersionNumber(1, 0) << Qt::strong_ordering::less << -1 << true << QVersionNumber(1);
+ QTest::newRow("1.0, 1") << QVersionNumber(1, 0) << QVersionNumber(1) << Qt::strong_ordering::greater << 1 << false << QVersionNumber(1);
+
+ QTest::newRow("0.1.2, 0.1") << QVersionNumber(0, 1, 2) << QVersionNumber(0, 1) << Qt::strong_ordering::greater << 2 << false << QVersionNumber(0, 1);
+ QTest::newRow("0.1, 0.1.2") << QVersionNumber(0, 1) << QVersionNumber(0, 1, 2) << Qt::strong_ordering::less << -2 << true << QVersionNumber(0, 1);
+ QTest::newRow("0.1.2, 0.1.2") << QVersionNumber(0, 1, 2) << QVersionNumber(0, 1, 2) << Qt::strong_ordering::equal << 0 << true << QVersionNumber(0, 1, 2);
+ QTest::newRow("0.1.2, 1.1.2") << QVersionNumber(0, 1, 2) << QVersionNumber(1, 1, 2) << Qt::strong_ordering::less << -1 << false << QVersionNumber();
+ QTest::newRow("1.1.2, 0.1.2") << QVersionNumber(1, 1, 2) << QVersionNumber(0, 1, 2) << Qt::strong_ordering::greater << 1 << false << QVersionNumber();
+ QTest::newRow("1, -1") << QVersionNumber(1) << QVersionNumber(-1) << Qt::strong_ordering::greater << 2 << false << QVersionNumber();
+ QTest::newRow("-1, 1") << QVersionNumber(-1) << QVersionNumber(1) << Qt::strong_ordering::less << -2 << false << QVersionNumber();
+ QTest::newRow("0.1, 0.-1") << QVersionNumber(0, 1) << QVersionNumber(0, -1) << Qt::strong_ordering::greater << 2 << false << QVersionNumber(0);
+ QTest::newRow("0.-1, 0.1") << QVersionNumber(0, -1) << QVersionNumber(0, 1) << Qt::strong_ordering::less << -2 << false << QVersionNumber(0);
+ QTest::newRow("0.-1, 0") << QVersionNumber(0, -1) << QVersionNumber(0) << Qt::strong_ordering::less << -1 << false << QVersionNumber(0);
+ QTest::newRow("0, 0.-1") << QVersionNumber(0) << QVersionNumber(0, -1) << Qt::strong_ordering::greater << 1 << true << QVersionNumber(0);
+
+ QTest::newRow("0.127.2, 0.127") << QVersionNumber(0, 127, 2) << QVersionNumber(0, 127) << Qt::strong_ordering::greater << 2 << false << QVersionNumber(0, 127);
+ QTest::newRow("0.127, 0.127.2") << QVersionNumber(0, 127) << QVersionNumber(0, 127, 2) << Qt::strong_ordering::less << -2 << true << QVersionNumber(0, 127);
+ QTest::newRow("0.127.2, 0.127.2") << QVersionNumber(0, 127, 2) << QVersionNumber(0, 127, 2) << Qt::strong_ordering::equal << 0 << true << QVersionNumber(0, 127, 2);
+ QTest::newRow("0.127.2, 127.127.2") << QVersionNumber(0, 127, 2) << QVersionNumber(127, 127, 2) << Qt::strong_ordering::less << -127 << false << QVersionNumber();
+ QTest::newRow("127.127.2, 0.127.2") << QVersionNumber(127, 127, 2) << QVersionNumber(0, 127, 2) << Qt::strong_ordering::greater << 127 << false << QVersionNumber();
+ QTest::newRow("127, -128") << QVersionNumber(127) << QVersionNumber(-128) << Qt::strong_ordering::greater << 255 << false << QVersionNumber();
+ QTest::newRow("-128, 127") << QVersionNumber(-128) << QVersionNumber(127) << Qt::strong_ordering::less << -255 << false << QVersionNumber();
+ QTest::newRow("0.127, 0.-128") << QVersionNumber(0, 127) << QVersionNumber(0, -128) << Qt::strong_ordering::greater << 255 << false << QVersionNumber(0);
+ QTest::newRow("0.-128, 0.127") << QVersionNumber(0, -128) << QVersionNumber(0, 127) << Qt::strong_ordering::less << -255 << false << QVersionNumber(0);
+ QTest::newRow("0.-128, 0") << QVersionNumber(0, -128) << QVersionNumber(0) << Qt::strong_ordering::less << -128 << false << QVersionNumber(0);
+ QTest::newRow("0, 0.-128") << QVersionNumber(0) << QVersionNumber(0, -128) << Qt::strong_ordering::greater << 128 << true << QVersionNumber(0);
+
+ QTest::newRow("0.128.2, 0.128") << QVersionNumber(0, 128, 2) << QVersionNumber(0, 128) << Qt::strong_ordering::greater << 2 << false << QVersionNumber(0, 128);
+ QTest::newRow("0.128, 0.128.2") << QVersionNumber(0, 128) << QVersionNumber(0, 128, 2) << Qt::strong_ordering::less << -2 << true << QVersionNumber(0, 128);
+ QTest::newRow("0.128.2, 0.128.2") << QVersionNumber(0, 128, 2) << QVersionNumber(0, 128, 2) << Qt::strong_ordering::equal << 0 << true << QVersionNumber(0, 128, 2);
+ QTest::newRow("0.128.2, 128.128.2") << QVersionNumber(0, 128, 2) << QVersionNumber(128, 128, 2) << Qt::strong_ordering::less << -128 << false << QVersionNumber();
+ QTest::newRow("128.128.2, 0.128.2") << QVersionNumber(128, 128, 2) << QVersionNumber(0, 128, 2) << Qt::strong_ordering::greater << 128 << false << QVersionNumber();
+ QTest::newRow("128, -129") << QVersionNumber(128) << QVersionNumber(-129) << Qt::strong_ordering::greater << 257 << false << QVersionNumber();
+ QTest::newRow("-129, 128") << QVersionNumber(-129) << QVersionNumber(128) << Qt::strong_ordering::less << -257 << false << QVersionNumber();
+ QTest::newRow("0.128, 0.-129") << QVersionNumber(0, 128) << QVersionNumber(0, -129) << Qt::strong_ordering::greater << 257 << false << QVersionNumber(0);
+ QTest::newRow("0.-129, 0.128") << QVersionNumber(0, -129) << QVersionNumber(0, 128) << Qt::strong_ordering::less << -257 << false << QVersionNumber(0);
+ QTest::newRow("0.-129, 0") << QVersionNumber(0, -129) << QVersionNumber(0) << Qt::strong_ordering::less << -129 << false << QVersionNumber(0);
+ QTest::newRow("0, 0.-129") << QVersionNumber(0) << QVersionNumber(0, -129) << Qt::strong_ordering::greater << 129 << true << QVersionNumber(0);
const QList<int> common = QList<int>({ 0, 1, 2, 3, 4, 5, 6 });
using namespace UglyOperator;
- QTest::newRow("0.1.2.3.4.5.6.0.1.2, 0.1.2.3.4.5.6.0.1") << QVersionNumber(common + 0 + 1 + 2) << QVersionNumber(common + 0 + 1) << false << true << false << false << true << true << 2 << false << QVersionNumber(common + 0 + 1);
- QTest::newRow("0.1.2.3.4.5.6.0.1, 0.1.2.3.4.5.6.0.1.2") << QVersionNumber(common + 0 + 1) << QVersionNumber(common + 0 + 1 + 2) << false << true << true << true << false << false << -2 << true << QVersionNumber(common + 0 + 1);
- QTest::newRow("0.1.2.3.4.5.6.0.1.2, 0.1.2.3.4.5.6.0.1.2") << QVersionNumber(common + 0 + 1 + 2) << QVersionNumber(common + 0 + 1 + 2) << true << false << false << true << false << true << 0 << true << QVersionNumber(common + 0 + 1 + 2);
- QTest::newRow("0.1.2.3.4.5.6.0.1.2, 0.1.2.3.4.5.6.1.1.2") << QVersionNumber(common + 0 + 1 + 2) << QVersionNumber(common + 1 + 1 + 2) << false << true << true << true << false << false << -1 << false << QVersionNumber(common);
- QTest::newRow("0.1.2.3.4.5.6.1.1.2, 0.1.2.3.4.5.6.0.1.2") << QVersionNumber(common + 1 + 1 + 2) << QVersionNumber(common + 0 + 1 + 2) << false << true << false << false << true << true << 1 << false << QVersionNumber(common);
- QTest::newRow("0.1.2.3.4.5.6.1, 0.1.2.3.4.5.6.-1") << QVersionNumber(common + 1) << QVersionNumber(common + -1) << false << true << false << false << true << true << 2 << false << QVersionNumber(common);
- QTest::newRow("0.1.2.3.4.5.6.-1, 0.1.2.3.4.5.6.1") << QVersionNumber(common + -1) << QVersionNumber(common + 1) << false << true << true << true << false << false << -2 << false << QVersionNumber(common);
- QTest::newRow("0.1.2.3.4.5.6.0.1, 0.1.2.3.4.5.6.0.-1") << QVersionNumber(common + 0 + 1) << QVersionNumber(common + 0 + -1) << false << true << false << false << true << true << 2 << false << QVersionNumber(common + 0);
- QTest::newRow("0.1.2.3.4.5.6.0.-1, 0.1.2.3.4.5.6.0.1") << QVersionNumber(common + 0 + -1) << QVersionNumber(common + 0 + 1) << false << true << true << true << false << false << -2 << false << QVersionNumber(common + 0);
- QTest::newRow("0.1.2.3.4.5.6.0.-1, 0.1.2.3.4.5.6.0") << QVersionNumber(common + 0 + -1) << QVersionNumber(common + 0) << false << true << true << true << false << false << -1 << false << QVersionNumber(common + 0);
- QTest::newRow("0.1.2.3.4.5.6.0, 0.1.2.3.4.5.6.0.-1") << QVersionNumber(common + 0) << QVersionNumber(common + 0 + -1) << false << true << false << false << true << true << 1 << true << QVersionNumber(common + 0);
+ QTest::newRow("0.1.2.3.4.5.6.0.1.2, 0.1.2.3.4.5.6.0.1") << QVersionNumber(common + 0 + 1 + 2) << QVersionNumber(common + 0 + 1) << Qt::strong_ordering::greater << 2 << false << QVersionNumber(common + 0 + 1);
+ QTest::newRow("0.1.2.3.4.5.6.0.1, 0.1.2.3.4.5.6.0.1.2") << QVersionNumber(common + 0 + 1) << QVersionNumber(common + 0 + 1 + 2) << Qt::strong_ordering::less << -2 << true << QVersionNumber(common + 0 + 1);
+ QTest::newRow("0.1.2.3.4.5.6.0.1.2, 0.1.2.3.4.5.6.0.1.2") << QVersionNumber(common + 0 + 1 + 2) << QVersionNumber(common + 0 + 1 + 2) << Qt::strong_ordering::equal << 0 << true << QVersionNumber(common + 0 + 1 + 2);
+ QTest::newRow("0.1.2.3.4.5.6.0.1.2, 0.1.2.3.4.5.6.1.1.2") << QVersionNumber(common + 0 + 1 + 2) << QVersionNumber(common + 1 + 1 + 2) << Qt::strong_ordering::less << -1 << false << QVersionNumber(common);
+ QTest::newRow("0.1.2.3.4.5.6.1.1.2, 0.1.2.3.4.5.6.0.1.2") << QVersionNumber(common + 1 + 1 + 2) << QVersionNumber(common + 0 + 1 + 2) << Qt::strong_ordering::greater << 1 << false << QVersionNumber(common);
+ QTest::newRow("0.1.2.3.4.5.6.1, 0.1.2.3.4.5.6.-1") << QVersionNumber(common + 1) << QVersionNumber(common + -1) << Qt::strong_ordering::greater << 2 << false << QVersionNumber(common);
+ QTest::newRow("0.1.2.3.4.5.6.-1, 0.1.2.3.4.5.6.1") << QVersionNumber(common + -1) << QVersionNumber(common + 1) << Qt::strong_ordering::less << -2 << false << QVersionNumber(common);
+ QTest::newRow("0.1.2.3.4.5.6.0.1, 0.1.2.3.4.5.6.0.-1") << QVersionNumber(common + 0 + 1) << QVersionNumber(common + 0 + -1) << Qt::strong_ordering::greater << 2 << false << QVersionNumber(common + 0);
+ QTest::newRow("0.1.2.3.4.5.6.0.-1, 0.1.2.3.4.5.6.0.1") << QVersionNumber(common + 0 + -1) << QVersionNumber(common + 0 + 1) << Qt::strong_ordering::less << -2 << false << QVersionNumber(common + 0);
+ QTest::newRow("0.1.2.3.4.5.6.0.-1, 0.1.2.3.4.5.6.0") << QVersionNumber(common + 0 + -1) << QVersionNumber(common + 0) << Qt::strong_ordering::less << -1 << false << QVersionNumber(common + 0);
+ QTest::newRow("0.1.2.3.4.5.6.0, 0.1.2.3.4.5.6.0.-1") << QVersionNumber(common + 0) << QVersionNumber(common + 0 + -1) << Qt::strong_ordering::greater << 1 << true << QVersionNumber(common + 0);
}
void tst_QVersionNumber::initTestCase()
@@ -196,6 +183,11 @@ void tst_QVersionNumber::initTestCase()
qRegisterMetaType<QList<int>>();
}
+void tst_QVersionNumber::compareCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QVersionNumber>();
+}
+
void tst_QVersionNumber::constructorDefault()
{
QVersionNumber version;
@@ -270,88 +262,18 @@ void tst_QVersionNumber::constructorCopy()
QCOMPARE(version.segments(), expectedVersion.segments());
}
-void tst_QVersionNumber::compareGreater_data()
-{
- comparisonData();
-}
-
-void tst_QVersionNumber::compareGreater()
-{
- QFETCH(QVersionNumber, lhs);
- QFETCH(QVersionNumber, rhs);
- QFETCH(bool, greaterThan);
-
- QCOMPARE(lhs > rhs, greaterThan);
-}
-
-void tst_QVersionNumber::compareGreaterEqual_data()
-{
- comparisonData();
-}
-
-void tst_QVersionNumber::compareGreaterEqual()
-{
- QFETCH(QVersionNumber, lhs);
- QFETCH(QVersionNumber, rhs);
- QFETCH(bool, greaterThanOrEqual);
-
- QCOMPARE(lhs >= rhs, greaterThanOrEqual);
-}
-
-void tst_QVersionNumber::compareLess_data()
-{
- comparisonData();
-}
-
-void tst_QVersionNumber::compareLess()
-{
- QFETCH(QVersionNumber, lhs);
- QFETCH(QVersionNumber, rhs);
- QFETCH(bool, lessThan);
-
- QCOMPARE(lhs < rhs, lessThan);
-}
-
-void tst_QVersionNumber::compareLessEqual_data()
-{
- comparisonData();
-}
-
-void tst_QVersionNumber::compareLessEqual()
-{
- QFETCH(QVersionNumber, lhs);
- QFETCH(QVersionNumber, rhs);
- QFETCH(bool, lessThanOrEqual);
-
- QCOMPARE(lhs <= rhs, lessThanOrEqual);
-}
-
-void tst_QVersionNumber::compareEqual_data()
-{
- comparisonData();
-}
-
-void tst_QVersionNumber::compareEqual()
-{
- QFETCH(QVersionNumber, lhs);
- QFETCH(QVersionNumber, rhs);
- QFETCH(bool, equal);
-
- QCOMPARE(lhs == rhs, equal);
-}
-
-void tst_QVersionNumber::compareNotEqual_data()
+void tst_QVersionNumber::comparisonOperators_data()
{
comparisonData();
}
-void tst_QVersionNumber::compareNotEqual()
+void tst_QVersionNumber::comparisonOperators()
{
QFETCH(QVersionNumber, lhs);
QFETCH(QVersionNumber, rhs);
- QFETCH(bool, notEqual);
+ QFETCH(Qt::strong_ordering, ordering);
- QCOMPARE(lhs != rhs, notEqual);
+ QT_TEST_ALL_COMPARISON_OPS(lhs, rhs, ordering);
}
void tst_QVersionNumber::compare_data()
@@ -394,7 +316,7 @@ void tst_QVersionNumber::commonPrefix()
QFETCH(QVersionNumber, common);
QVersionNumber calculatedPrefix = QVersionNumber::commonPrefix(lhs, rhs);
- QCOMPARE(calculatedPrefix, common);
+ QT_TEST_EQUALITY_OPS(calculatedPrefix, common, true);
QCOMPARE(calculatedPrefix.segments(), common.segments());
}
@@ -530,18 +452,18 @@ void tst_QVersionNumber::fromString_extra()
// when passing explicit nullptr:
{
auto v = QVersionNumber::fromString("1.2.3-rc1", nullptr);
- QCOMPARE(v, QVersionNumber({1, 2, 3}));
+ QT_TEST_EQUALITY_OPS(v, QVersionNumber({1, 2, 3}), true);
}
{
auto v = QVersionNumber::fromString("1.2.3-rc1", 0);
- QCOMPARE(v, QVersionNumber({1, 2, 3}));
+ QT_TEST_EQUALITY_OPS(v, QVersionNumber({1, 2, 3}), true);
}
// check the UTF16->L1 conversion isn't doing something weird
{
qsizetype i = -1;
auto v = QVersionNumber::fromString(u"1.0ı", &i); // LATIN SMALL LETTER DOTLESS I
- QCOMPARE(v, QVersionNumber(1, 0));
+ QT_TEST_EQUALITY_OPS(v, QVersionNumber(1, 0), true);
QCOMPARE(i, 3);
}
}
@@ -652,14 +574,14 @@ void tst_QVersionNumber::moveSemantics()
{
QVersionNumber v1(1, 2, 3);
QVersionNumber v2 = std::move(v1);
- QCOMPARE(v2, QVersionNumber(1, 2, 3));
+ QT_TEST_EQUALITY_OPS(v2, QVersionNumber(1, 2, 3), true);
}
// QVersionNumber &operator=(QVersionNumber &&)
{
QVersionNumber v1(1, 2, 3);
QVersionNumber v2;
v2 = std::move(v1);
- QCOMPARE(v2, QVersionNumber(1, 2, 3));
+ QT_TEST_EQUALITY_OPS(v2, QVersionNumber(1, 2, 3), true);
}
// QVersionNumber(QList<int> &&)
{
@@ -668,7 +590,7 @@ void tst_QVersionNumber::moveSemantics()
QVersionNumber v2(std::move(segments));
QVERIFY(!v1.isNull());
QVERIFY(!v2.isNull());
- QCOMPARE(v1, v2);
+ QT_TEST_EQUALITY_OPS(v1, v2, true);
}
#ifdef Q_COMPILER_REF_QUALIFIERS
// normalized()
diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
index 504d1a4fea..ab750dff33 100644
--- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
+++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
@@ -1422,7 +1422,7 @@ void tst_QDBusConnection::connectionLimit()
QProcess daemon;
daemon.start("dbus-daemon",
- QStringList() << "--config-file" << QFINDTESTDATA("tst_qdbusconnection.conf")
+ QStringList() << "--config-file" << QFINDTESTDATA("../qdbusconnection/tst_qdbusconnection.conf")
<< "--nofork"
<< "--print-address");
QVERIFY2(daemon.waitForReadyRead(2000),
diff --git a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp
index e7a8273115..355a65bc59 100644
--- a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp
+++ b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp
@@ -161,7 +161,9 @@ void basicStringTypes_data()
{
QTest::newRow("string") << QVariant("ping") << "s" << "\"ping\"";
QTest::newRow("objectpath") << QVariant::fromValue(QDBusObjectPath("/org/kde")) << "o" << "[ObjectPath: /org/kde]";
+ QTest::newRow("emptysignature") << QVariant::fromValue(QDBusSignature(QString())) << "g" << "[Signature: ]";
QTest::newRow("signature") << QVariant::fromValue(QDBusSignature("g")) << "g" << "[Signature: g]";
+ QTest::newRow("multisignature") << QVariant::fromValue(QDBusSignature("bit")) << "g" << "[Signature: bit]";
QTest::newRow("emptystring") << QVariant("") << "s" << "\"\"";
QTest::newRow("nullstring") << QVariant(QString()) << "s" << "\"\"";
}
@@ -907,7 +909,7 @@ void tst_QDBusMarshall::sendSignalErrors()
QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal to service \"\" path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid object path passed in arguments");
QVERIFY(!con.send(msg));
- QDBusSignature sig;
+ QDBusSignature sig(QChar(0));
msg.setArguments(QVariantList() << QVariant::fromValue(sig));
QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal to service \"\" path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid signature passed in arguments");
QVERIFY(!con.send(msg));
@@ -992,7 +994,7 @@ void tst_QDBusMarshall::sendCallErrors_data()
<< "";
QTest::newRow("invalid-signature-arg") << serviceName << objectPath << interfaceName << "ping"
- << (QVariantList() << QVariant::fromValue(QDBusSignature()))
+ << (QVariantList() << QVariant::fromValue(QDBusSignature(QChar(0))))
<< "org.freedesktop.DBus.Error.Failed"
<< "Marshalling failed: Invalid signature passed in arguments"
<< "";
diff --git a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp
index f4ad4cb77a..63cb7d4a65 100644
--- a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp
+++ b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp
@@ -206,6 +206,7 @@ void tst_QDBusType::isValidBasicType()
void tst_QDBusType::isValidSingleSignature_data()
{
addColumns();
+ QTest::newRow("empty") << "" << false;
addSingleSignatures();
addNakedDictEntry();
}
@@ -222,6 +223,7 @@ void tst_QDBusType::isValidSingleSignature()
void tst_QDBusType::isValidArray_data()
{
addColumns();
+ QTest::newRow("empty") << "" << false;
addSingleSignatures();
}
@@ -241,7 +243,10 @@ void tst_QDBusType::isValidArray()
void tst_QDBusType::isValidSignature_data()
{
- isValidSingleSignature_data();
+ addColumns();
+ QTest::newRow("empty") << "" << true;
+ addSingleSignatures();
+ addNakedDictEntry();
}
void tst_QDBusType::isValidSignature()
@@ -250,8 +255,10 @@ void tst_QDBusType::isValidSignature()
QFETCH(bool, result);
data.append(data);
- if (data.at(0).unicode())
- QCOMPARE(bool(q_dbus_signature_validate(data.toLatin1(), 0)), result);
+ if (!data.isEmpty() && data.at(0).unicode()) {
+ // libdbus-1 API can't deal with string containing NULs
+ QCOMPARE(bool(q_dbus_signature_validate(data.toLatin1(), nullptr)), result);
+ }
QCOMPARE(QDBusUtil::isValidSignature(data), result);
}
diff --git a/tests/auto/gui/image/CMakeLists.txt b/tests/auto/gui/image/CMakeLists.txt
index 9cc6d4d2bf..3535d5f01e 100644
--- a/tests/auto/gui/image/CMakeLists.txt
+++ b/tests/auto/gui/image/CMakeLists.txt
@@ -12,8 +12,12 @@ add_subdirectory(qpixmap)
add_subdirectory(qimage)
add_subdirectory(qimageiohandler)
add_subdirectory(qimagewriter)
-add_subdirectory(qmovie)
-add_subdirectory(qpicture)
+if(QT_FEATURE_movie)
+ add_subdirectory(qmovie)
+endif()
+if(QT_FEATURE_picture)
+ add_subdirectory(qpicture)
+endif()
add_subdirectory(qiconhighdpi)
if(QT_FEATURE_private_tests)
add_subdirectory(qpixmapcache)
diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp
index 1d0cdfcc4e..3e3d0a49bc 100644
--- a/tests/auto/gui/image/qimage/tst_qimage.cpp
+++ b/tests/auto/gui/image/qimage/tst_qimage.cpp
@@ -3863,10 +3863,12 @@ void tst_QImage::metadataPassthrough()
QCOMPARE(alphaMask.dotsPerMeterY(), a.dotsPerMeterY());
QCOMPARE(alphaMask.devicePixelRatio(), a.devicePixelRatio());
+#ifndef QT_NO_IMAGE_HEURISTIC_MASK
QImage heuristicMask = a.createHeuristicMask();
QCOMPARE(heuristicMask.dotsPerMeterX(), a.dotsPerMeterX());
QCOMPARE(heuristicMask.dotsPerMeterY(), a.dotsPerMeterY());
QCOMPARE(heuristicMask.devicePixelRatio(), a.devicePixelRatio());
+#endif
QImage maskFromColor = a.createMaskFromColor(qRgb(0, 0, 0));
QCOMPARE(maskFromColor.dotsPerMeterX(), a.dotsPerMeterX());
diff --git a/tests/auto/gui/image/qmovie/tst_qmovie.cpp b/tests/auto/gui/image/qmovie/tst_qmovie.cpp
index c2171d4209..29c3297043 100644
--- a/tests/auto/gui/image/qmovie/tst_qmovie.cpp
+++ b/tests/auto/gui/image/qmovie/tst_qmovie.cpp
@@ -36,6 +36,7 @@ private slots:
void playMovie();
void jumpToFrame_data();
void jumpToFrame();
+ void frameDelay();
void changeMovieFile();
#ifndef QT_NO_WIDGETS
void infiniteLoop();
@@ -184,6 +185,17 @@ void tst_QMovie::jumpToFrame()
QCOMPARE(movie.currentFrameNumber(), 0);
}
+void tst_QMovie::frameDelay()
+{
+ QMovie movie(QFINDTESTDATA("animations/comicsecard.gif"));
+ QList<int> frameDelays{ 200, 800, 800, 2000, 2600 };
+ for (int i = 0; i < movie.frameCount(); i++) {
+ movie.jumpToFrame(i);
+ // Processing may have taken a little time, so round to nearest 100ms
+ QCOMPARE(100 * qRound(movie.nextFrameDelay() / 100.0f), frameDelays[i]);
+ }
+}
+
void tst_QMovie::changeMovieFile()
{
QMovie movie(QFINDTESTDATA("animations/comicsecard.gif"));
diff --git a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp
index 137439d98b..d8c553b521 100644
--- a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp
+++ b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp
@@ -1176,8 +1176,10 @@ void tst_QPixmap::dprPassthrough()
pm.convertFromImage(img);
QCOMPARE(pm.devicePixelRatio(), dpr);
+#ifndef QT_NO_IMAGE_HEURISTIC_MASK
QBitmap heuristicMask = src.createHeuristicMask();
QCOMPARE(heuristicMask.devicePixelRatio(), dpr);
+#endif
QBitmap maskFromColor = src.createMaskFromColor(Qt::white);
QCOMPARE(maskFromColor.devicePixelRatio(), dpr);
diff --git a/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp b/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp
index 70fb2b39d3..093367c759 100644
--- a/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp
+++ b/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp
@@ -112,13 +112,17 @@ void tst_QStandardItem::getSetData()
item.setToolTip(toolTip);
QCOMPARE(item.toolTip(), toolTip);
+#ifndef QT_NO_STATUSTIP
QString statusTip = QLatin1String("statusTip ") + iS;
item.setStatusTip(statusTip);
QCOMPARE(item.statusTip(), statusTip);
+#endif
+#if QT_CONFIG(whatsthis)
QString whatsThis = QLatin1String("whatsThis ") + iS;
item.setWhatsThis(whatsThis);
QCOMPARE(item.whatsThis(), whatsThis);
+#endif
QSize sizeHint(64*i, 48*i);
item.setSizeHint(sizeHint);
@@ -157,8 +161,12 @@ void tst_QStandardItem::getSetData()
QCOMPARE(item.text(), text);
QCOMPARE(item.icon(), icon);
QCOMPARE(item.toolTip(), toolTip);
+#ifndef QT_NO_STATUSTIP
QCOMPARE(item.statusTip(), statusTip);
+#endif
+#if QT_CONFIG(whatsthis)
QCOMPARE(item.whatsThis(), whatsThis);
+#endif
QCOMPARE(item.sizeHint(), sizeHint);
QCOMPARE(item.font(), font);
QCOMPARE(item.textAlignment(), textAlignment);
@@ -171,8 +179,12 @@ void tst_QStandardItem::getSetData()
QCOMPARE(qvariant_cast<QString>(item.data(Qt::DisplayRole)), text);
QCOMPARE(qvariant_cast<QIcon>(item.data(Qt::DecorationRole)), icon);
QCOMPARE(qvariant_cast<QString>(item.data(Qt::ToolTipRole)), toolTip);
+#ifndef QT_NO_STATUSTIP
QCOMPARE(qvariant_cast<QString>(item.data(Qt::StatusTipRole)), statusTip);
+#endif
+#if QT_CONFIG(whatsthis)
QCOMPARE(qvariant_cast<QString>(item.data(Qt::WhatsThisRole)), whatsThis);
+#endif
QCOMPARE(qvariant_cast<QSize>(item.data(Qt::SizeHintRole)), sizeHint);
QCOMPARE(qvariant_cast<QFont>(item.data(Qt::FontRole)), font);
QCOMPARE(qvariant_cast<int>(item.data(Qt::TextAlignmentRole)), int(textAlignment));
@@ -844,7 +856,9 @@ void tst_QStandardItem::streamItem()
item.setText(QLatin1String("text"));
item.setToolTip(QLatin1String("toolTip"));
item.setStatusTip(QLatin1String("statusTip"));
+#if QT_CONFIG(whatsthis)
item.setWhatsThis(QLatin1String("whatsThis"));
+#endif
item.setSizeHint(QSize(64, 48));
item.setFont(QFont());
item.setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);
@@ -866,7 +880,9 @@ void tst_QStandardItem::streamItem()
QCOMPARE(streamedItem.text(), item.text());
QCOMPARE(streamedItem.toolTip(), item.toolTip());
QCOMPARE(streamedItem.statusTip(), item.statusTip());
+#if QT_CONFIG(whatsthis)
QCOMPARE(streamedItem.whatsThis(), item.whatsThis());
+#endif
QCOMPARE(streamedItem.sizeHint(), item.sizeHint());
QCOMPARE(streamedItem.font(), item.font());
QCOMPARE(streamedItem.textAlignment(), item.textAlignment());
@@ -905,7 +921,9 @@ void tst_QStandardItem::clone()
item.setText(QLatin1String("text"));
item.setToolTip(QLatin1String("toolTip"));
item.setStatusTip(QLatin1String("statusTip"));
+#if QT_CONFIG(whatsthis)
item.setWhatsThis(QLatin1String("whatsThis"));
+#endif
item.setSizeHint(QSize(64, 48));
item.setFont(QFont());
item.setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);
@@ -920,7 +938,9 @@ void tst_QStandardItem::clone()
QCOMPARE(clone->text(), item.text());
QCOMPARE(clone->toolTip(), item.toolTip());
QCOMPARE(clone->statusTip(), item.statusTip());
+#if QT_CONFIG(whatsthis)
QCOMPARE(clone->whatsThis(), item.whatsThis());
+#endif
QCOMPARE(clone->sizeHint(), item.sizeHint());
QCOMPARE(clone->font(), item.font());
QCOMPARE(clone->textAlignment(), item.textAlignment());
diff --git a/tests/auto/gui/kernel/qevent/tst_qevent.cpp b/tests/auto/gui/kernel/qevent/tst_qevent.cpp
index 6960f99af2..8e8169b16c 100644
--- a/tests/auto/gui/kernel/qevent/tst_qevent.cpp
+++ b/tests/auto/gui/kernel/qevent/tst_qevent.cpp
@@ -6,7 +6,52 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qevent.h>
+#if QT_CONFIG(future)
#include <QtCore/private/qfutureinterface_p.h>
+#endif
+
+
+#if QT_CONFIG(future)
+#define X_QFutureCallOutEvent(X) X(QFutureCallOutEvent, ())
+#else
+#define X_QFutureCallOutEvent(X)
+#endif
+
+#if QT_CONFIG(wheelevent)
+#define X_QWheelEvent(X) X(QWheelEvent, ({}, {}, {}, {}, {}, {}, {}, {}))
+#else
+#define X_QWheelEvent(X)
+#endif
+
+#if QT_CONFIG(tabletevent)
+#define X_QTabletEvent(X) X(QTabletEvent, (QEvent::None, QPointingDevice::primaryPointingDevice(), {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}))
+#else
+#define X_QTabletEvent(X)
+#endif
+
+#if QT_CONFIG(gestures)
+#define X_QNativeGestureEvent(X) X(QNativeGestureEvent, ({}, QPointingDevice::primaryPointingDevice(), 0, {}, {}, {}, {}, {}))
+#else
+#define X_QNativeGestureEvent(X)
+#endif
+
+#if QT_CONFIG(whatsthis)
+#define X_QWhatsThisClickedEvent(X) X(QWhatsThisClickedEvent, ({}))
+#else
+#define X_QWhatsThisClickedEvent(X)
+#endif
+
+#if QT_CONFIG(action)
+#define X_QActionEvent(X) X(QActionEvent, (0, nullptr))
+#else
+#define X_QActionEvent(X)
+#endif
+
+#if QT_CONFIG(shortcut)
+#define X_QShortcutEvent(X) X(QShortcutEvent, ({}, 0))
+#else
+#define X_QShortcutEvent(X)
+#endif
#define FOR_EACH_CORE_EVENT(X) \
/* qcoreevent.h */ \
@@ -15,7 +60,7 @@
X(QChildEvent, (QEvent::ChildAdded, nullptr)) \
X(QDynamicPropertyChangeEvent, ("size")) \
/* qfutureinterface_p.h */ \
- X(QFutureCallOutEvent, ()) \
+ X_QFutureCallOutEvent(X) \
/* end */
#define FOR_EACH_GUI_EVENT(X) \
@@ -27,9 +72,9 @@
X(QEnterEvent, ({}, {}, {})) \
X(QMouseEvent, (QEvent::None, {}, {}, {}, {}, {}, {}, {}, QPointingDevice::primaryPointingDevice())) \
X(QHoverEvent, (QEvent::None, {}, {}, QPointF{})) \
- X(QWheelEvent, ({}, {}, {}, {}, {}, {}, {}, {})) \
- X(QTabletEvent, (QEvent::None, QPointingDevice::primaryPointingDevice(), {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {})) \
- X(QNativeGestureEvent, ({}, QPointingDevice::primaryPointingDevice(), 0, {}, {}, {}, {}, {})) \
+ X_QWheelEvent(X) \
+ X_QTabletEvent(X) \
+ X_QNativeGestureEvent(X) \
X(QKeyEvent, (QEvent::None, 0, {})) \
X(QFocusEvent, (QEvent::None)) \
X(QPaintEvent, (QRect{0, 0, 100, 100})) \
@@ -50,11 +95,11 @@
X(QDragLeaveEvent, ()) \
X(QHelpEvent, ({}, {}, {})) \
X(QStatusTipEvent, ({})) \
- X(QWhatsThisClickedEvent, ({})) \
- X(QActionEvent, (0, nullptr)) \
+ X_QWhatsThisClickedEvent(X) \
+ X_QActionEvent(X) \
X(QFileOpenEvent, (QString{})) \
X(QToolBarChangeEvent, (false)) \
- X(QShortcutEvent, ({}, 0)) \
+ X_QShortcutEvent(X) \
X(QWindowStateChangeEvent, ({})) \
X(QTouchEvent, (QEvent::None)) \
X(QScrollPrepareEvent, ({})) \
diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp
index 6b8700f580..d1a50e3d69 100644
--- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp
+++ b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp
@@ -1004,8 +1004,8 @@ void tst_QGuiApplication::quitOnLastWindowClosedWithEventLoopLocker()
});
{
- // Disabling QEventLoopLocker support should not affect
- // quitting when last window is closed.
+ // Disabling QEventLoopLocker automatic quit should not affect
+ // quitting when last window is closed if there are no lockers.
app.setQuitLockEnabled(false);
QuitSpy quitSpy;
@@ -1019,8 +1019,40 @@ void tst_QGuiApplication::quitOnLastWindowClosedWithEventLoopLocker()
}
{
- // Disabling quitOnLastWindowClosed support should not affect
- // quitting when last QEventLoopLocker goes out of scope.
+ // Disabling QEventLoopLocker automatic quit should still block
+ // quitting when last window is closed if there is a locker alive.
+ app.setQuitLockEnabled(false);
+
+ QScopedPointer<QEventLoopLocker> locker(new QEventLoopLocker);
+
+ QuitSpy quitSpy;
+ QWindow window;
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QTimer::singleShot(0, &window, &QWindow::close);
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 0);
+ }
+
+ {
+ // Disabling quitOnLastWindowClosed automatic quit should not affect
+ // quitting when last QEventLoopLocker goes out of scope if
+ // there are no windows.
+ app.setQuitLockEnabled(true);
+ app.setQuitOnLastWindowClosed(false);
+
+ QuitSpy quitSpy;
+ QScopedPointer<QEventLoopLocker> locker(new QEventLoopLocker);
+ QTimer::singleShot(0, [&]{ locker.reset(nullptr); });
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 1);
+ }
+
+ {
+ // Disabling quitOnLastWindowClosed automatic quit should still block
+ // quitting via QEventLoopLocker if there's a window alive.
app.setQuitLockEnabled(true);
app.setQuitOnLastWindowClosed(false);
@@ -1032,7 +1064,7 @@ void tst_QGuiApplication::quitOnLastWindowClosedWithEventLoopLocker()
QTimer::singleShot(0, [&]{ locker.reset(nullptr); });
QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
app.exec();
- QCOMPARE(quitSpy.quits, 1);
+ QCOMPARE(quitSpy.quits, 0);
}
{
diff --git a/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp
index 526abd6ea3..fdb1b333ef 100644
--- a/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp
+++ b/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp
@@ -172,6 +172,9 @@ void tst_ForeignWindow::destroyWhenParentIsDestroyed()
// Reparenting into a window will result in creating it
QVERIFY(parentWindow.handle());
+ parentWindow.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&parentWindow));
+
// Destroying the parent window of the foreign window results
// in destroying the foreign window as well, as the foreign
// window no longer has a parent it can be embedded in.
@@ -184,6 +187,9 @@ void tst_ForeignWindow::destroyWhenParentIsDestroyed()
foreignWindow->create();
QVERIFY(foreignWindow->handle());
QTRY_COMPARE(nativeWindow.parentWinId(), parentWindow.winId());
+
+ parentWindow.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&parentWindow));
}
#include <tst_foreignwindow.moc>
diff --git a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp
index 16ea076934..7505d463ed 100644
--- a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp
+++ b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp
@@ -292,9 +292,9 @@ void tst_QColorSpace::imageConversion()
int lastBlue = 0;
for (int i = 0; i < 256; ++i) {
QRgb p = testImage.pixel(i, 0);
- QVERIFY(qRed(p) >= lastRed);
- QVERIFY(qGreen(p) >= lastGreen);
- QVERIFY(qBlue(p) >= lastBlue);
+ QCOMPARE_GE(qRed(p), lastRed);
+ QCOMPARE_GE(qGreen(p), lastGreen);
+ QCOMPARE_GE(qBlue(p), lastBlue);
lastRed = qRed(p);
lastGreen = qGreen(p);
lastBlue = qBlue(p);
@@ -307,12 +307,12 @@ void tst_QColorSpace::imageConversion()
QCOMPARE(testImage.colorSpace(), QColorSpace(fromColorSpace));
for (int i = 0; i < 256; ++i) {
QRgb p = testImage.pixel(i, 0);
- QVERIFY(qAbs(qRed(p) - qBlue(p)) <= tolerance);
- QVERIFY(qAbs(qRed(p) - qGreen(p)) <= tolerance);
- QVERIFY(qAbs(qGreen(p) - qBlue(p)) <= tolerance);
- QVERIFY((lastRed - qRed(p)) <= (tolerance / 2));
- QVERIFY((lastGreen - qGreen(p)) <= (tolerance / 2));
- QVERIFY((lastBlue - qBlue(p)) <= (tolerance / 2));
+ QCOMPARE_LE(qAbs(qRed(p) - qBlue(p)), tolerance);
+ QCOMPARE_LE(qAbs(qRed(p) - qGreen(p)), tolerance);
+ QCOMPARE_LE(qAbs(qGreen(p) - qBlue(p)), tolerance);
+ QCOMPARE_LE(lastRed - qRed(p), tolerance / 2);
+ QCOMPARE_LE(lastBlue - qBlue(p), tolerance / 2);
+ QCOMPARE_LE(lastGreen - qGreen(p), tolerance / 2);
lastRed = qRed(p);
lastGreen = qGreen(p);
lastBlue = qBlue(p);
@@ -353,9 +353,9 @@ void tst_QColorSpace::imageConversion64()
int lastBlue = 0;
for (int i = 0; i < 256; ++i) {
QRgb p = testImage.pixel(i, 0);
- QVERIFY(qRed(p) >= lastRed);
- QVERIFY(qGreen(p) >= lastGreen);
- QVERIFY(qBlue(p) >= lastBlue);
+ QCOMPARE_GE(qRed(p), lastRed);
+ QCOMPARE_GE(qGreen(p), lastGreen);
+ QCOMPARE_GE(qBlue(p), lastBlue);
lastRed = qRed(p);
lastGreen = qGreen(p);
lastBlue = qBlue(p);
@@ -370,9 +370,9 @@ void tst_QColorSpace::imageConversion64()
QRgb p = testImage.pixel(i, 0);
QCOMPARE(qRed(p), qGreen(p));
QCOMPARE(qRed(p), qBlue(p));
- QVERIFY((lastRed - qRed(p)) <= 0);
- QVERIFY((lastGreen - qGreen(p)) <= 0);
- QVERIFY((lastBlue - qBlue(p)) <= 0);
+ QCOMPARE_GE(qRed(p), lastRed);
+ QCOMPARE_GE(qGreen(p), lastGreen);
+ QCOMPARE_GE(qBlue(p), lastBlue);
lastRed = qRed(p);
lastGreen = qGreen(p);
lastBlue = qBlue(p);
@@ -415,17 +415,17 @@ void tst_QColorSpace::imageConversion64PM()
const int expectedAlpha = j * 15;
for (int i = 0; i < 256; ++i) {
QRgb p = testImage.pixel(i, j);
- QVERIFY(qRed(p) >= lastRed);
- QVERIFY(qGreen(p) >= lastGreen);
- QVERIFY(qBlue(p) >= lastBlue);
+ QCOMPARE_GE(qRed(p), lastRed);
+ QCOMPARE_GE(qGreen(p), lastGreen);
+ QCOMPARE_GE(qBlue(p), lastBlue);
QCOMPARE(qAlpha(p), expectedAlpha);
lastRed = qRed(p);
lastGreen = qGreen(p);
lastBlue = qBlue(p);
}
- QVERIFY(lastRed <= expectedAlpha);
- QVERIFY(lastGreen <= expectedAlpha);
- QVERIFY(lastBlue <= expectedAlpha);
+ QCOMPARE_LE(lastRed, expectedAlpha);
+ QCOMPARE_LE(lastGreen, expectedAlpha);
+ QCOMPARE_LE(lastBlue, expectedAlpha);
lastRed = 0;
lastGreen = 0;
lastBlue = 0;
@@ -438,15 +438,15 @@ void tst_QColorSpace::imageConversion64PM()
for (int i = 0; i < 256; ++i) {
QRgb expected = qPremultiply(qRgba(i, i, i, expectedAlpha));
QRgb p = testImage.pixel(i, j);
- QVERIFY(qAbs(qRed(p) - qGreen(p)) <= 1);
- QVERIFY(qAbs(qRed(p) - qBlue(p)) <= 1);
+ QCOMPARE_LE(qAbs(qRed(p) - qGreen(p)), 1);
+ QCOMPARE_LE(qAbs(qRed(p) - qBlue(p)), 1);
QCOMPARE(qAlpha(p), expectedAlpha);
- QVERIFY((lastRed - qRed(p)) <= 0);
- QVERIFY((lastGreen - qGreen(p)) <= 0);
- QVERIFY((lastBlue - qBlue(p)) <= 0);
- QVERIFY(qAbs(qRed(p) - qRed(expected)) <= 1);
- QVERIFY(qAbs(qGreen(p) - qGreen(expected)) <= 1);
- QVERIFY(qAbs(qBlue(p) - qBlue(expected)) <= 1);
+ QCOMPARE_GE(qRed(p), lastRed);
+ QCOMPARE_GE(qGreen(p), lastGreen);
+ QCOMPARE_GE(qBlue(p), lastBlue);
+ QCOMPARE_LE(qAbs(qRed(p) - qRed(expected)), 1);
+ QCOMPARE_LE(qAbs(qGreen(p) - qGreen(expected)), 1);
+ QCOMPARE_LE(qAbs(qBlue(p) - qBlue(expected)), 1);
lastRed = qRed(p);
lastGreen = qGreen(p);
lastBlue = qBlue(p);
@@ -493,7 +493,7 @@ void tst_QColorSpace::imageConversionOverLargerGamut()
int lastRed = 0;
for (int x = 0; x < 256; ++x) {
QRgb p = resultImage.pixel(x, y);
- QVERIFY(qRed(p) >= lastRed);
+ QCOMPARE_GE(qRed(p), lastRed);
lastRed = qRed(p);
}
}
@@ -501,7 +501,7 @@ void tst_QColorSpace::imageConversionOverLargerGamut()
int lastGreen = 0;
for (int y = 0; y < 256; ++y) {
QRgb p = resultImage.pixel(x, y);
- QVERIFY(qGreen(p) >= lastGreen);
+ QCOMPARE_GE(qGreen(p), lastGreen);
lastGreen = qGreen(p);
}
}
diff --git a/tests/auto/gui/painting/qpagelayout/tst_qpagelayout.cpp b/tests/auto/gui/painting/qpagelayout/tst_qpagelayout.cpp
index cbbf857357..4490877e87 100644
--- a/tests/auto/gui/painting/qpagelayout/tst_qpagelayout.cpp
+++ b/tests/auto/gui/painting/qpagelayout/tst_qpagelayout.cpp
@@ -12,6 +12,7 @@ private slots:
void invalid();
void basics();
void setGetMargins();
+ void setGetClampedMargins();
void setUnits_data();
void setUnits();
};
@@ -216,7 +217,7 @@ void tst_QPageLayout::basics()
void tst_QPageLayout::setGetMargins()
{
- // A4, 20pt margins
+ // A4, 10pt margins
QMarginsF margins = QMarginsF(10, 10, 10, 10);
QMarginsF min = QMarginsF(10, 10, 10, 10);
QMarginsF max = QMarginsF(585, 832, 585, 832);
@@ -229,7 +230,7 @@ void tst_QPageLayout::setGetMargins()
QCOMPARE(change.minimumMargins(), min);
QCOMPARE(change.maximumMargins(), max);
- // Set magins within min/max ok
+ // Set margins within min/max ok
margins = QMarginsF(20, 20, 20, 20);
change.setMargins(margins);
QCOMPARE(change.margins(QPageLayout::Millimeter), QMarginsF(7.06, 7.06, 7.06, 7.06));
@@ -289,7 +290,7 @@ void tst_QPageLayout::setGetMargins()
fullPage.setMargins(margins);
QCOMPARE(fullPage.margins(), margins);
- // Set margins all above max is rejected
+ // Set margins all above max is accepted
margins = QMarginsF(1000, 1000, 1000, 1000);
fullPage.setMargins(margins);
QCOMPARE(fullPage.margins(), margins);
@@ -312,6 +313,126 @@ void tst_QPageLayout::setGetMargins()
QCOMPARE(fullPage.maximumMargins(), max);
}
+void tst_QPageLayout::setGetClampedMargins()
+{
+ // A4, 10pt margins
+ QMarginsF margins = QMarginsF(10, 10, 10, 10);
+ QMarginsF min = QMarginsF(10, 10, 10, 10);
+ QMarginsF max = QMarginsF(585, 832, 585, 832);
+ QPageLayout change = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, margins, QPageLayout::Point, min);
+ QCOMPARE(change.isValid(), true);
+
+ // Clamp margins within min/max ok
+ margins = QMarginsF(20, 20, 20, 20);
+ change.setMargins(margins, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins(QPageLayout::Millimeter), QMarginsF(7.06, 7.06, 7.06, 7.06));
+ QCOMPARE(change.marginsPoints(), QMargins(20, 20, 20, 20));
+ QCOMPARE(change.marginsPixels(72), QMargins(20, 20, 20, 20));
+ QCOMPARE(change.margins(), margins);
+
+ // Clamp margins all below min
+ change.setMargins(QMarginsF(0, 0, 0, 0), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins(), change.minimumMargins());
+
+ // Clamp margins all above max
+ change.setMargins(QMarginsF(1000, 1000, 1000, 1000), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins(), change.maximumMargins());
+
+ // Only 1 wrong, clamp still works
+ change.setMargins(QMarginsF(50, 50, 50, 0), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins(), QMarginsF(50, 50, 50, change.minimumMargins().bottom()));
+
+ // A4, 20pt margins
+ margins = QMarginsF(20, 20, 20, 20);
+ min = QMarginsF(10, 10, 10, 10);
+ max = QMarginsF(585, 832, 585, 832);
+ QPageLayout fullPage = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, margins, QPageLayout::Point, min);
+ fullPage.setMode(QPageLayout::FullPageMode);
+ QCOMPARE(fullPage.isValid(), true);
+ QCOMPARE(fullPage.margins(), margins);
+ QCOMPARE(fullPage.minimumMargins(), min);
+ QCOMPARE(fullPage.maximumMargins(), max);
+
+ // Clamp margins within min/max ok
+ margins = QMarginsF(50, 50, 50, 50);
+ fullPage.setMargins(margins, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(fullPage.margins(), margins);
+
+ // Clamp margins all below min, no clamping
+ margins = QMarginsF(0, 0, 0, 0);
+ fullPage.setMargins(margins, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(fullPage.margins(), margins);
+
+ // Clamp margins all above max, no clamping
+ margins = QMarginsF(1000, 1000, 1000, 1000);
+ fullPage.setMargins(margins, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(fullPage.margins(), margins);
+
+ // Only 1 wrong, no clamping
+ margins = QMarginsF(50, 50, 50, 0);
+ fullPage.setMargins(margins, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(fullPage.margins(), margins);
+
+ // Set page size, sets min/max, clamps existing margins
+ margins = QMarginsF(20, 500, 20, 500);
+ fullPage.setMargins(margins, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(fullPage.margins(), margins);
+ min = QMarginsF(30, 30, 30, 30);
+ max = QMarginsF(267, 390, 267, 390);
+ fullPage.setPageSize(QPageSize(QPageSize::A6));
+ fullPage.setMinimumMargins(min);
+ QCOMPARE(fullPage.margins(), margins);
+ QCOMPARE(fullPage.minimumMargins(), min);
+ QCOMPARE(fullPage.maximumMargins(), max);
+
+ // Test set* API calls
+ min = QMarginsF(1, 2, 3, 4);
+ max = QMarginsF(595 - min.right(), 842 - min.bottom(), 595 - min.left(), 842 - min.top());
+ change = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, margins, QPageLayout::Point, min);
+ QCOMPARE(change.minimumMargins(), min);
+ QCOMPARE(change.maximumMargins(), max);
+
+ // Test setLeftMargin
+ change.setLeftMargin(0, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().left(), min.left());
+ change.setLeftMargin(change.fullRectPoints().width(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().left(), max.left());
+ change.setLeftMargin(min.left(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().left(), min.left());
+ change.setLeftMargin(max.left(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().left(), max.left());
+
+ // Test setTopMargin
+ change.setTopMargin(0, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().top(), min.top());
+ change.setTopMargin(change.fullRectPoints().height(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().top(), max.top());
+ change.setTopMargin(min.top(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().top(), min.top());
+ change.setTopMargin(max.top(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().top(), max.top());
+
+ // Test setRightMargin
+ change.setRightMargin(0, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().right(), min.right());
+ change.setRightMargin(change.fullRectPoints().width(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().right(), max.right());
+ change.setRightMargin(min.right(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().right(), min.right());
+ change.setRightMargin(max.right(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().right(), max.right());
+
+ // Test setBottomMargin
+ change.setBottomMargin(0, QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().bottom(), min.bottom());
+ change.setBottomMargin(change.fullRectPoints().height(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().bottom(), max.bottom());
+ change.setBottomMargin(min.bottom(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().bottom(), min.bottom());
+ change.setBottomMargin(max.bottom(), QPageLayout::OutOfBoundsPolicy::Clamp);
+ QCOMPARE(change.margins().bottom(), max.bottom());
+}
+
void tst_QPageLayout::setUnits_data()
{
QTest::addColumn<QPageLayout::Unit>("units");
diff --git a/tests/auto/gui/text/CMakeLists.txt b/tests/auto/gui/text/CMakeLists.txt
index bad13de7dc..30b35fb10a 100644
--- a/tests/auto/gui/text/CMakeLists.txt
+++ b/tests/auto/gui/text/CMakeLists.txt
@@ -11,7 +11,9 @@ add_subdirectory(qstatictext)
add_subdirectory(qsyntaxhighlighter)
add_subdirectory(qtextblock)
add_subdirectory(qtextcursor)
-add_subdirectory(qtextdocumentfragment)
+if(QT_FEATURE_texthtmlparser)
+ add_subdirectory(qtextdocumentfragment)
+endif()
add_subdirectory(qtextdocumentlayout)
add_subdirectory(qtextformat)
add_subdirectory(qtextimagehandler)
diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp
index 2ae2ccda0a..3d0fab4603 100644
--- a/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp
+++ b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp
@@ -22,9 +22,11 @@ public:
private slots:
void getSetCheck();
void maximumBlockCount();
+#ifndef QT_NO_TEXTHTMLPARSER
void anchorAt();
void imageAt();
void formatAt();
+#endif
};
tst_QAbstractTextDocumentLayout::tst_QAbstractTextDocumentLayout()
@@ -119,6 +121,7 @@ void tst_QAbstractTextDocumentLayout::maximumBlockCount()
QCOMPARE(layout.blockCount, 10);
}
+#ifndef QT_NO_TEXTHTMLPARSER
void tst_QAbstractTextDocumentLayout::anchorAt()
{
QTextDocument doc;
@@ -204,6 +207,7 @@ void tst_QAbstractTextDocumentLayout::formatAt()
QVERIFY(!format.toCharFormat().fontItalic());
QVERIFY(!format.isImageFormat());
}
+#endif
QTEST_MAIN(tst_QAbstractTextDocumentLayout)
#include "tst_qabstracttextdocumentlayout.moc"
diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
index a438d7ebc8..203fe003a0 100644
--- a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
+++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
@@ -56,6 +56,10 @@ private slots:
void quotedAndUnquotedIdentifiers();
void whitespaceValues_data();
void whitespaceValues();
+ void strokeLineCapValues_data();
+ void strokeLineCapValues();
+ void strokeLineJoinValues_data();
+ void strokeLineJoinValues();
};
void tst_QCssParser::scanner_data()
@@ -1759,6 +1763,57 @@ void tst_QCssParser::whitespaceValues()
QCOMPARE(rule.declarations.at(0).d->values.first().toString(), value);
}
+void tst_QCssParser::strokeLineCapValues_data()
+{
+ QTest::addColumn<QString>("value");
+
+ QTest::newRow("flatcap") << "flatcap";
+ QTest::newRow("roundcap") << "roundcap";
+ QTest::newRow("squarecap") << "squarecap";
+}
+
+void tst_QCssParser::strokeLineCapValues()
+{
+ QFETCH(QString, value);
+ QCss::Parser parser(QString("foo { -qt-stroke-linecap: %1 }").arg(value));
+ QCss::StyleSheet sheet;
+ QVERIFY(parser.parse(&sheet));
+
+ QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ?
+ sheet.styleRules.at(0) : *sheet.nameIndex.begin();
+ QCOMPARE(rule.declarations.size(), 1);
+
+ QCOMPARE(rule.declarations.at(0).d->property, QLatin1String("-qt-stroke-linecap"));
+ QCOMPARE(rule.declarations.at(0).d->values.first().type, QCss::Value::KnownIdentifier);
+ QCOMPARE(rule.declarations.at(0).d->values.first().toString(), value);
+}
+
+void tst_QCssParser::strokeLineJoinValues_data()
+{
+ QTest::addColumn<QString>("value");
+
+ QTest::newRow("beveljoin") << "beveljoin";
+ QTest::newRow("miterjoin") << "miterjoin";
+ QTest::newRow("roundjoin") << "roundjoin";
+ QTest::newRow("svgmiterjoin") << "svgmiterjoin";
+}
+
+void tst_QCssParser::strokeLineJoinValues()
+{
+ QFETCH(QString, value);
+ QCss::Parser parser(QString("foo { -qt-stroke-linejoin: %1 }").arg(value));
+ QCss::StyleSheet sheet;
+ QVERIFY(parser.parse(&sheet));
+
+ QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ?
+ sheet.styleRules.at(0) : *sheet.nameIndex.begin();
+ QCOMPARE(rule.declarations.size(), 1);
+
+ QCOMPARE(rule.declarations.at(0).d->property, QLatin1String("-qt-stroke-linejoin"));
+ QCOMPARE(rule.declarations.at(0).d->values.first().type, QCss::Value::KnownIdentifier);
+ QCOMPARE(rule.declarations.at(0).d->values.first().toString(), value);
+}
+
QTEST_MAIN(tst_QCssParser)
#include "tst_qcssparser.moc"
diff --git a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp
index 678eb0393f..9471c1d93f 100644
--- a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp
+++ b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp
@@ -263,7 +263,7 @@ void tst_QFontMetrics::inFontUcs4()
glyphs.glyphs[0] = 0;
QVERIFY(engine->stringToCMap(string.constData(), string.size(),
&glyphs, &glyphs.numGlyphs,
- QFontEngine::GlyphIndicesOnly));
+ QFontEngine::GlyphIndicesOnly) > 0);
QCOMPARE(glyphs.numGlyphs, 1);
QCOMPARE(glyphs.glyphs[0], uint(1));
}
@@ -275,7 +275,7 @@ void tst_QFontMetrics::inFontUcs4()
glyphs.glyphs[0] = 0;
QVERIFY(engine->stringToCMap(string.constData(), string.size(),
&glyphs, &glyphs.numGlyphs,
- QFontEngine::GlyphIndicesOnly));
+ QFontEngine::GlyphIndicesOnly) >= 0);
QVERIFY(glyphs.glyphs[0] != 1);
}
}
diff --git a/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp b/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp
index 6984cd1bd2..8f5cacae4a 100644
--- a/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp
+++ b/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp
@@ -39,7 +39,9 @@ private slots:
void navigation7();
void navigation8();
void navigation9();
+#ifndef QT_NO_TEXTHTMLPARSER
void navigation10();
+#endif
void movePositionEndOfLine();
void insertBlock();
void insertWithBlockSeparator1();
@@ -431,6 +433,7 @@ void tst_QTextCursor::navigation9()
QCOMPARE(cursor.position(), 15);
}
+#ifndef QT_NO_TEXTHTMLPARSER
void tst_QTextCursor::navigation10()
{
doc->setHtml("<html><p>just a simple paragraph.</p>"
@@ -542,6 +545,7 @@ void tst_QTextCursor::navigation10()
QVERIFY(ok);
QCOMPARE(cursor.position(), 1); // a
}
+#endif
void tst_QTextCursor::insertBlock()
{
diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
index 40f78ed778..600b45575f 100644
--- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
+++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
@@ -1172,7 +1172,7 @@ void tst_QTextDocument::toHtml_data()
cursor.insertTable(2, 2);
QTest::newRow("simpletable") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td></td>\n<td></td></tr>"
"\n<tr>\n<td></td>\n<td></td></tr>"
"</table>");
@@ -1186,7 +1186,7 @@ void tst_QTextDocument::toHtml_data()
table->mergeCells(0, 2, 1, 2);
QTest::newRow("tablespans") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td colspan=\"2\"></td>\n<td colspan=\"2\"></td></tr>"
"</table>");
}
@@ -1205,7 +1205,7 @@ void tst_QTextDocument::toHtml_data()
cursor.insertTable(2, 2, fmt);
QTest::newRow("tableattrs") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" style=\" float: right;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">"
+ << QString("<table border=\"1\" style=\" float: right; border-collapse:collapse;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">"
"\n<tr>\n<td></td>\n<td></td></tr>"
"\n<tr>\n<td></td>\n<td></td></tr>"
"</table>");
@@ -1227,7 +1227,7 @@ void tst_QTextDocument::toHtml_data()
cursor.insertTable(2, 2, fmt);
QTest::newRow("tableattrs2") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">"
+ << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px; border-collapse:collapse;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">"
"\n<tr>\n<td></td>\n<td></td></tr>"
"\n<tr>\n<td></td>\n<td></td></tr>"
"</table>");
@@ -1241,7 +1241,7 @@ void tst_QTextDocument::toHtml_data()
cursor.insertTable(4, 2, fmt);
QTest::newRow("tableheader") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"<thead>\n<tr>\n<td></td>\n<td></td></tr>"
"\n<tr>\n<td></td>\n<td></td></tr></thead>"
"\n<tr>\n<td></td>\n<td></td></tr>"
@@ -1257,8 +1257,8 @@ void tst_QTextDocument::toHtml_data()
subTable->cellAt(0, 0).firstCursorPosition().insertText("Hey");
QTest::newRow("nestedtable") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
- "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" cellspacing=\"2\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
+ "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>"
"\n<tr>\n<td></td>\n<td></td></tr>"
"</table>");
}
@@ -1275,7 +1275,7 @@ void tst_QTextDocument::toHtml_data()
cursor.insertTable(1, 3, fmt);
QTest::newRow("colwidths") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td></td>\n<td width=\"30%\"></td>\n<td width=\"40\"></td></tr>"
"</table>");
}
@@ -1292,7 +1292,7 @@ void tst_QTextDocument::toHtml_data()
cellCurs.mergeBlockCharFormat(fmt);
QTest::newRow("cellproperties") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td bgcolor=\"#ffffff\"></td></tr>"
"</table>");
}
@@ -1559,7 +1559,7 @@ void tst_QTextDocument::toHtml_data()
table->setFormat(fmt);
QTest::newRow("mergedtablecolwidths") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td colspan=\"2\"></td></tr>"
"\n<tr>\n<td width=\"20\"></td>\n<td width=\"40\"></td></tr>"
"</table>");
@@ -1622,7 +1622,7 @@ void tst_QTextDocument::toHtml_data()
table->cellAt(0, 0).firstCursorPosition().insertText("Blah");
QTest::newRow("table-vertical-alignment") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td style=\" vertical-align:middle;\">\n"
"<p DEFAULTBLOCKSTYLE>Blah</p></td>"
"\n<td style=\" vertical-align:top;\"></td></tr>"
@@ -1651,7 +1651,7 @@ void tst_QTextDocument::toHtml_data()
table->cellAt(0, 0).firstCursorPosition().insertText("Blah");
QTest::newRow("table-cell-paddings") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td style=\" padding-left:1;\">\n"
"<p DEFAULTBLOCKSTYLE>Blah</p></td>"
"\n<td style=\" padding-right:1;\"></td></tr>"
@@ -1669,7 +1669,7 @@ void tst_QTextDocument::toHtml_data()
cursor.insertTable(2, 2, fmt);
QTest::newRow("tableborder") << QTextDocumentFragment(&doc)
- << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid;\" cellspacing=\"2\">"
+ << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid; border-collapse:collapse;\" cellpadding=\"4\">"
"\n<tr>\n<td></td>\n<td></td></tr>"
"\n<tr>\n<td></td>\n<td></td></tr>"
"</table>");
@@ -1711,7 +1711,7 @@ void tst_QTextDocument::toHtml_data()
<< QString("EMPTYBLOCK") +
QString("<p OPENDEFAULTBLOCKSTYLE page-break-before:always;\">Foo</p>"
"\n<p OPENDEFAULTBLOCKSTYLE page-break-before:always; page-break-after:always;\">Bar</p>"
- "\n<table border=\"1\" style=\" page-break-after:always;\" cellspacing=\"2\">\n<tr>\n<td></td></tr></table>");
+ "\n<table border=\"1\" style=\" page-break-after:always; border-collapse:collapse;\" cellpadding=\"4\">\n<tr>\n<td></td></tr></table>");
}
{
@@ -4053,20 +4053,107 @@ void tst_QTextDocument::restoreStrokeFromHtml()
QTextDocument document;
QTextCursor textCursor(&document);
QTextCharFormat textOutline;
- textOutline.setTextOutline(QPen(Qt::red, 2.3));
- textCursor.insertText("Outlined text", textOutline);
+
+ // Set stroke color and width
+ {
+ QPen pen(Qt::red, 2.3, Qt::SolidLine);
+ textOutline.setTextOutline(pen);
+ textCursor.insertText("Outlined text", textOutline);
+ }
+
+ // Set Cap and Join styles
+ {
+ QPen pen;
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setJoinStyle(Qt::RoundJoin);
+ textOutline.setTextOutline(pen);
+ textCursor.insertBlock();
+ textCursor.insertText("Cap and Join Style", textOutline);
+ }
+
+ // Set Miter limit
+ {
+ QPen pen;
+ pen.setJoinStyle(Qt::MiterJoin);
+ pen.setMiterLimit(4);
+ textOutline.setTextOutline(pen);
+ textCursor.insertBlock();
+ textCursor.insertText("Miter Limit", textOutline);
+ }
+
+ // Set Dash Array and Dash Offset
+ {
+ QPen pen;
+ QList<qreal> pattern;
+ const int dash = 2;
+ const int gap = 4;
+ pattern << dash << gap << dash << gap << dash << gap;
+ pen.setDashPattern(pattern);
+ pen.setDashOffset(3);
+ textOutline.setTextOutline(pen);
+ textCursor.insertBlock();
+ textCursor.insertText("Dash Pattern", textOutline);
+ }
+
{
QTextDocument otherDocument;
otherDocument.setHtml(document.toHtml());
- QCOMPARE(otherDocument.blockCount(), 1);
- QTextBlock block = otherDocument.firstBlock();
- QTextFragment fragment = block.begin().fragment();
- QCOMPARE(fragment.text(), QStringLiteral("Outlined text"));
- QTextCharFormat fmt = fragment.charFormat();
- QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline));
- QPen pen = fmt.textOutline();
- QCOMPARE(pen.color(), QColor(Qt::red));
- QCOMPARE(pen.widthF(), 2.3);
+ QCOMPARE(otherDocument.blockCount(), document.blockCount());
+
+ QTextBlock block;
+ QTextFragment fragment;
+ QTextCharFormat fmt;
+ QPen pen;
+
+ {
+ block = otherDocument.findBlockByNumber(0);
+ fragment = block.begin().fragment();
+ QCOMPARE(fragment.text(), QStringLiteral("Outlined text"));
+ fmt = fragment.charFormat();
+ QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline));
+ pen = fmt.textOutline();
+ QCOMPARE(pen.color(), QColor(Qt::red));
+ QCOMPARE(pen.widthF(), 2.3);
+ }
+
+ {
+ block = otherDocument.findBlockByNumber(1);
+ qDebug() << block.text();
+ fragment = block.begin().fragment();
+ QCOMPARE(fragment.text(), QStringLiteral("Cap and Join Style"));
+ fmt = fragment.charFormat();
+ QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline));
+ pen = fmt.textOutline();
+ QCOMPARE(pen.capStyle(), Qt::FlatCap);
+ QCOMPARE(pen.joinStyle(), Qt::RoundJoin);
+ }
+
+ {
+ block = otherDocument.findBlockByNumber(2);
+ fragment = block.begin().fragment();
+ QCOMPARE(fragment.text(), QStringLiteral("Miter Limit"));
+ fmt = fragment.charFormat();
+ QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline));
+ pen = fmt.textOutline();
+ QCOMPARE(pen.joinStyle(), Qt::MiterJoin);
+ QCOMPARE(pen.miterLimit(), 4);
+ }
+
+
+ {
+ block = otherDocument.findBlockByNumber(3);
+ fragment = block.begin().fragment();
+ QCOMPARE(fragment.text(), QStringLiteral("Dash Pattern"));
+ fmt = fragment.charFormat();
+ QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline));
+ pen = fmt.textOutline();
+ QCOMPARE(pen.dashOffset(), 3);
+ QList<qreal> pattern;
+ const int dash = 2;
+ const int gap = 4;
+ pattern << dash << gap << dash << gap << dash << gap;
+ QCOMPARE(pen.dashPattern(), pattern);
+ }
}
}
diff --git a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp
index 2a279682ca..2ae31849bf 100644
--- a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp
+++ b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp
@@ -24,18 +24,24 @@ private slots:
void cleanupTestCase();
void defaultPageSizeHandling();
void idealWidth();
+#ifndef QT_NO_TEXTHTMLPARSER
void lineSeparatorFollowingTable();
+#endif
#ifndef QT_NO_WIDGETS
void wrapAtWordBoundaryOrAnywhere();
#endif
void inlineImage();
+#ifndef QT_NO_TEXTHTMLPARSER
void clippedTableCell();
+#endif
void floatingTablePageBreak();
void imageAtRightAlignedTab();
void blockVisibility();
+#ifndef QT_NO_TEXTHTMLPARSER
void testHitTest();
void largeImage();
+#endif
private:
QTextDocument *doc;
@@ -99,6 +105,7 @@ void tst_QTextDocumentLayout::idealWidth()
QVERIFY(doc->idealWidth() > 0);
}
+#ifndef QT_NO_TEXTHTMLPARSER
// none of the QTextLine items in the document should intersect with the margin rect
void tst_QTextDocumentLayout::lineSeparatorFollowingTable()
{
@@ -145,6 +152,7 @@ void tst_QTextDocumentLayout::lineSeparatorFollowingTable()
}
}
}
+#endif
#ifndef QT_NO_WIDGETS
void tst_QTextDocumentLayout::wrapAtWordBoundaryOrAnywhere()
@@ -184,6 +192,7 @@ void tst_QTextDocumentLayout::inlineImage()
QCOMPARE(doc->pageCount(), 1);
}
+#ifndef QT_NO_TEXTHTMLPARSER
void tst_QTextDocumentLayout::clippedTableCell()
{
const char *html =
@@ -224,6 +233,7 @@ void tst_QTextDocumentLayout::clippedTableCell()
expected.save("expected.png");
QCOMPARE(img, expected);
}
+#endif
void tst_QTextDocumentLayout::floatingTablePageBreak()
{
@@ -323,6 +333,7 @@ void tst_QTextDocumentLayout::blockVisibility()
QCOMPARE(doc->size(), halfSize);
}
+#ifndef QT_NO_TEXTHTMLPARSER
void tst_QTextDocumentLayout::largeImage()
{
auto img = QImage(400, 500, QImage::Format_ARGB32_Premultiplied);
@@ -416,6 +427,7 @@ void tst_QTextDocumentLayout::testHitTest()
QVERIFY(positionY - topMargin <= y);
}
}
+#endif
QTEST_MAIN(tst_QTextDocumentLayout)
#include "tst_qtextdocumentlayout.moc"
diff --git a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp
index d20a2f1ea5..6c6145561d 100644
--- a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp
+++ b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp
@@ -7,7 +7,9 @@
#include <qcoreapplication.h>
#include <qdebug.h>
+#if QT_CONFIG(settings)
#include <qsettings.h>
+#endif
#include <qtextformat.h>
#include <private/qtextformat_p.h>
#include <qtextdocument.h>
@@ -27,7 +29,9 @@ Q_OBJECT
private slots:
void getSetCheck();
void defaultAlignment();
+#if QT_CONFIG(settings)
void testQTextCharFormat() const;
+#endif
void testUnderlinePropertyPrecedence();
void toFormat();
void resolveFont();
@@ -47,6 +51,7 @@ private slots:
#endif
};
+#if QT_CONFIG(settings)
/*! \internal
This (used to) trigger a crash in:
@@ -61,6 +66,7 @@ void tst_QTextFormat::testQTextCharFormat() const
settings.value("test", test);
}
+#endif
// Testing get/set functions
void tst_QTextFormat::getSetCheck()
diff --git a/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp b/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp
index 5311aa6f2b..0048623d0e 100644
--- a/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp
+++ b/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp
@@ -6,6 +6,10 @@
#include <QPainter>
#include <private/qtextimagehandler_p.h>
+using namespace Qt::StringLiterals;
+
+// #define DEBUG_WRITE_HTML
+
class tst_QTextImageHandler : public QObject
{
Q_OBJECT
@@ -18,7 +22,11 @@ private slots:
void cleanup();
void cleanupTestCase();
void loadAtNImages_data();
+#ifndef QT_NO_TEXTHTMLPARSER
void loadAtNImages();
+ void maxWidth_data();
+ void maxWidth();
+#endif
};
tst_QTextImageHandler::tst_QTextImageHandler()
@@ -47,6 +55,7 @@ void tst_QTextImageHandler::loadAtNImages_data()
QTest::addRow("qrc_url") << "qrc:/data/image.png";
}
+#ifndef QT_NO_TEXTHTMLPARSER
void tst_QTextImageHandler::loadAtNImages()
{
QFETCH(QString, imageFile);
@@ -58,7 +67,7 @@ void tst_QTextImageHandler::loadAtNImages()
const auto it = std::find_if(formats.begin(), formats.end(), [](const auto &format){
return format.objectType() == QTextFormat::ImageObject;
});
- QVERIFY(it != formats.end());
+ QCOMPARE_NE(it, formats.end());
const QTextImageFormat format = (*it).toImageFormat();
QTextImageHandler handler;
@@ -75,5 +84,64 @@ void tst_QTextImageHandler::loadAtNImages()
}
}
+void tst_QTextImageHandler::maxWidth_data()
+{
+ QTest::addColumn<QString>("imageFile");
+ QTest::addColumn<QSizeF>("pageSize");
+ QTest::addColumn<QTextLength>("maxWidth");
+ QTest::addColumn<QSizeF>("expectedSize");
+
+ QTest::addRow("constrained-percentage") << QFINDTESTDATA("data/image.png") << QSizeF(16, 16) << QTextLength(QTextLength::PercentageLength, 100) << QSizeF(12, 12);
+ QTest::addRow("not-constrained-percentage") << QFINDTESTDATA("data/image.png") << QSizeF(200, 200) << QTextLength(QTextLength::PercentageLength, 100) << QSizeF(16, 16);
+ QTest::addRow("constrained-fixed") << QFINDTESTDATA("data/image.png") << QSizeF(16, 16) << QTextLength(QTextLength::FixedLength, 5) << QSizeF(5, 5);
+ QTest::addRow("not-constrained-fixed") << QFINDTESTDATA("data/image.png") << QSizeF(200, 200) << QTextLength(QTextLength::FixedLength, 5) << QSizeF(5, 5);
+ QTest::addRow("not-constrained-default") << QFINDTESTDATA("data/image.png") << QSizeF(200, 200) << QTextLength(QTextLength::VariableLength, 5) << QSizeF(16, 16);
+}
+
+void tst_QTextImageHandler::maxWidth()
+{
+ QFETCH(QString, imageFile);
+ QFETCH(QSizeF, pageSize);
+ QFETCH(QTextLength, maxWidth);
+ QFETCH(QSizeF, expectedSize);
+
+ QTextDocument doc;
+ doc.setPageSize(pageSize);
+ doc.setDocumentMargin(2);
+ QTextCursor c(&doc);
+ QString style;
+ if (maxWidth.type() == QTextLength::PercentageLength)
+ style = " style=\"max-width:"_L1 + QString::number(maxWidth.rawValue()) + "%;\""_L1;
+ else if (maxWidth.type() == QTextLength::FixedLength)
+ style = " style=\"max-width:"_L1 + QString::number(maxWidth.rawValue()) + "px;\""_L1;
+ const QString html = "<img src=\"" + imageFile + u'\"' + style + "\">";
+ c.insertHtml(html);
+
+#ifdef DEBUG_WRITE_HTML
+ {
+ QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".html");
+ out.open(QFile::WriteOnly);
+ out.write(html.toLatin1());
+ out.close();
+ }
+ {
+ QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + "_rewrite.html");
+ out.open(QFile::WriteOnly);
+ out.write(doc.toHtml().toLatin1());
+ out.close();
+ }
+#endif
+ const auto formats = doc.allFormats();
+ const auto it = std::find_if(formats.begin(), formats.end(), [](const auto &format){
+ return format.objectType() == QTextFormat::ImageObject;
+ });
+ QCOMPARE_NE(it, formats.end());
+ const QTextImageFormat format = (*it).toImageFormat();
+ QTextImageHandler handler;
+
+ QCOMPARE(handler.intrinsicSize(&doc, 0, format), expectedSize);
+}
+#endif
+
QTEST_MAIN(tst_QTextImageHandler)
#include "tst_qtextimagehandler.moc"
diff --git a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp
index 28eae93f6a..10d44f6d70 100644
--- a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp
+++ b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp
@@ -140,6 +140,7 @@ void tst_QTextList::autoNumberingPrefixAndSuffixHtmlExportImport()
QCOMPARE(list->count(), 28);
+#ifndef QT_NO_TEXTHTMLPARSER
QString htmlExport = doc->toHtml();
QTextDocument importDoc;
importDoc.setHtml(htmlExport);
@@ -152,6 +153,7 @@ void tst_QTextList::autoNumberingPrefixAndSuffixHtmlExportImport()
QCOMPARE(importCursor.currentList()->itemNumber(importCursor.block()), 27);
QCOMPARE(importCursor.currentList()->itemText(importCursor.block()), QLatin1String("\"ab#"));
QCOMPARE(importCursor.currentList()->format().indent(), 10);
+#endif
}
void tst_QTextList::autoNumberingRTL()
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/example.md b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md
index 15b30598e6..8fdad207ae 100644
--- a/tests/auto/gui/text/qtextmarkdownwriter/data/example.md
+++ b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md
@@ -40,7 +40,7 @@ numerals in the same list structure:
1. Introduction
2. Qt Tools
1) Qt Assistant
- 2) Qt Designer
+ 2) Qt Widgets Designer
1. Form Editor
2. Component Architecture
3) Qt Linguist
@@ -70,7 +70,7 @@ column spans, text formatting within cells, and size constraints for columns.
|-------------|------------------------------------|---------------------------|-------------------------|
|9:00 - 11:00 |Introduction to Qt |||
|11:00 - 13:00|Using qmake |Object-oriented Programming|Layouts in Qt |
-|13:00 - 15:00|Qt Designer Tutorial |Extreme Programming |Writing Custom Styles |
+|13:00 - 15:00|Qt Widgets Designer Tutorial |Extreme Programming |Writing Custom Styles |
|15:00 - 17:00|Qt Linguist and Internationalization|Test-Driven Development | |
*Try adding text to the cells in the table and experiment with the alignment of
diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
index d0e1e1cd74..a7e319ef62 100644
--- a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
+++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
@@ -1236,6 +1236,7 @@ void tst_QTextTable::checkBorderAttributes()
QFETCH(QBrush, leftBorderBrush);
QFETCH(QBrush, rightBorderBrush);
+#ifndef QT_NO_TEXTHTMLPARSER
QTextDocument doc;
doc.setHtml(html);
QTextCursor cursor(doc.firstBlock());
@@ -1261,6 +1262,7 @@ void tst_QTextTable::checkBorderAttributes()
QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellRightBorderBrush), rightBorderBrush);
}
}
+#endif
}
void tst_QTextTable::checkTableBorderAttributes_data()
@@ -1317,6 +1319,7 @@ void tst_QTextTable::checkTableBorderAttributes()
QFETCH(QTextFrameFormat::BorderStyle, tableBorderStyle);
QFETCH(QBrush, tableBorderBrush);
+#ifndef QT_NO_TEXTHTMLPARSER
QTextDocument doc;
doc.setHtml(html);
QTextCursor cursor(doc.firstBlock());
@@ -1327,6 +1330,7 @@ void tst_QTextTable::checkTableBorderAttributes()
QCOMPARE(currentTable->format().border(), tableBorderWidth);
QCOMPARE(currentTable->format().borderStyle(), tableBorderStyle);
QCOMPARE(currentTable->format().borderBrush(), tableBorderBrush);
+#endif
}
#ifndef QT_NO_WIDGETS
@@ -1385,6 +1389,7 @@ void tst_QTextTable::columnWidthWithImage()
QFETCH(QString, rightHtml);
QFETCH(QSize, imageSize);
+#ifndef QT_NO_TEXTHTMLPARSER
QTextDocument doc;
doc.setHtml(tableTemplate.arg(leftHtml).arg(rightHtml));
QTextEdit textEdit;
@@ -1404,6 +1409,7 @@ void tst_QTextTable::columnWidthWithImage()
const QRectF rightRect = currentTable->document()->documentLayout()->blockBoundingRect(block);
QCOMPARE(leftRect.size().toSize(), imageSize);
QVERIFY(rightRect.left() > leftRect.right());
+#endif
}
#endif
diff --git a/tests/auto/gui/util/CMakeLists.txt b/tests/auto/gui/util/CMakeLists.txt
index 830a9ff2f0..1efdf85b97 100644
--- a/tests/auto/gui/util/CMakeLists.txt
+++ b/tests/auto/gui/util/CMakeLists.txt
@@ -1,10 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-add_subdirectory(qdesktopservices)
+if(QT_FEATURE_desktopservices)
+ add_subdirectory(qdesktopservices)
+endif()
add_subdirectory(qdoublevalidator)
add_subdirectory(qintvalidator)
add_subdirectory(qregularexpressionvalidator)
add_subdirectory(qtexturefilereader)
-add_subdirectory(qundogroup)
-add_subdirectory(qundostack)
+if(QT_FEATURE_undogroup)
+ add_subdirectory(qundogroup)
+endif()
+if(QT_FEATURE_undocommand)
+ add_subdirectory(qundostack)
+endif()
diff --git a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp
index e08b299209..e75626eda7 100644
--- a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp
+++ b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp
@@ -42,10 +42,6 @@ public slots:
}
};
-#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
-# define CAN_IMPLICITLY_UNSET
-#endif
-
void tst_qdesktopservices::handlers()
{
MyUrlHandler fooHandler;
@@ -53,12 +49,10 @@ void tst_qdesktopservices::handlers()
QDesktopServices::setUrlHandler(QString("foo"), &fooHandler, "handle");
QDesktopServices::setUrlHandler(QString("bar"), &barHandler, "handle");
-#ifndef CAN_IMPLICITLY_UNSET
const auto unsetHandlers = qScopeGuard([] {
QDesktopServices::unsetUrlHandler(u"bar"_s);
QDesktopServices::unsetUrlHandler(u"foo"_s);
});
-#endif
QUrl fooUrl("foo://blub/meh");
QUrl barUrl("bar://hmm/hmmmm");
@@ -68,15 +62,6 @@ void tst_qdesktopservices::handlers()
QCOMPARE(fooHandler.lastHandledUrl.toString(), fooUrl.toString());
QCOMPARE(barHandler.lastHandledUrl.toString(), barUrl.toString());
-
-#ifdef CAN_IMPLICITLY_UNSET
- for (int i = 0; i < 2; ++i)
- QTest::ignoreMessage(QtWarningMsg,
- "Please call QDesktopServices::unsetUrlHandler() before destroying a "
- "registered URL handler object.\n"
- "Support for destroying a registered URL handler object is deprecated, "
- "and will be removed in Qt 6.6.");
-#endif
}
QTEST_MAIN(tst_qdesktopservices)
diff --git a/tests/auto/network/access/CMakeLists.txt b/tests/auto/network/access/CMakeLists.txt
index 44b7d5c1bb..d1130f832e 100644
--- a/tests/auto/network/access/CMakeLists.txt
+++ b/tests/auto/network/access/CMakeLists.txt
@@ -2,19 +2,25 @@
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qhttpheaders)
-add_subdirectory(qnetworkdiskcache)
+if(QT_FEATURE_networkdiskcache)
+ add_subdirectory(qnetworkdiskcache)
+endif()
add_subdirectory(qnetworkcookiejar)
add_subdirectory(qnetworkaccessmanager)
add_subdirectory(qnetworkcookie)
add_subdirectory(qnetworkrequest)
-add_subdirectory(qnetworkrequestfactory)
add_subdirectory(qnetworkreply)
add_subdirectory(qnetworkcachemetadata)
add_subdirectory(qabstractnetworkcache)
-add_subdirectory(qrestaccessmanager)
+if(QT_FEATURE_http)
+ add_subdirectory(qnetworkreply_local)
+ add_subdirectory(qnetworkrequestfactory)
+ add_subdirectory(qrestaccessmanager)
+endif()
if(QT_FEATURE_private_tests)
add_subdirectory(qhttp2connection)
add_subdirectory(qhttpheaderparser)
+ add_subdirectory(qhttpheadershelper)
add_subdirectory(qhttpnetworkconnection)
add_subdirectory(qhttpnetworkreply)
add_subdirectory(hpack)
diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp
index b624f6e436..d9e82330b2 100644
--- a/tests/auto/network/access/http2/tst_http2.cpp
+++ b/tests/auto/network/access/http2/tst_http2.cpp
@@ -25,6 +25,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qthread.h>
#include <QtCore/qurl.h>
+#include <QtCore/qset.h>
#include <cstdlib>
#include <memory>
@@ -95,6 +96,8 @@ private slots:
void authenticationRequired_data();
void authenticationRequired();
+ void unsupportedAuthenticateChallenge();
+
void h2cAllowedAttribute_data();
void h2cAllowedAttribute();
@@ -1243,6 +1246,89 @@ void tst_Http2::authenticationRequired()
QTRY_VERIFY(serverGotSettingsACK);
}
+void tst_Http2::unsupportedAuthenticateChallenge()
+{
+ clearHTTP2State();
+ serverPort = 0;
+
+ if (defaultConnectionType() == H2Type::h2c)
+ QSKIP("This test requires TLS with ALPN to work");
+
+ ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType()));
+ QByteArray responseBody = "Hello"_ba;
+ targetServer->setResponseBody(responseBody);
+ targetServer->setAuthenticationHeader("Bearer realm=\"qt.io accounts\"");
+
+ QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
+ runEventLoop();
+
+ QVERIFY(serverPort != 0);
+
+ nRequests = 1;
+
+ QUrl url = requestUrl(defaultConnectionType());
+ url.setPath("/index.html");
+ QNetworkRequest request(url);
+
+ QByteArray expectedBody = "Hello, World!";
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
+ QScopedPointer<QNetworkReply> reply;
+ reply.reset(manager->post(request, expectedBody));
+
+ bool authenticationRequested = false;
+ connect(manager.get(), &QNetworkAccessManager::authenticationRequired, reply.get(),
+ [&](QNetworkReply *, QAuthenticator *auth) {
+ authenticationRequested = true;
+ });
+
+ bool finishedReceived = false;
+ connect(reply.get(), &QNetworkReply::finished, reply.get(),
+ [&]() { finishedReceived = true; });
+ bool errorReceived = false;
+ connect(reply.get(), &QNetworkReply::errorOccurred, reply.get(),
+ [&]() { errorReceived = true; });
+
+ QSet<quint32> receivedDataOnStreams;
+ connect(targetServer.get(), &Http2Server::receivedDATAFrame, reply.get(),
+ [&receivedDataOnStreams](quint32 streamID, const QByteArray &body) {
+ Q_UNUSED(body);
+ receivedDataOnStreams.insert(streamID);
+ });
+
+ // Use queued connection so that the finished signal can be emitted and the
+ // isFinished property can be set.
+ connect(reply.get(), &QNetworkReply::errorOccurred, this,
+ &tst_Http2::replyFinishedWithError, Qt::QueuedConnection);
+
+ // Since we're using self-signed certificates, ignore SSL errors:
+ reply->ignoreSslErrors();
+
+ runEventLoop();
+ STOP_ON_FAILURE
+ QVERIFY2(reply->isFinished(),
+ "The reply should error out if authentication fails, or finish if it succeeds");
+
+ QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
+ QVERIFY(reply->isFinished());
+ QVERIFY(errorReceived);
+ QVERIFY(finishedReceived);
+ QCOMPARE(receivedDataOnStreams.size(), 1);
+ QVERIFY(receivedDataOnStreams.contains(1)); // the original, failed, request
+
+ QVERIFY(!authenticationRequested);
+
+ // We should not have sent any authentication headers to the server, since
+ // we don't support the challenge.
+ const QByteArray reqAuthHeader = targetServer->requestAuthorizationHeader();
+ QVERIFY(reqAuthHeader.isEmpty());
+
+ // In the `!success` case we need to wait for the server to emit this or it might cause issues
+ // in the next test running after this. In the `success` case we anyway expect it to have been
+ // received.
+ QTRY_VERIFY(serverGotSettingsACK);
+
+}
+
void tst_Http2::h2cAllowedAttribute_data()
{
QTest::addColumn<bool>("h2cAllowed");
diff --git a/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp
index 9bdef9bbe1..95f067a66e 100644
--- a/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp
+++ b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp
@@ -50,6 +50,7 @@ private:
};
+#if QT_CONFIG(networkdiskcache)
class NetworkDiskCache : public QNetworkDiskCache
{
Q_OBJECT
@@ -72,6 +73,7 @@ public:
QTemporaryDir tempDir;
bool gotData;
};
+#endif
tst_QAbstractNetworkCache::tst_QAbstractNetworkCache()
@@ -254,10 +256,12 @@ void tst_QAbstractNetworkCache::runTest()
QFETCH(bool, fetchFromCache);
QNetworkAccessManager manager;
+#if QT_CONFIG(networkdiskcache)
NetworkDiskCache *diskCache = new NetworkDiskCache(&manager);
QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString()));
manager.setCache(diskCache);
QCOMPARE(diskCache->gotData, false);
+#endif
QUrl realUrl = url.contains("://") ? url : TESTFILE + url;
QNetworkRequest request(realUrl);
@@ -266,7 +270,9 @@ void tst_QAbstractNetworkCache::runTest()
QNetworkReply *reply = manager.get(request);
QSignalSpy downloaded1(reply, SIGNAL(finished()));
QTRY_COMPARE(downloaded1.size(), 1);
+#if QT_CONFIG(networkdiskcache)
QCOMPARE(diskCache->gotData, false);
+#endif
QByteArray goodData = reply->readAll();
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheLoadControl);
@@ -293,7 +299,9 @@ void tst_QAbstractNetworkCache::runTest()
std::sort(rawHeaderList.begin(), rawHeaderList.end());
std::sort(rawHeaderList2.begin(), rawHeaderList2.end());
}
+#if QT_CONFIG(networkdiskcache)
QCOMPARE(diskCache->gotData, fetchFromCache);
+#endif
}
void tst_QAbstractNetworkCache::checkSynchronous()
@@ -305,10 +313,12 @@ void tst_QAbstractNetworkCache::checkSynchronous()
QFETCH(bool, fetchFromCache);
QNetworkAccessManager manager;
+#if QT_CONFIG(networkdiskcache)
NetworkDiskCache *diskCache = new NetworkDiskCache(&manager);
QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString()));
manager.setCache(diskCache);
QCOMPARE(diskCache->gotData, false);
+#endif
QUrl realUrl = url.contains("://") ? url : TESTFILE + url;
QNetworkRequest request(realUrl);
@@ -320,7 +330,9 @@ void tst_QAbstractNetworkCache::checkSynchronous()
// prime the cache
QNetworkReply *reply = manager.get(request);
QVERIFY(reply->isFinished()); // synchronous
+#if QT_CONFIG(networkdiskcache)
QCOMPARE(diskCache->gotData, false);
+#endif
QByteArray goodData = reply->readAll();
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheLoadControl);
@@ -348,15 +360,19 @@ void tst_QAbstractNetworkCache::checkSynchronous()
std::sort(rawHeaderList.begin(), rawHeaderList.end());
std::sort(rawHeaderList2.begin(), rawHeaderList2.end());
}
+#if QT_CONFIG(networkdiskcache)
QCOMPARE(diskCache->gotData, fetchFromCache);
+#endif
}
void tst_QAbstractNetworkCache::deleteCache()
{
QNetworkAccessManager manager;
+#if QT_CONFIG(networkdiskcache)
NetworkDiskCache *diskCache = new NetworkDiskCache(&manager);
QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString()));
manager.setCache(diskCache);
+#endif
QString url = "httpcachetest_cachecontrol.cgi?max-age=1000";
QNetworkRequest request(QUrl(TESTFILE + url));
diff --git a/tests/auto/network/access/qhttpheadershelper/CMakeLists.txt b/tests/auto/network/access/qhttpheadershelper/CMakeLists.txt
new file mode 100644
index 0000000000..75935d2844
--- /dev/null
+++ b/tests/auto/network/access/qhttpheadershelper/CMakeLists.txt
@@ -0,0 +1,15 @@
+# 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_qhttpheadershelper LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qhttpheadershelper
+ SOURCES
+ tst_qhttpheadershelper.cpp
+ LIBRARIES
+ Qt::NetworkPrivate
+)
diff --git a/tests/auto/network/access/qhttpheadershelper/tst_qhttpheadershelper.cpp b/tests/auto/network/access/qhttpheadershelper/tst_qhttpheadershelper.cpp
new file mode 100644
index 0000000000..b204d0cbe3
--- /dev/null
+++ b/tests/auto/network/access/qhttpheadershelper/tst_qhttpheadershelper.cpp
@@ -0,0 +1,76 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtNetwork/qhttpheaders.h>
+#include <QtNetwork/private/qhttpheadershelper_p.h>
+
+#include <QtTest/qtest.h>
+
+using namespace Qt::StringLiterals;
+
+class tst_QHttpHeadersHelper : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testCompareStrict();
+
+private:
+ static constexpr QAnyStringView n1{"name1"};
+ static constexpr QAnyStringView n2{"name2"};
+ static constexpr QAnyStringView v1{"value1"};
+ static constexpr QAnyStringView v2{"value2"};
+ static constexpr QAnyStringView N1{"NAME1"};
+ static constexpr QAnyStringView N2{"NAME2"};
+ static constexpr QAnyStringView V1{"VALUE1"};
+ static constexpr QAnyStringView V2{"VALUE2"};
+};
+
+void tst_QHttpHeadersHelper::testCompareStrict()
+{
+ using namespace QHttpHeadersHelper;
+
+ // Basic comparisons
+ QHttpHeaders h1;
+ QHttpHeaders h2;
+ QVERIFY(compareStrict(h1, h2)); // empties
+ h1.append(n1, v1);
+ QVERIFY(compareStrict(h1, h1)); // self
+ h2.append(n1, v1);
+ QVERIFY(compareStrict(h1, h2));
+ h1.append(n2, v2);
+ QVERIFY(!compareStrict(h1, h2));
+ h1.removeAll(n2);
+ QVERIFY(compareStrict(h1, h2));
+
+ // Order-sensitivity
+ h1.clear();
+ h2.clear();
+ // Same headers but in different order
+ h1.append(n1, v1);
+ h1.append(n2, v2);
+ h2.append(n2, v2);
+ h2.append(n1, v1);
+ QVERIFY(!compareStrict(h1, h2));
+
+ // Different number of headers
+ h1.clear();
+ h2.clear();
+ h1.append(n1, v1);
+ h2.append(n1, v1);
+ h2.append(n2, v2);
+ QVERIFY(!compareStrict(h1, h2));
+
+ // Same header name, multiple values
+ h1.clear();
+ h2.clear();
+ h1.append(n1, v1);
+ h1.append(n1, v2);
+ h2.append(n1, v1);
+ QVERIFY(!compareStrict(h1, h2));
+ h2.append(n1, v2);
+ QVERIFY(compareStrict(h1, h2));
+}
+
+QTEST_MAIN(tst_QHttpHeadersHelper)
+#include "tst_qhttpheadershelper.moc"
diff --git a/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp
index f811943dea..d49195efc6 100644
--- a/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp
+++ b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp
@@ -29,6 +29,8 @@ private slots:
void operatorEqualEqual();
void rawHeaders_data();
void rawHeaders();
+ void headers_data();
+ void headers();
void saveToDisk_data();
void saveToDisk();
void url_data();
@@ -114,6 +116,12 @@ void tst_QNetworkCacheMetaData::isValid_data()
QNetworkCacheMetaData data5;
data5.setSaveToDisk(false);
QTest::newRow("valid-5") << data5 << true;
+
+ QNetworkCacheMetaData data6;
+ QHttpHeaders httpHeaders;
+ httpHeaders.append("name", "value");
+ data6.setHeaders(httpHeaders);
+ QTest::newRow("valid-6") << data6 << true;
}
// public bool isValid() const
@@ -153,6 +161,9 @@ void tst_QNetworkCacheMetaData::operatorEqual_data()
QNetworkCacheMetaData::RawHeaderList headers;
headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar"));
data.setRawHeaders(headers);
+ QHttpHeaders httpHeaders;
+ httpHeaders.append("name", "value");
+ data.setHeaders(httpHeaders);
data.setLastModified(QDateTime::currentDateTime());
data.setExpirationDate(QDateTime::currentDateTime());
data.setSaveToDisk(false);
@@ -212,6 +223,18 @@ void tst_QNetworkCacheMetaData::operatorEqualEqual_data()
QTest::newRow("valid-5-4") << data5 << data2 << false;
QTest::newRow("valid-5-5") << data5 << data3 << false;
QTest::newRow("valid-5-6") << data5 << data4 << false;
+
+ QNetworkCacheMetaData data6;
+ QHttpHeaders httpHeaders;
+ httpHeaders.append("name", "value");
+ data6.setHeaders(httpHeaders);
+ QTest::newRow("valid-6-1") << data6 << QNetworkCacheMetaData() << false;
+ QTest::newRow("valid-6-2") << data6 << data6 << true;
+ QTest::newRow("valid-6-3") << data6 << data1 << false;
+ QTest::newRow("valid-6-4") << data6 << data2 << false;
+ QTest::newRow("valid-6-5") << data6 << data3 << false;
+ QTest::newRow("valid-6-6") << data6 << data4 << false;
+ QTest::newRow("valid-6-7") << data6 << data5 << false;
}
// public bool operator==(QNetworkCacheMetaData const& other) const
@@ -231,7 +254,11 @@ void tst_QNetworkCacheMetaData::rawHeaders_data()
QTest::newRow("null") << QNetworkCacheMetaData::RawHeaderList();
QNetworkCacheMetaData::RawHeaderList headers;
headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar"));
- QTest::newRow("valie") << headers;
+ QTest::newRow("valid") << headers;
+ headers.append(QNetworkCacheMetaData::RawHeader("n1", "V1, v2, v3"));
+ headers.append(QNetworkCacheMetaData::RawHeader("n2", "V2"));
+ headers.append(QNetworkCacheMetaData::RawHeader("set-cookie", "v1\nV2\nV3"));
+ QTest::newRow("valid-2") << headers;
}
// public QNetworkCacheMetaData::RawHeaderList rawHeaders() const
@@ -245,6 +272,25 @@ void tst_QNetworkCacheMetaData::rawHeaders()
QCOMPARE(data.rawHeaders(), rawHeaders);
}
+void tst_QNetworkCacheMetaData::headers_data()
+{
+ QTest::addColumn<QHttpHeaders>("httpHeaders");
+ QTest::newRow("null") << QHttpHeaders();
+ QHttpHeaders headers;
+ headers.append("foo", "Bar");
+ QTest::newRow("valid") << headers;
+}
+
+void tst_QNetworkCacheMetaData::headers()
+{
+ QFETCH(QHttpHeaders, httpHeaders);
+
+ SubQNetworkCacheMetaData data;
+
+ data.setHeaders(httpHeaders);
+ QCOMPARE(data.headers().toListOfPairs(), httpHeaders.toListOfPairs());
+}
+
void tst_QNetworkCacheMetaData::saveToDisk_data()
{
QTest::addColumn<bool>("saveToDisk");
@@ -289,6 +335,9 @@ void tst_QNetworkCacheMetaData::stream()
QNetworkCacheMetaData::RawHeaderList headers;
headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar"));
data.setRawHeaders(headers);
+ QHttpHeaders httpHeaders;
+ httpHeaders.append("name", "value");
+ data.setHeaders(httpHeaders);
data.setLastModified(QDateTime::currentDateTime());
data.setExpirationDate(QDateTime::currentDateTime());
data.setSaveToDisk(false);
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index a4a05b18f5..a26d2c809b 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -35,8 +35,10 @@
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
+#if QT_CONFIG(localserver)
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
+#endif
#include <QtNetwork/QHostInfo>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
@@ -44,14 +46,18 @@
#include <QtNetwork/QAbstractNetworkCache>
#include <QtNetwork/qauthenticator.h>
#include <QtNetwork/qnetworkaccessmanager.h>
+#if QT_CONFIG(networkdiskcache)
#include <QtNetwork/qnetworkdiskcache.h>
+#endif
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkreply.h>
-#include <QtNetwork/QHttp1Configuration>
#include <QtNetwork/qnetworkcookie.h>
#include <QtNetwork/QNetworkCookieJar>
+#if QT_CONFIG(http)
#include <QtNetwork/QHttpPart>
#include <QtNetwork/QHttpMultiPart>
+#include <QtNetwork/QHttp1Configuration>
+#endif
#include <QtNetwork/QNetworkProxyQuery>
#if QT_CONFIG(ssl)
#include <QtNetwork/qsslerror.h>
@@ -129,14 +135,14 @@ class tst_QNetworkReply: public QObject
static QString tempRedirectReplyStr() {
QString s = "HTTP/1.1 307 Temporary Redirect\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %1\r\n"
"\r\n";
return s;
}
static QString movedReplyStr() {
QString s = "HTTP/1.1 301 Moved Permanently\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %1\r\n"
"\r\n";
return s;
@@ -144,7 +150,7 @@ class tst_QNetworkReply: public QObject
static QString foundReplyStr() {
QString s = "HTTP/1.1 302 Found\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %1\r\n"
"\r\n";
return s;
@@ -152,7 +158,7 @@ class tst_QNetworkReply: public QObject
static QString permRedirectReplyStr() {
QString s = "HTTP/1.1 308 Permanent Redirect\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %1\r\n"
"\r\n";
return s;
@@ -194,8 +200,10 @@ public:
~tst_QNetworkReply();
QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
QNetworkReplyPtr &reply, const QByteArray &data = QByteArray());
+#if QT_CONFIG(http)
QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
QHttpMultiPart *multiPart, const QByteArray &verb);
+#endif
QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
const QByteArray &verb, QIODevice *data);
@@ -261,17 +269,21 @@ private Q_SLOTS:
void putToHttp();
void putToHttpSynchronous_data();
void putToHttpSynchronous();
+#if QT_CONFIG(http)
void putToHttpMultipart_data();
void putToHttpMultipart();
+#endif
void putWithoutBody();
void putWithoutBody_data();
void postToHttp_data();
void postToHttp();
void postToHttpSynchronous_data();
void postToHttpSynchronous();
+#if QT_CONFIG(http)
void postToHttpMultipart_data();
void postToHttpMultipart();
void multipartSkipIndices(); // QTBUG-32534
+#endif
void postWithoutBody_data();
void postWithoutBody();
#if QT_CONFIG(ssl)
@@ -342,8 +354,10 @@ private Q_SLOTS:
void ioPutToFileFromFile();
void ioPutToFileFromSocket_data();
void ioPutToFileFromSocket();
+#if QT_CONFIG(localserver)
void ioPutToFileFromLocalSocket_data();
void ioPutToFileFromLocalSocket();
+#endif
void ioPutToFileFromProcess_data();
void ioPutToFileFromProcess();
void ioPutToFtpFromFile_data();
@@ -449,7 +463,9 @@ private Q_SLOTS:
void ioGetFromHttpWithoutContentLength();
void ioGetFromHttpBrokenChunkedEncoding();
+#if QT_CONFIG(http)
void qtbug12908compressedHttpReply();
+#endif
void compressedHttpReplyBrokenGzip();
void getFromUnreachableIp();
@@ -468,7 +484,9 @@ private Q_SLOTS:
void qtbug27161httpHeaderMayBeDamaged_data();
void qtbug27161httpHeaderMayBeDamaged();
+#if QT_CONFIG(networkdiskcache)
void qtbug28035browserDoesNotLoadQtProjectOrgCorrectly();
+#endif
void qtbug45581WrongReplyStatusCode();
@@ -484,8 +502,10 @@ private Q_SLOTS:
void varyingCacheExpiry_data();
void varyingCacheExpiry();
+#if QT_CONFIG(http)
void amountOfHttp1ConnectionsQtbug25280_data();
void amountOfHttp1ConnectionsQtbug25280();
+#endif
void dontInsertPartialContentIntoTheCache();
@@ -521,12 +541,16 @@ private Q_SLOTS:
void ioHttpCookiesDuringRedirect();
void ioHttpRedirect_data();
void ioHttpRedirect();
+#if QT_CONFIG(networkdiskcache)
void ioHttpRedirectWithCache();
+#endif
void ioHttpRedirectFromLocalToRemote();
void ioHttpRedirectPostPut_data();
void ioHttpRedirectPostPut();
+#if QT_CONFIG(http)
void ioHttpRedirectMultipartPost_data();
void ioHttpRedirectMultipartPost();
+#endif
void ioHttpRedirectDelete();
void ioHttpRedirectCustom();
void ioHttpRedirectWithUploadDevice_data();
@@ -540,16 +564,20 @@ private Q_SLOTS:
void autoDeleteReplies_data();
void autoDeleteReplies();
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
void requestWithTimeout_data();
void requestWithTimeout();
+#endif
void moreActivitySignals_data();
void moreActivitySignals();
void contentEncoding_data();
void contentEncoding();
+#if QT_CONFIG(http)
void contentEncodingBigPayload_data();
void contentEncodingBigPayload();
+#endif
void cacheWithContentEncoding_data();
void cacheWithContentEncoding();
void downloadProgressWithContentEncoding_data();
@@ -560,8 +588,13 @@ private Q_SLOTS:
void notFoundWithCompression_data();
void notFoundWithCompression();
+#if QT_CONFIG(http)
+ void qhttpPartDebug_data();
+ void qhttpPartDebug();
+
void qtbug68821proxyError_data();
void qtbug68821proxyError();
+#endif
void abortAndError();
@@ -1437,6 +1470,7 @@ void tst_QNetworkReply::storeSslConfiguration()
}
#endif
+#if QT_CONFIG(http)
QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request,
QNetworkReplyPtr &reply,
QHttpMultiPart *multiPart,
@@ -1468,6 +1502,7 @@ QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request,
}
return QString();
}
+#endif
QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
const QNetworkRequest &request,
@@ -2753,7 +2788,7 @@ void tst_QNetworkReply::postToHttp()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply;
QFETCH(QByteArray, data);
@@ -2780,7 +2815,7 @@ void tst_QNetworkReply::postToHttpSynchronous()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
@@ -2802,6 +2837,7 @@ void tst_QNetworkReply::postToHttpSynchronous()
QCOMPARE(uploadedData, md5sum.toHex());
}
+#if QT_CONFIG(http)
void tst_QNetworkReply::postToHttpMultipart_data()
{
QTest::addColumn<QUrl>("url");
@@ -2841,8 +2877,8 @@ void tst_QNetworkReply::postToHttpMultipart_data()
QHttpMultiPart *customMultiPart = new QHttpMultiPart;
customMultiPart->append(textPart);
- expectedData = "header: Content-Type, value: 'text/plain'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
+ expectedData = "header: content-type, value: 'text/plain'\n"
+ "header: content-disposition, value: 'form-data; name=\"text\"'\n"
"content: 7 bytes\n"
"\n";
QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom");
@@ -2878,18 +2914,18 @@ void tst_QNetworkReply::postToHttpMultipart_data()
multiPart3->append(textPart);
multiPart3->append(textPart2);
multiPart3->append(textPart3);
- expectedData = "header: Content-Type, value: 'text/plain'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
+ expectedData = "header: content-type, value: 'text/plain'\n"
+ "header: content-disposition, value: 'form-data; name=\"text\"'\n"
"content: 7 bytes\n"
"\n"
- "header: Content-Type, value: 'text/plain'\n"
- "header: myRawHeader, value: 'myValue'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n"
+ "header: content-type, value: 'text/plain'\n"
+ "header: myrawheader, value: 'myValue'\n"
+ "header: content-disposition, value: 'form-data; name=\"text2\"'\n"
"content: some more bytes\n"
"\n"
- "header: Content-Type, value: 'text/plain'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n"
- "header: Content-Location, value: 'http://my.test.location.tld'\n"
+ "header: content-type, value: 'text/plain'\n"
+ "header: content-disposition, value: 'form-data; name=\"text3\"'\n"
+ "header: content-location, value: 'http://my.test.location.tld'\n"
"content: even more bytes\n\n";
QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative");
@@ -3111,6 +3147,7 @@ void tst_QNetworkReply::multipartSkipIndices() // QTBUG-32534
}
multiPart->deleteLater();
}
+#endif
void tst_QNetworkReply::postWithoutBody_data()
{
@@ -3153,6 +3190,7 @@ void tst_QNetworkReply::postWithoutBody()
QCOMPARE(server.foundContentLength, client_data);
}
+#if QT_CONFIG(http)
void tst_QNetworkReply::putToHttpMultipart_data()
{
postToHttpMultipart_data();
@@ -3197,6 +3235,7 @@ void tst_QNetworkReply::putToHttpMultipart()
// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
QCOMPARE(replyData, expectedReplyData);
}
+#endif
#if QT_CONFIG(ssl)
void tst_QNetworkReply::putToHttps_data()
@@ -3308,7 +3347,7 @@ void tst_QNetworkReply::postToHttps()
QSslConfiguration conf;
conf.setCaCertificates(certs);
request.setSslConfiguration(conf);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply;
QFETCH(QByteArray, data);
@@ -3342,7 +3381,7 @@ void tst_QNetworkReply::postToHttpsSynchronous()
QSslConfiguration conf;
conf.setCaCertificates(certs);
request.setSslConfiguration(conf);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
@@ -3364,6 +3403,7 @@ void tst_QNetworkReply::postToHttpsSynchronous()
QCOMPARE(uploadedData, md5sum.toHex());
}
+#if QT_CONFIG(http)
void tst_QNetworkReply::postToHttpsMultipart_data()
{
if (isSecureTransport)
@@ -3414,7 +3454,7 @@ void tst_QNetworkReply::postToHttpsMultipart()
expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
QCOMPARE(replyData, expectedReplyData);
}
-
+#endif
#endif // QT_CONFIG(ssl)
void tst_QNetworkReply::deleteFromHttp_data()
@@ -4458,7 +4498,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
QByteArray reply200 =
"HTTP/1.0 200\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: no-store\r\n"
"Content-length: 8\r\n"
"\r\n"
@@ -4593,7 +4633,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
QByteArray reply206 =
"HTTP/1.0 206\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: no-cache\r\n"
"Content-Range: bytes 2-6/8\r\n"
"Content-length: 4\r\n"
@@ -4996,6 +5036,7 @@ void tst_QNetworkReply::ioPutToFileFromSocket()
QCOMPARE(contents, data);
}
+#if QT_CONFIG(localserver)
void tst_QNetworkReply::ioPutToFileFromLocalSocket_data()
{
putToFile_data();
@@ -5039,6 +5080,7 @@ void tst_QNetworkReply::ioPutToFileFromLocalSocket()
QByteArray contents = file.readAll();
QCOMPARE(contents, data);
}
+#endif
// Currently no stdin/out supported for Windows CE.
void tst_QNetworkReply::ioPutToFileFromProcess_data()
@@ -5202,7 +5244,7 @@ void tst_QNetworkReply::ioPostToHttpFromFile()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &sourceFile));
@@ -5279,7 +5321,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocket()
socketpair.endPoints[0]->write(data);
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
manager.setProxy(proxy);
QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
@@ -5353,7 +5395,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
true);
@@ -5384,7 +5426,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &sourceFile));
connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
@@ -5410,7 +5452,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
// only send 5 bytes
request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
@@ -5441,7 +5483,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &uploadBuffer));
connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
@@ -5469,7 +5511,7 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
// disallow buffering
request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
@@ -5554,7 +5596,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
QUrl url = QUrl(QLatin1String("https://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/'));
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, sourceFile));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
@@ -5708,7 +5750,7 @@ void tst_QNetworkReply::ioPostToHttpUploadProgress()
// create the request
QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &sourceFile));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -5776,7 +5818,7 @@ void tst_QNetworkReply::emitAllUploadProgressSignals()
QUrl url = QUrl(QLatin1String("http://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/'));
QNetworkRequest normalRequest(url);
- normalRequest.setRawHeader("Content-Type", "application/octet-stream");
+ normalRequest.setRawHeader("content-type", "application/octet-stream");
QNetworkRequest catchAllSignalsRequest(normalRequest);
catchAllSignalsRequest.setAttribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute, true);
@@ -5827,7 +5869,7 @@ void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
// create the request
QUrl url = QUrl(QLatin1String("http://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/'));
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &buffer));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -5873,7 +5915,11 @@ void tst_QNetworkReply::lastModifiedHeaderForFile()
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
- QCOMPARE(header, fileInfo.lastModified());
+ QDateTime expected = fileInfo.lastModified();
+ // remove msecs, HTTP dates don't support it
+ expected = expected.addMSecs(-expected.time().msec());
+
+ QCOMPARE(header.toUTC(), expected.toUTC());
}
void tst_QNetworkReply::lastModifiedHeaderForHttp()
@@ -6179,7 +6225,7 @@ void tst_QNetworkReply::receiveCookiesFromHttp()
QByteArray data = cookieString.toLatin1() + '\n';
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/set-cookie.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply;
RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
@@ -6207,7 +6253,7 @@ void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/set-cookie.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
true);
@@ -7485,6 +7531,7 @@ void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding()
QCOMPARE(reply->error(), QNetworkReply::NoError);
}
+#if QT_CONFIG(http)
// TODO:
// Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport.
// Then have a custom HTTP server that waits after this chunk so the returning gets
@@ -7513,6 +7560,7 @@ void tst_QNetworkReply::qtbug12908compressedHttpReply()
QCOMPARE(reply->size(), qint64(16384));
QCOMPARE(reply->readAll(), QByteArray(16384, '\0'));
}
+#endif
void tst_QNetworkReply::compressedHttpReplyBrokenGzip()
{
@@ -8039,11 +8087,12 @@ void tst_QNetworkReply::qtbug27161httpHeaderMayBeDamaged(){
QCOMPARE(reply->readAll(), QByteArray("ABC"));
}
+#if QT_CONFIG(networkdiskcache)
void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
QByteArray getReply =
"HTTP/1.1 200\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: max-age = 6000\r\n"
"\r\n"
"GET";
@@ -8051,7 +8100,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
QByteArray postReply =
"HTTP/1.1 200\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: max-age = 6000\r\n"
"Content-length: 4\r\n"
"\r\n"
@@ -8060,7 +8109,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
QByteArray putReply =
"HTTP/1.1 201\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: max-age = 6000\r\n"
"\r\n";
@@ -8098,7 +8147,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
server.clearHeaderParserState();
server.setDataToTransmit(postReply);
- request.setRawHeader("Content-Type", "text/plain");
+ request.setRawHeader("content-type", "text/plain");
reply.reset(manager.post(request, postData));
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
@@ -8163,6 +8212,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
QCOMPARE(reply->readAll(), QByteArray("GET"));
QCOMPARE(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), true);
}
+#endif
void tst_QNetworkReply::qtbug45581WrongReplyStatusCode()
{
@@ -8548,6 +8598,7 @@ public:
}
};
+#if QT_CONFIG(http)
void tst_QNetworkReply::amountOfHttp1ConnectionsQtbug25280_data()
{
QTest::addColumn<int>("amount");
@@ -8588,13 +8639,14 @@ void tst_QNetworkReply::amountOfHttp1ConnectionsQtbug25280()
}
QCOMPARE(server.receivedSockets.size(), amount);
}
+#endif
void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
{
QByteArray reply206 =
"HTTP/1.0 206\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: no-cache\r\n"
"Content-Range: bytes 2-6/8\r\n"
"Content-length: 4\r\n"
@@ -8651,7 +8703,7 @@ void tst_QNetworkReply::synchronousAuthenticationCache()
"WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
"Content-Length: 4\r\n"
"Connection: close\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"\r\n"
"auth";
QRegularExpression rx("authorization: Basic ([^\r\n]*)\r\n");
@@ -8660,7 +8712,7 @@ void tst_QNetworkReply::synchronousAuthenticationCache()
if (QByteArray::fromBase64(match.captured(1).toLatin1()) == "login:password") {
dataToTransmit =
"HTTP/1.0 200 OK\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Content-Length: 2\r\n"
"\r\n"
"OK";
@@ -9030,7 +9082,7 @@ void tst_QNetworkReply::ioHttpRedirectErrors_data()
QTest::addColumn<QNetworkReply::NetworkError>("error");
QString tempRedirectReply = QString("HTTP/1.1 307 Temporary Redirect\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: http://localhost:%1\r\n\r\n");
QTest::newRow("too-many-redirects") << "http://localhost" << tempRedirectReply << QNetworkReply::TooManyRedirectsError;
@@ -9338,7 +9390,7 @@ void tst_QNetworkReply::ioHttpRedirect()
targetUrl.setPort(target.serverPort());
QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %2\r\n"
"\r\n").arg(status, targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1(), false);
@@ -9356,6 +9408,7 @@ void tst_QNetworkReply::ioHttpRedirect()
QVERIFY(validateRedirectedResponseHeaders(reply));
}
+#if QT_CONFIG(networkdiskcache)
/*
Test that, if we load a redirect from cache, we don't treat the request to
the destination of the redirect as a redirect.
@@ -9366,7 +9419,7 @@ void tst_QNetworkReply::ioHttpRedirectWithCache()
{
// Disallow caching the result so that the second request must also send the request
QByteArray http200ResponseNoCache = "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-Control: no-cache\r\n"
"\r\nHello";
@@ -9376,7 +9429,7 @@ void tst_QNetworkReply::ioHttpRedirectWithCache()
// A cache-able redirect reply
QString redirectReply = QStringLiteral("HTTP/1.1 308\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %1\r\n"
"Cache-Control: max-age=3600\r\n"
"\r\nYou're being redirected").arg(targetUrl.toString());
@@ -9413,6 +9466,7 @@ void tst_QNetworkReply::ioHttpRedirectWithCache()
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QVERIFY(validateRedirectedResponseHeaders(reply));
}
+#endif
void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote()
{
@@ -9488,7 +9542,7 @@ void tst_QNetworkReply::ioHttpRedirectPostPut()
QUrl targetUrl("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %2\r\n"
"\r\n").arg(status, targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1());
@@ -9507,6 +9561,7 @@ void tst_QNetworkReply::ioHttpRedirectPostPut()
QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
}
+#if QT_CONFIG(http)
void tst_QNetworkReply::ioHttpRedirectMultipartPost_data()
{
postToHttpMultipart_data();
@@ -9567,6 +9622,7 @@ void tst_QNetworkReply::ioHttpRedirectMultipartPost()
// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
QCOMPARE(replyData, expectedReplyData);
}
+#endif
void tst_QNetworkReply::ioHttpRedirectDelete()
{
@@ -9642,7 +9698,7 @@ void tst_QNetworkReply::ioHttpRedirectWithUploadDevice()
targetUrl.setPort(target.serverPort());
QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %2\r\n"
"\r\n").arg(status, targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1());
@@ -9676,8 +9732,8 @@ void tst_QNetworkReply::ioHttpRedirectWithUploadDevice()
// we shouldn't send Content-Length with not content (esp. for GET)
QVERIFY2(!target.receivedData.contains("Content-Length"),
"Target server should not have received a Content-Length header");
- QVERIFY2(!target.receivedData.contains("Content-Type"),
- "Target server should not have received a Content-Type header");
+ QVERIFY2(!target.receivedData.contains("content-type"),
+ "Target server should not have received a content-type header");
}
}
@@ -10008,6 +10064,7 @@ void tst_QNetworkReply::autoDeleteReplies()
}
}
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
void tst_QNetworkReply::requestWithTimeout_data()
{
using Operation = QNetworkAccessManager::Operation;
@@ -10045,7 +10102,7 @@ void tst_QNetworkReply::requestWithTimeout()
server.stopTransfer = true;
QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
if (reqInt > 0)
request.setTransferTimeout(reqInt);
if (reqChrono > 0ms)
@@ -10067,6 +10124,7 @@ void tst_QNetworkReply::requestWithTimeout()
QCOMPARE(spy.size(), 1);
QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
}
+#endif
void tst_QNetworkReply::moreActivitySignals_data()
{
@@ -10097,7 +10155,7 @@ void tst_QNetworkReply::moreActivitySignals()
QNetworkRequest request(url);
QNetworkReplyPtr reply;
if (postWithData) {
- request.setRawHeader("Content-Type", "text/plain");
+ request.setRawHeader("content-type", "text/plain");
reply.reset(manager.post(request, "Hello, world!"));
} else {
reply.reset(manager.get(request));
@@ -10118,7 +10176,7 @@ void tst_QNetworkReply::moreActivitySignals()
// Second request will not send socketStartedConnecting because of keep-alive, so don't check it.
QNetworkReplyPtr secondreply;
if (postWithData) {
- request.setRawHeader("Content-Type", "text/plain");
+ request.setRawHeader("content-type", "text/plain");
secondreply.reset(manager.post(request, "Hello, world!"));
} else {
secondreply.reset(manager.get(request));
@@ -10239,6 +10297,7 @@ void tst_QNetworkReply::contentEncoding()
}
}
+#if QT_CONFIG(http)
void tst_QNetworkReply::contentEncodingBigPayload_data()
{
QTest::addColumn<QByteArray>("encoding");
@@ -10297,6 +10356,7 @@ void tst_QNetworkReply::contentEncodingBigPayload()
}
QCOMPARE(total, expectedSize);
}
+#endif
void tst_QNetworkReply::cacheWithContentEncoding_data()
{
@@ -10479,6 +10539,60 @@ void tst_QNetworkReply::notFoundWithCompression()
QCOMPARE(reply->readAll(), expected);
}
+#if QT_CONFIG(http)
+void tst_QNetworkReply::qhttpPartDebug_data()
+{
+ QTest::addColumn<QByteArray>("header_data");
+ QTest::addColumn<QByteArray>("raw_header_data");
+ QTest::addColumn<QList<QByteArray>>("expected_header_values");
+ QTest::addColumn<bool>("overwrite");
+
+ QTest::newRow("header-data-set") << "form-data; name=\"prompt\""_ba << ""_ba
+ << (QList<QByteArray>() << "form-data; name=\"prompt\""_ba) << false;
+ QTest::newRow("raw-header-data-set") << ""_ba << "thisismykeyherebutnotreally"_ba
+ << (QList<QByteArray>() << "thisismykeyherebutnotreally"_ba) << false;
+ QTest::newRow("both-set") << "form-data; name=\"prompt\""_ba
+ << "thisismykeyherebutnotreally"_ba
+ << (QList<QByteArray>()
+ << "form-data; name=\"prompt\""_ba
+ << "thisismykeyherebutnotreally"_ba) << false;
+ QTest::newRow("overwrite") << "form-data; name=\"prompt\""_ba
+ << "thisismykeyherebutnotreally"_ba
+ << (QList<QByteArray>()
+ << "thisismykeyherebutnotreally"_ba
+ << "thisismykeyherebutnotreally"_ba) << true;
+}
+
+void tst_QNetworkReply::qhttpPartDebug()
+{
+ QFETCH(const QByteArray, header_data);
+ QFETCH(const QByteArray, raw_header_data);
+ QFETCH(const QList<QByteArray>, expected_header_values);
+ QFETCH(bool, overwrite);
+
+ QHttpPart httpPart;
+
+ if (!header_data.isEmpty())
+ httpPart.setHeader(QNetworkRequest::ContentDispositionHeader, header_data);
+
+ if (!raw_header_data.isEmpty())
+ httpPart.setRawHeader("Authorization", raw_header_data);
+
+ if (overwrite)
+ httpPart.setRawHeader("Content-Disposition", raw_header_data);
+
+ QByteArray msg;
+ {
+ QBuffer buf(&msg);
+ QVERIFY(buf.open(QIODevice::WriteOnly));
+ QDebug debug(&buf);
+ debug << httpPart;
+ }
+
+ for (const auto &value : expected_header_values)
+ QVERIFY2(msg.contains(value), "Missing header value: " + value);
+}
+
void tst_QNetworkReply::qtbug68821proxyError_data()
{
QTest::addColumn<QString>("proxyHost");
@@ -10527,6 +10641,7 @@ void tst_QNetworkReply::qtbug68821proxyError()
QCOMPARE(spy.count(), 1);
QCOMPARE(spy.at(0).at(0), error);
}
+#endif
void tst_QNetworkReply::abortAndError()
{
diff --git a/tests/auto/network/access/qnetworkreply_local/CMakeLists.txt b/tests/auto/network/access/qnetworkreply_local/CMakeLists.txt
new file mode 100644
index 0000000000..13a60afb13
--- /dev/null
+++ b/tests/auto/network/access/qnetworkreply_local/CMakeLists.txt
@@ -0,0 +1,9 @@
+qt_internal_add_test(tst_qnetworkreply_local
+ SOURCES
+ minihttpserver.h
+ tst_qnetworkreply_local.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::NetworkPrivate
+ BUNDLE_ANDROID_OPENSSL_LIBS
+)
diff --git a/tests/auto/network/access/qnetworkreply_local/minihttpserver.h b/tests/auto/network/access/qnetworkreply_local/minihttpserver.h
new file mode 100644
index 0000000000..eb0697a6f8
--- /dev/null
+++ b/tests/auto/network/access/qnetworkreply_local/minihttpserver.h
@@ -0,0 +1,246 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MINIHTTPSERVER_H
+#define MINIHTTPSERVER_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qtcpsocket.h>
+#include <QtNetwork/qlocalsocket.h>
+#if QT_CONFIG(ssl)
+# include <QtNetwork/qsslsocket.h>
+#endif
+#if QT_CONFIG(localserver)
+# include <QtNetwork/qlocalserver.h>
+#endif
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qhash.h>
+
+#include <utility>
+
+static inline QByteArray default200Response()
+{
+ return QByteArrayLiteral("HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: 12\r\n"
+ "\r\n"
+ "Hello World!");
+}
+class MiniHttpServerV2 : public QObject
+{
+ Q_OBJECT
+
+public:
+ struct State;
+
+#if QT_CONFIG(localserver)
+ void bind(QLocalServer *server)
+ {
+ Q_ASSERT(!localServer);
+ localServer = server;
+ connect(server, &QLocalServer::newConnection, this,
+ &MiniHttpServerV2::incomingLocalConnection);
+ }
+#endif
+
+ void bind(QTcpServer *server)
+ {
+ Q_ASSERT(!tcpServer);
+ tcpServer = server;
+ connect(server, &QTcpServer::pendingConnectionAvailable, this,
+ &MiniHttpServerV2::incomingConnection);
+ }
+
+ void setDataToTransmit(QByteArray data) { dataToTransmit = std::move(data); }
+
+ void clearServerState()
+ {
+ auto copy = std::exchange(clientStates, {});
+ for (auto [socket, _] : copy.asKeyValueRange()) {
+ if (auto *tcpSocket = qobject_cast<QTcpSocket *>(socket))
+ tcpSocket->disconnectFromHost();
+ else if (auto *localSocket = qobject_cast<QLocalSocket *>(socket))
+ localSocket->disconnectFromServer();
+ else
+ Q_UNREACHABLE_RETURN();
+ socket->deleteLater();
+ }
+ }
+
+ bool hasPendingConnections() const
+ {
+ return
+#if QT_CONFIG(localserver)
+ (localServer && localServer->hasPendingConnections()) ||
+#endif
+ (tcpServer && tcpServer->hasPendingConnections());
+ }
+
+ QString addressForScheme(QStringView scheme) const
+ {
+ using namespace Qt::StringLiterals;
+ if (scheme.startsWith("unix"_L1) || scheme.startsWith("local"_L1)) {
+#if QT_CONFIG(localserver)
+ if (localServer)
+ return localServer->serverName();
+#endif
+ } else if (scheme == "http"_L1) {
+ if (tcpServer)
+ return "%1:%2"_L1.arg(tcpServer->serverAddress().toString(),
+ QString::number(tcpServer->serverPort()));
+ }
+ return {};
+ }
+
+ QList<State> peerStates() const { return clientStates.values(); }
+
+protected:
+#if QT_CONFIG(localserver)
+ void incomingLocalConnection()
+ {
+ auto *socket = localServer->nextPendingConnection();
+ connectSocketSignals(socket);
+ }
+#endif
+
+ void incomingConnection()
+ {
+ auto *socket = tcpServer->nextPendingConnection();
+ connectSocketSignals(socket);
+ }
+
+ void reply(QIODevice *socket)
+ {
+ Q_ASSERT(socket);
+ if (dataToTransmit.isEmpty()) {
+ emit socket->bytesWritten(0); // emulate having written the data
+ return;
+ }
+ if (!stopTransfer)
+ socket->write(dataToTransmit);
+ }
+
+private:
+ void connectSocketSignals(QIODevice *socket)
+ {
+ connect(socket, &QIODevice::readyRead, this, [this, socket]() { readyReadSlot(socket); });
+ connect(socket, &QIODevice::bytesWritten, this,
+ [this, socket]() { bytesWrittenSlot(socket); });
+#if QT_CONFIG(ssl)
+ if (auto *sslSocket = qobject_cast<QSslSocket *>(socket))
+ connect(sslSocket, &QSslSocket::sslErrors, this, &MiniHttpServerV2::slotSslErrors);
+#endif
+
+ if (auto *tcpSocket = qobject_cast<QTcpSocket *>(socket)) {
+ connect(tcpSocket, &QAbstractSocket::errorOccurred, this, &MiniHttpServerV2::slotError);
+ } else if (auto *localSocket = qobject_cast<QLocalSocket *>(socket)) {
+ connect(localSocket, &QLocalSocket::errorOccurred, this,
+ [this](QLocalSocket::LocalSocketError error) {
+ slotError(QAbstractSocket::SocketError(error));
+ });
+ } else {
+ Q_UNREACHABLE_RETURN();
+ }
+ }
+
+ void parseContentLength(State &st, QByteArrayView header)
+ {
+ qsizetype index = header.indexOf("\r\ncontent-length:");
+ if (index == -1)
+ return;
+ st.foundContentLength = true;
+
+ index += sizeof("\r\ncontent-length:") - 1;
+ const auto *end = std::find(header.cbegin() + index, header.cend(), '\r');
+ QByteArrayView num = header.mid(index, std::distance(header.cbegin() + index, end));
+ bool ok = false;
+ st.contentLength = num.toInt(&ok);
+ if (!ok)
+ st.contentLength = -1;
+ }
+
+private slots:
+#if QT_CONFIG(ssl)
+ void slotSslErrors(const QList<QSslError> &errors)
+ {
+ QTcpSocket *currentClient = qobject_cast<QTcpSocket *>(sender());
+ Q_ASSERT(currentClient);
+ qDebug() << "slotSslErrors" << currentClient->errorString() << errors;
+ }
+#endif
+ void slotError(QAbstractSocket::SocketError err)
+ {
+ QTcpSocket *currentClient = qobject_cast<QTcpSocket *>(sender());
+ Q_ASSERT(currentClient);
+ qDebug() << "slotError" << err << currentClient->errorString();
+ }
+
+public slots:
+
+ void readyReadSlot(QIODevice *socket)
+ {
+ if (stopTransfer)
+ return;
+ State &st = clientStates[socket];
+ st.receivedData += socket->readAll();
+ const qsizetype doubleEndlPos = st.receivedData.indexOf("\r\n\r\n");
+
+ if (doubleEndlPos != -1) {
+ const qsizetype endOfHeader = doubleEndlPos + 4;
+ st.contentRead = st.receivedData.size() - endOfHeader;
+
+ if (!st.checkedContentLength) {
+ parseContentLength(st, QByteArrayView(st.receivedData).first(endOfHeader));
+ st.checkedContentLength = true;
+ }
+
+ if (st.contentRead < st.contentLength)
+ return;
+
+ // multiple requests incoming, remove the bytes of the current one
+ if (multiple)
+ st.receivedData.remove(0, endOfHeader);
+
+ reply(socket);
+ }
+ }
+
+ void bytesWrittenSlot(QIODevice *socket)
+ {
+ // Disconnect and delete in next cycle (else Windows clients will fail with
+ // RemoteHostClosedError).
+ if (doClose && socket->bytesToWrite() == 0) {
+ disconnect(socket, nullptr, this, nullptr);
+ socket->deleteLater();
+ }
+ }
+
+private:
+ QByteArray dataToTransmit = default200Response();
+
+ QTcpServer *tcpServer = nullptr;
+#if QT_CONFIG(localserver)
+ QLocalServer *localServer = nullptr;
+#endif
+
+ QHash<QIODevice *, State> clientStates;
+
+public:
+ struct State
+ {
+ QByteArray receivedData;
+ qsizetype contentLength = 0;
+ qsizetype contentRead = 0;
+ bool checkedContentLength = false;
+ bool foundContentLength = false;
+ };
+
+ bool doClose = true;
+ bool multiple = false;
+ bool stopTransfer = false;
+};
+
+#endif // MINIHTTPSERVER_H
diff --git a/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp b/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp
new file mode 100644
index 0000000000..729605d9c8
--- /dev/null
+++ b/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp
@@ -0,0 +1,114 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <QtTest/qtest.h>
+
+#include <QtNetwork/qnetworkreply.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+#include "minihttpserver.h"
+
+using namespace Qt::StringLiterals;
+
+/*
+ The tests here are meant to be self-contained, using servers in the same
+ process if needed. This enables externals to more easily run the tests too.
+*/
+class tst_QNetworkReply_local : public QObject
+{
+ Q_OBJECT
+private slots:
+ void initTestCase_data();
+
+ void get();
+ void post();
+};
+
+void tst_QNetworkReply_local::initTestCase_data()
+{
+ QTest::addColumn<QString>("scheme");
+
+ QTest::newRow("http") << "http";
+#if QT_CONFIG(localserver)
+ QTest::newRow("unix") << "unix+http";
+ QTest::newRow("local") << "local+http"; // equivalent to unix, but test that it works
+#endif
+}
+
+static std::unique_ptr<MiniHttpServerV2> getServerForCurrentScheme()
+{
+ auto server = std::make_unique<MiniHttpServerV2>();
+ QFETCH_GLOBAL(QString, scheme);
+ if (scheme.startsWith("unix"_L1) || scheme.startsWith("local"_L1)) {
+#if QT_CONFIG(localserver)
+ QLocalServer *localServer = new QLocalServer(server.get());
+ localServer->listen(u"qt_networkreply_test_"_s
+ % QLatin1StringView(QTest::currentTestFunction())
+ % QString::number(QCoreApplication::applicationPid()));
+ server->bind(localServer);
+#endif
+ } else if (scheme == "http") {
+ QTcpServer *tcpServer = new QTcpServer(server.get());
+ tcpServer->listen(QHostAddress::LocalHost, 0);
+ server->bind(tcpServer);
+ }
+ return server;
+}
+
+static QUrl getUrlForCurrentScheme(MiniHttpServerV2 *server)
+{
+ QFETCH_GLOBAL(QString, scheme);
+ const QString address = server->addressForScheme(scheme);
+ const QString urlString = QLatin1StringView("%1://%2").arg(scheme, address);
+ return { urlString };
+}
+
+void tst_QNetworkReply_local::get()
+{
+ std::unique_ptr<MiniHttpServerV2> server = getServerForCurrentScheme();
+ const QUrl url = getUrlForCurrentScheme(server.get());
+
+ QNetworkAccessManager manager;
+ std::unique_ptr<QNetworkReply> reply(manager.get(QNetworkRequest(url)));
+
+ const bool res = QTest::qWaitFor([reply = reply.get()] { return reply->isFinished(); });
+ QVERIFY(res);
+
+ QCOMPARE(reply->readAll(), QByteArray("Hello World!"));
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+}
+
+void tst_QNetworkReply_local::post()
+{
+ std::unique_ptr<MiniHttpServerV2> server = getServerForCurrentScheme();
+ const QUrl url = getUrlForCurrentScheme(server.get());
+
+ QNetworkAccessManager manager;
+ const QByteArray payload = "Hello from the other side!"_ba;
+ QNetworkRequest req(url);
+ req.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
+ std::unique_ptr<QNetworkReply> reply(manager.post(req, payload));
+
+ const bool res = QTest::qWaitFor([reply = reply.get()] { return reply->isFinished(); });
+ QVERIFY(res);
+
+ QCOMPARE(reply->readAll(), QByteArray("Hello World!"));
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+
+ auto states = server->peerStates();
+ QCOMPARE(states.size(), 1);
+
+ const auto &firstRequest = states.at(0);
+
+ QVERIFY(firstRequest.checkedContentLength);
+ QCOMPARE(firstRequest.contentLength, payload.size());
+ QCOMPARE_GT(firstRequest.receivedData.size(), payload.size() + 4);
+ QCOMPARE(firstRequest.receivedData.last(payload.size() + 4), "\r\n\r\n" + payload);
+}
+
+QTEST_MAIN(tst_QNetworkReply_local)
+
+#include "tst_qnetworkreply_local.moc"
+#include "moc_minihttpserver.cpp"
diff --git a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp
index bdef1115dd..0b6d6f339b 100644
--- a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp
+++ b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp
@@ -3,6 +3,8 @@
#include <QTest>
+#include <QtNetwork/QHttp1Configuration>
+#include <QtNetwork/QHttp2Configuration>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkCookie>
@@ -31,6 +33,10 @@ private slots:
void rawHeaderParsing_data();
void rawHeaderParsing();
void originatingObject();
+ void setHeaders_data();
+ void setHeaders();
+ void operatorEqual_data();
+ void operatorEqual();
void removeHeader();
};
@@ -347,7 +353,7 @@ void tst_QNetworkRequest::rawHeaderParsing_data()
<< true
<< "Content-Type" << "text/html";
QTest::newRow("Content-Length") << QNetworkRequest::ContentLengthHeader << QVariant(qint64(1))
- << true << "Content-Length" << " 1 ";
+ << true << "Content-Length" << "1";
QTest::newRow("Location") << QNetworkRequest::LocationHeader
<< QVariant(QUrl("http://foo/with space"))
<< true << "Location" << "http://foo/with%20space";
@@ -552,5 +558,155 @@ void tst_QNetworkRequest::originatingObject()
QVERIFY(!request.originatingObject());
}
+void tst_QNetworkRequest::setHeaders_data()
+{
+ QTest::addColumn<QHttpHeaders>("h");
+ QTest::newRow("null") << QHttpHeaders();
+ QHttpHeaders headers;
+ headers.append("name1", "value1");
+ QTest::newRow("valid") << headers;
+}
+
+void tst_QNetworkRequest::setHeaders()
+{
+ QFETCH(QHttpHeaders, h);
+
+ QNetworkRequest r1;
+
+ auto result = r1.headers();
+ QVERIFY(result.isEmpty());
+
+ r1.setHeaders(h);
+ QCOMPARE(r1.headers().toListOfPairs(), h.toListOfPairs());
+
+ QNetworkRequest r2;
+ auto tmp = h;
+ r2.setHeaders(std::move(tmp));
+ QCOMPARE(r2.headers().toListOfPairs(), h.toListOfPairs());
+}
+
+void tst_QNetworkRequest::operatorEqual_data()
+{
+ QTest::addColumn<QNetworkRequest>("a");
+ QTest::addColumn<QNetworkRequest>("b");
+ QTest::addColumn<bool>("expectedToMatch");
+ QTest::newRow("null") << QNetworkRequest() << QNetworkRequest() << true;
+
+ QNetworkRequest data1;
+ data1.setUrl(QUrl("http://qt-project.org"));
+ QTest::newRow("url-1-1") << data1 << QNetworkRequest() << false;
+ QTest::newRow("url-1-2") << data1 << data1 << true;
+
+ QNetworkRequest data2;
+ QHttpHeaders headers;
+ headers.append("name1", "value1");
+ data2.setHeaders(headers);
+ QTest::newRow("headers-2-1") << data2 << QNetworkRequest() << false;
+ QTest::newRow("headers-2-2") << data2 << data2 << true;
+ QTest::newRow("headers-2-3") << data2 << data1 << false;
+
+ QNetworkRequest data3;
+ data3.setPeerVerifyName("peerName");
+ QTest::newRow("peerName-3-1") << data3 << QNetworkRequest() << false;
+ QTest::newRow("peerName-3-2") << data3 << data3 << true;
+ QTest::newRow("peerName-3-3") << data3 << data1 << false;
+ QTest::newRow("peerName-3-4") << data3 << data2 << false;
+
+ QNetworkRequest data4;
+ data4.setAttribute(QNetworkRequest::Http2AllowedAttribute, true);
+ QTest::newRow("attribute-4-1") << data4 << QNetworkRequest() << false;
+ QTest::newRow("attribute-4-2") << data4 << data4 << true;
+ QTest::newRow("attribute-4-3") << data4 << data1 << false;
+ QTest::newRow("attribute-4-4") << data4 << data2 << false;
+ QTest::newRow("attribute-4-5") << data4 << data3 << false;
+
+ QNetworkRequest data5;
+ data5.setPriority(QNetworkRequest::Priority::HighPriority);
+ QTest::newRow("priority-5-1") << data5 << QNetworkRequest() << false;
+ QTest::newRow("priority-5-2") << data5 << data5 << true;
+ QTest::newRow("priority-5-3") << data5 << data1 << false;
+ QTest::newRow("priority-5-4") << data5 << data2 << false;
+ QTest::newRow("priority-5-5") << data5 << data3 << false;
+ QTest::newRow("priority-5-6") << data5 << data4 << false;
+
+ QNetworkRequest data6;
+ data6.setMaximumRedirectsAllowed(3);
+ QTest::newRow("maxRedirects-6-1") << data6 << QNetworkRequest() << false;
+ QTest::newRow("maxRedirects-6-2") << data6 << data6 << true;
+ QTest::newRow("maxRedirects-6-3") << data6 << data1 << false;
+ QTest::newRow("maxRedirects-6-4") << data6 << data2 << false;
+ QTest::newRow("maxRedirects-6-5") << data6 << data3 << false;
+ QTest::newRow("maxRedirects-6-6") << data6 << data4 << false;
+ QTest::newRow("maxRedirects-6-7") << data6 << data5 << false;
+
+#if QT_CONFIG(http)
+ QNetworkRequest data7;
+ QHttp1Configuration http1Configuration;
+ http1Configuration.setNumberOfConnectionsPerHost(5);
+ data7.setHttp1Configuration(http1Configuration);
+ QTest::newRow("http1Config-7-1") << data7 << QNetworkRequest() << false;
+ QTest::newRow("http1Config-7-2") << data7 << data7 << true;
+ QTest::newRow("http1Config-7-3") << data7 << data1 << false;
+ QTest::newRow("http1Config-7-4") << data7 << data2 << false;
+ QTest::newRow("http1Config-7-5") << data7 << data3 << false;
+ QTest::newRow("http1Config-7-6") << data7 << data4 << false;
+ QTest::newRow("http1Config-7-7") << data7 << data5 << false;
+ QTest::newRow("http1Config-7-8") << data7 << data6 << false;
+
+ QNetworkRequest data8;
+ QHttp2Configuration http2Configuration;
+ http2Configuration.setMaxFrameSize(16386);
+ data8.setHttp2Configuration(http2Configuration);
+ QTest::newRow("http2Config-8-1") << data8 << QNetworkRequest() << false;
+ QTest::newRow("http2Config-8-2") << data8 << data8 << true;
+ QTest::newRow("http2Config-8-3") << data8 << data1 << false;
+ QTest::newRow("http2Config-8-4") << data8 << data2 << false;
+ QTest::newRow("http2Config-8-5") << data8 << data3 << false;
+ QTest::newRow("http2Config-8-6") << data8 << data4 << false;
+ QTest::newRow("http2Config-8-7") << data8 << data5 << false;
+ QTest::newRow("http2Config-8-8") << data8 << data6 << false;
+ QTest::newRow("http2Config-8-9") << data8 << data7 << false;
+
+ QNetworkRequest data9;
+ data9.setDecompressedSafetyCheckThreshold(-1);
+ QTest::newRow("threshold-9-1") << data9 << QNetworkRequest() << false;
+ QTest::newRow("threshold-9-2") << data9 << data9 << true;
+ QTest::newRow("threshold-9-3") << data9 << data1 << false;
+ QTest::newRow("threshold-9-4") << data9 << data2 << false;
+ QTest::newRow("threshold-9-5") << data9 << data3 << false;
+ QTest::newRow("threshold-9-6") << data9 << data4 << false;
+ QTest::newRow("threshold-9-7") << data9 << data5 << false;
+ QTest::newRow("threshold-9-8") << data9 << data6 << false;
+ QTest::newRow("threshold-9-9") << data9 << data7 << false;
+ QTest::newRow("threshold-9-10") << data9 << data8 << false;
+#endif
+
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
+ QNetworkRequest data10;
+ data10.setTransferTimeout(50000);
+ QTest::newRow("timeout-10-1") << data10 << QNetworkRequest() << false;
+ QTest::newRow("timeout-10-2") << data10 << data10 << true;
+ QTest::newRow("timeout-10-3") << data10 << data1 << false;
+ QTest::newRow("timeout-10-4") << data10 << data2 << false;
+ QTest::newRow("timeout-10-5") << data10 << data3 << false;
+ QTest::newRow("timeout-10-6") << data10 << data4 << false;
+ QTest::newRow("timeout-10-7") << data10 << data5 << false;
+ QTest::newRow("timeout-10-8") << data10 << data6 << false;
+ QTest::newRow("timeout-10-9") << data10 << data7 << false;
+ QTest::newRow("timeout-10-10") << data10 << data8 << false;
+ QTest::newRow("timeout-10-11") << data10 << data9 << false;
+#endif
+}
+
+// public bool operator==(const QNetworkRequest &other) const
+void tst_QNetworkRequest::operatorEqual()
+{
+ QFETCH(QNetworkRequest, a);
+ QFETCH(QNetworkRequest, b);
+ QFETCH(bool, expectedToMatch);
+
+ QCOMPARE(a == b, expectedToMatch);
+}
+
QTEST_MAIN(tst_QNetworkRequest)
#include "tst_qnetworkrequest.moc"
diff --git a/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp
index 602bffd9c1..d6bdda76ca 100644
--- a/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp
+++ b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp
@@ -3,7 +3,9 @@
#include "httptestserver_p.h"
+#if QT_CONFIG(http)
#include <QtNetwork/qhttpmultipart.h>
+#endif
#include <QtNetwork/qrestaccessmanager.h>
#include <QtNetwork/qauthenticator.h>
#include <QtNetwork/qnetworkreply.h>
@@ -13,6 +15,7 @@
#include <QTest>
#include <QtTest/qsignalspy.h>
+#include <QtCore/private/qglobal_p.h> // for access to Qt's feature system
#include <QtCore/qbuffer.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsondocument.h>
@@ -32,7 +35,9 @@ private slots:
void initialization();
void destruction();
void callbacks();
+#if QT_CONFIG(http)
void requests();
+#endif
void reply();
void errors();
void body();
@@ -89,6 +94,7 @@ void tst_QRestAccessManager::reply()
networkReply = nullptr; \
}
+#if QT_CONFIG(http)
void tst_QRestAccessManager::requests()
{
// A basic test for each HTTP method against the local testserver.
@@ -267,6 +273,7 @@ void tst_QRestAccessManager::requests()
//manager.sendCustomRequest(request, this, [](){}); // No verb && no data
//manager.sendCustomRequest(request, "FOOBAR", this, [](){}); // No verb || no data
}
+#endif
void tst_QRestAccessManager::memberHandler(QRestReply &reply)
{
@@ -723,11 +730,29 @@ void tst_QRestAccessManager::text()
// should consider the indicated charset and convert it to an UTF-16 QString => the returned
// QString from text() should match with the original (UTF-16) QString.
- // Successful UTF-8
+ // Successful UTF-8 (explicit)
serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-8"_ba);
serverSideResponse.body = encUTF8(sourceString);
VERIFY_TEXT_REPLY_OK;
+ // Successful UTF-8 (obfuscated)
+ serverSideResponse.headers.removeAll(Header::ContentType);
+ serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=\"UT\\F-8\""_ba);
+ serverSideResponse.body = encUTF8(sourceString);
+ VERIFY_TEXT_REPLY_OK;
+
+ // Successful UTF-8 (empty charset)
+ serverSideResponse.headers.removeAll(Header::ContentType);
+ serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=\"\""_ba);
+ serverSideResponse.body = encUTF8(sourceString);
+ VERIFY_TEXT_REPLY_OK;
+
+ // Successful UTF-8 (implicit)
+ serverSideResponse.headers.removeAll(Header::ContentType);
+ serverSideResponse.headers.append(Header::ContentType, "text/plain"_ba);
+ serverSideResponse.body = encUTF8(sourceString);
+ VERIFY_TEXT_REPLY_OK;
+
// Successful UTF-16
serverSideResponse.headers.removeAll(Header::ContentType);
serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-16"_ba);
@@ -746,10 +771,17 @@ void tst_QRestAccessManager::text()
serverSideResponse.body = encUTF32(sourceString);
VERIFY_TEXT_REPLY_OK;
- // Successful UTF-32 with spec-wise allowed extra content in the Content-Type header value
+ // Successful UTF-32 with spec-wise allowed extra trailing content in the Content-Type header value
+ serverSideResponse.headers.removeAll(Header::ContentType);
+ serverSideResponse.headers.append(Header::ContentType,
+ "text(this is a \\)comment)/ (this (too)) plain; charset = \"UTF-32\";extraparameter=bar"_ba);
+ serverSideResponse.body = encUTF32(sourceString);
+ VERIFY_TEXT_REPLY_OK;
+
+ // Successful UTF-32 with spec-wise allowed extra leading content in the Content-Type header value
serverSideResponse.headers.removeAll(Header::ContentType);
serverSideResponse.headers.append(Header::ContentType,
- "text/plain; charset = \"UTF-32\";extraparameter=bar"_ba);
+ "text/plain; extraparameter=bar;charset = \"UT\\F-32\""_ba);
serverSideResponse.body = encUTF32(sourceString);
VERIFY_TEXT_REPLY_OK;
diff --git a/tests/auto/network/kernel/CMakeLists.txt b/tests/auto/network/kernel/CMakeLists.txt
index b42a9724b3..df87e9d58e 100644
--- a/tests/auto/network/kernel/CMakeLists.txt
+++ b/tests/auto/network/kernel/CMakeLists.txt
@@ -6,12 +6,16 @@ if(QT_FEATURE_dnslookup AND (QT_FEATURE_libresolv OR WIN32))
add_subdirectory(qdnslookup_appless)
endif()
if(QT_FEATURE_networkinterface)
+ add_subdirectory(qnetworkaddressentry)
add_subdirectory(qnetworkproxyfactory)
add_subdirectory(qnetworkinterface)
endif()
-add_subdirectory(qnetworkproxy)
-add_subdirectory(qnetworkdatagram)
-add_subdirectory(qnetworkaddressentry)
+if(QT_FEATURE_networkproxy)
+ add_subdirectory(qnetworkproxy)
+endif()
+if(QT_FEATURE_udpsocket)
+ add_subdirectory(qnetworkdatagram)
+endif()
add_subdirectory(qhostaddress)
if(QT_FEATURE_private_tests AND NOT MACOS AND NOT INTEGRITY)
add_subdirectory(qhostinfo)
diff --git a/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp b/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp
index 20ecf8a6ab..af3a74a498 100644
--- a/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp
+++ b/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp
@@ -13,6 +13,13 @@
#include <QtNetwork/QNetworkDatagram>
#include <QtNetwork/QUdpSocket>
+#if QT_CONFIG(networkproxy)
+# include <QtNetwork/QNetworkProxyFactory>
+#endif
+#if QT_CONFIG(ssl)
+# include <QtNetwork/QSslSocket>
+#endif
+
#ifdef Q_OS_UNIX
# include <QtCore/QFile>
#else
@@ -35,12 +42,21 @@ class tst_QDnsLookup: public QObject
QString domainName(const QString &input);
QString domainNameList(const QString &input);
QStringList domainNameListAlternatives(const QString &input);
+
+ std::unique_ptr<QDnsLookup> lookupCommon(QDnsLookup::Type type, const QString &domain,
+ const QHostAddress &server = {}, quint16 port = 0,
+ QDnsLookup::Protocol protocol = QDnsLookup::Standard);
+ QStringList formatReply(const QDnsLookup *lookup) const;
+
+ void setNameserver_helper(QDnsLookup::Protocol protocol);
public slots:
void initTestCase();
private slots:
void lookupLocalhost();
void lookupRoot();
+ void lookupNxDomain_data();
+ void lookupNxDomain();
void lookup_data();
void lookup();
void lookupIdn_data() { lookup_data(); }
@@ -51,6 +67,8 @@ private slots:
void setNameserverLoopback();
void setNameserver_data();
void setNameserver();
+ void dnsOverTls_data();
+ void dnsOverTls();
void bindingsAndProperties();
void automatedBindings();
};
@@ -68,9 +86,11 @@ static const char preparedDnsQuery[] =
"\x00\x00\x06\x00\x01" // <root domain> IN SOA
;
-static QList<QHostAddress> systemNameservers()
+static QList<QHostAddress> systemNameservers(QDnsLookup::Protocol protocol)
{
QList<QHostAddress> result;
+ if (protocol != QDnsLookup::Standard)
+ return result;
#ifdef Q_OS_WIN
ULONG infosize = 0;
@@ -85,25 +105,29 @@ static QList<QHostAddress> systemNameservers()
}
}
#else
- QFile f("/etc/resolv.conf");
- if (!f.open(QIODevice::ReadOnly))
- return result;
-
- while (!f.atEnd()) {
- static const char command[] = "nameserver";
- QByteArray line = f.readLine().simplified();
- if (!line.startsWith(command))
- continue;
-
- QString addr = QLatin1StringView(line).mid(sizeof(command));
- result.emplaceBack(addr);
- }
+ auto parseFile = [&](QLatin1StringView path) {
+ QFile f(path);
+ if (!f.open(QIODevice::ReadOnly))
+ return;
+
+ while (!f.atEnd()) {
+ static const char command[] = "nameserver";
+ QByteArray line = f.readLine().simplified();
+ if (!line.startsWith(command))
+ continue;
+
+ QString addr = QLatin1StringView(line).mid(sizeof(command));
+ result.emplaceBack(addr);
+ }
+ };
+ parseFile("/etc/resolv.conf"_L1);
+ parseFile("/run/systemd/resolve/resolv.conf"_L1);
#endif
return result;
}
-static QList<QHostAddress> globalPublicNameservers()
+static QList<QHostAddress> globalPublicNameservers(QDnsLookup::Protocol proto)
{
const char *const candidates[] = {
// Google's dns.google
@@ -118,6 +142,56 @@ static QList<QHostAddress> globalPublicNameservers()
//"9.9.9.9", "2620:fe::9",
};
+ auto udpSendAndReceive = [](const QHostAddress &addr, QByteArray &data) {
+ QUdpSocket socket;
+ socket.connectToHost(addr, 53);
+ if (socket.waitForConnected(1))
+ socket.write(data);
+
+ if (!socket.waitForReadyRead(1000))
+ return socket.errorString();
+
+ QNetworkDatagram dgram = socket.receiveDatagram();
+ if (!dgram.isValid())
+ return socket.errorString();
+
+ data = dgram.data();
+ return QString();
+ };
+
+ auto tlsSendAndReceive = [](const QHostAddress &addr, QByteArray &data) {
+#if QT_CONFIG(ssl)
+ QSslSocket socket;
+ QDeadlineTimer timeout(2000);
+ socket.connectToHostEncrypted(addr.toString(), 853);
+ if (!socket.waitForEncrypted(2000))
+ return socket.errorString();
+
+ quint16 size = qToBigEndian<quint16>(data.size());
+ socket.write(reinterpret_cast<char *>(&size), sizeof(size));
+ socket.write(data);
+
+ if (!socket.waitForReadyRead(timeout.remainingTime()))
+ return socket.errorString();
+ if (socket.bytesAvailable() < 2)
+ return u"protocol error"_s;
+
+ socket.read(reinterpret_cast<char *>(&size), sizeof(size));
+ size = qFromBigEndian(size);
+
+ while (socket.bytesAvailable() < size) {
+ int remaining = timeout.remainingTime();
+ if (remaining < 0 || !socket.waitForReadyRead(remaining))
+ return socket.errorString();
+ }
+
+ data = socket.readAll();
+ return QString();
+#else
+ return u"SSL/TLS support not compiled in"_s;
+#endif
+ };
+
QList<QHostAddress> result;
QRandomGenerator &rng = *QRandomGenerator::system();
for (auto name : candidates) {
@@ -128,23 +202,18 @@ static QList<QHostAddress> globalPublicNameservers()
char *ptr = data.data();
qToBigEndian(id, ptr);
- QUdpSocket socket;
- socket.connectToHost(addr, 53);
- if (socket.waitForConnected(1))
- socket.write(data);
-
- if (!socket.waitForReadyRead(1000)) {
- qDebug() << addr << "discarded:" << socket.errorString();
- continue;
- }
-
- QNetworkDatagram dgram = socket.receiveDatagram();
- if (!dgram.isValid()) {
- qDebug() << addr << "discarded:" << socket.errorString();
+ QString errorString = [&] {
+ switch (proto) {
+ case QDnsLookup::Standard: return udpSendAndReceive(addr, data);
+ case QDnsLookup::DnsOverTls: return tlsSendAndReceive(addr, data);
+ }
+ Q_UNREACHABLE();
+ }();
+ if (!errorString.isEmpty()) {
+ qDebug() << addr << "discarded:" << errorString;
continue;
}
- data = dgram.data();
ptr = data.data();
if (data.size() < HeaderSize) {
qDebug() << addr << "discarded: reply too small";
@@ -171,6 +240,11 @@ void tst_QDnsLookup::initTestCase()
{
if (qgetenv("QTEST_ENVIRONMENT") == "ci")
dnsServersMustWork = true;
+
+#if QT_CONFIG(networkproxy)
+ // for DNS-over-TLS
+ QNetworkProxyFactory::setUseSystemConfiguration(true);
+#endif
}
QString tst_QDnsLookup::domainName(const QString &input)
@@ -209,17 +283,119 @@ QStringList tst_QDnsLookup::domainNameListAlternatives(const QString &input)
return alternatives;
}
+std::unique_ptr<QDnsLookup>
+tst_QDnsLookup::lookupCommon(QDnsLookup::Type type, const QString &domain,
+ const QHostAddress &server, quint16 port,
+ QDnsLookup::Protocol protocol)
+{
+ auto lookup = std::make_unique<QDnsLookup>(type, domainName(domain), protocol, server, port);
+ QObject::connect(lookup.get(), &QDnsLookup::finished,
+ &QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
+ lookup->lookup();
+ QTestEventLoop::instance().enterLoopMSecs(Timeout);
+
+ QDnsLookup::Error error = lookup->error();
+ if (QTestEventLoop::instance().timeout())
+ error = QDnsLookup::TimeoutError;
+
+ if (!dnsServersMustWork && (error == QDnsLookup::ServerFailureError
+ || error == QDnsLookup::ServerRefusedError
+ || error == QDnsLookup::TimeoutError)) {
+ // It's not a QDnsLookup problem if the server refuses to answer the query.
+ // This happens for queries of type ANY through Dnsmasq, for example.
+ [&] {
+ auto me = QMetaEnum::fromType<QDnsLookup::Type>();
+ QString msg = u"Server refused or was unable to answer query; %1 type %3: %2"_s
+ .arg(domain, lookup->errorString(), QString(me.valueToKey(int(type))));
+ QSKIP(msg.toLocal8Bit());
+ }();
+ return {};
+ }
+
+ return lookup;
+}
+
+QStringList tst_QDnsLookup::formatReply(const QDnsLookup *lookup) const
+{
+ QStringList result;
+ QString domain = lookup->name();
+
+ auto shorter = [this](QString value) {
+ const QString &ending = usingIdnDomain ? idnDomain : normalDomain;
+ if (value.endsWith(ending))
+ value.chop(ending.size());
+ else
+ value += u'.';
+ return value;
+ };
+
+ for (const QDnsMailExchangeRecord &rr : lookup->mailExchangeRecords()) {
+ QString entry = u"MX %1 %2"_s.arg(rr.preference(), 5).arg(shorter(rr.exchange()));
+ if (rr.name() != domain)
+ entry = "MX unexpected label to "_L1 + rr.name();
+ result.append(std::move(entry));
+ }
+
+ for (const QDnsServiceRecord &rr : lookup->serviceRecords()) {
+ QString entry = u"SRV %1 %2 %3 %4"_s.arg(rr.priority(), 5).arg(rr.weight())
+ .arg(rr.port()).arg(shorter(rr.target()));
+ if (rr.name() != domain)
+ entry = "SRV unexpected label to "_L1 + rr.name();
+ result.append(std::move(entry));
+ }
+
+ auto addNameRecords = [&](QLatin1StringView rrtype, const QList<QDnsDomainNameRecord> &rrset) {
+ for (const QDnsDomainNameRecord &rr : rrset) {
+ QString entry = u"%1 %2"_s.arg(rrtype, shorter(rr.value()));
+ if (rr.name() != domain)
+ entry = rrtype + " unexpected label to "_L1 + rr.name();
+ result.append(std::move(entry));
+ }
+ };
+ addNameRecords("NS"_L1, lookup->nameServerRecords());
+ addNameRecords("PTR"_L1, lookup->pointerRecords());
+ addNameRecords("CNAME"_L1, lookup->canonicalNameRecords());
+
+ for (const QDnsHostAddressRecord &rr : lookup->hostAddressRecords()) {
+ if (rr.name() != domain)
+ continue; // A and AAAA may appear as extra records in the answer section
+ QHostAddress addr = rr.value();
+ result.append(u"%1 %2"_s
+ .arg(addr.protocol() == QHostAddress::IPv6Protocol ? "AAAA" : "A",
+ addr.toString()));
+ }
+
+ for (const QDnsTextRecord &rr : lookup->textRecords()) {
+ QString entry = "TXT"_L1;
+ for (const QByteArray &data : rr.values()) {
+ entry += u' ';
+ entry += QDebug::toString(data);
+ }
+ result.append(std::move(entry));
+ }
+
+ for (const QDnsTlsAssociationRecord &rr : lookup->tlsAssociationRecords()) {
+ QString entry = u"TLSA %1 %2 %3 %4"_s.arg(int(rr.usage())).arg(int(rr.selector()))
+ .arg(int(rr.matchType())).arg(rr.value().toHex().toUpper());
+ if (rr.name() != domain)
+ entry = "TLSA unexpected label to "_L1 + rr.name();
+ result.append(std::move(entry));
+ }
+
+ result.sort();
+ return result;
+}
+
void tst_QDnsLookup::lookupLocalhost()
{
- QDnsLookup lookup(QDnsLookup::Type::A, u"localhost"_s);
- lookup.lookup();
- QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
- QCOMPARE(lookup.error(), QDnsLookup::NoError);
+ auto lookup = lookupCommon(QDnsLookup::Type::A, u"localhost."_s);
+ QVERIFY(lookup);
+ QCOMPARE(lookup->error(), QDnsLookup::NoError);
- QList<QDnsHostAddressRecord> hosts = lookup.hostAddressRecords();
+ QList<QDnsHostAddressRecord> hosts = lookup->hostAddressRecords();
QCOMPARE(hosts.size(), 1);
QCOMPARE(hosts.at(0).value(), QHostAddress::LocalHost);
- QVERIFY2(hosts.at(0).name().startsWith(lookup.name()),
+ QVERIFY2(hosts.at(0).name().startsWith(lookup->name()),
qPrintable(hosts.at(0).name()));
}
@@ -228,12 +404,12 @@ void tst_QDnsLookup::lookupRoot()
#ifdef Q_OS_WIN
QSKIP("This test fails on Windows as it seems to treat the lookup as a local one.");
#else
- QDnsLookup lookup(QDnsLookup::Type::NS, u""_s);
- lookup.lookup();
- QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
- QCOMPARE(lookup.error(), QDnsLookup::NoError);
+ auto lookup = lookupCommon(QDnsLookup::Type::NS, u""_s);
+ if (!lookup)
+ return;
+ QCOMPARE(lookup->error(), QDnsLookup::NoError);
- const QList<QDnsDomainNameRecord> servers = lookup.nameServerRecords();
+ const QList<QDnsDomainNameRecord> servers = lookup->nameServerRecords();
QVERIFY(!servers.isEmpty());
for (const QDnsDomainNameRecord &ns : servers) {
QCOMPARE(ns.name(), QString());
@@ -242,215 +418,142 @@ void tst_QDnsLookup::lookupRoot()
#endif
}
+void tst_QDnsLookup::lookupNxDomain_data()
+{
+ QTest::addColumn<QDnsLookup::Type>("type");
+ QTest::addColumn<QString>("domain");
+
+ QTest::newRow("a") << QDnsLookup::A << "invalid.invalid";
+ QTest::newRow("aaaa") << QDnsLookup::AAAA << "invalid.invalid";
+ QTest::newRow("any") << QDnsLookup::ANY << "invalid.invalid";
+ QTest::newRow("mx") << QDnsLookup::MX << "invalid.invalid";
+ QTest::newRow("ns") << QDnsLookup::NS << "invalid.invalid";
+ QTest::newRow("ptr") << QDnsLookup::PTR << "invalid.invalid";
+ QTest::newRow("srv") << QDnsLookup::SRV << "invalid.invalid";
+ QTest::newRow("txt") << QDnsLookup::TXT << "invalid.invalid";
+}
+
+void tst_QDnsLookup::lookupNxDomain()
+{
+ QFETCH(QDnsLookup::Type, type);
+ QFETCH(QString, domain);
+
+ auto lookup = lookupCommon(type, domain);
+ if (!lookup)
+ return;
+ QCOMPARE(lookup->name(), domainName(domain));
+ QCOMPARE(lookup->type(), type);
+ QCOMPARE(lookup->error(), QDnsLookup::NotFoundError);
+}
+
void tst_QDnsLookup::lookup_data()
{
- QTest::addColumn<int>("type");
+ QTest::addColumn<QDnsLookup::Type>("type");
QTest::addColumn<QString>("domain");
- QTest::addColumn<int>("error");
- QTest::addColumn<QString>("cname");
- QTest::addColumn<QString>("host");
- QTest::addColumn<QString>("mx");
- QTest::addColumn<QString>("ns");
- QTest::addColumn<QString>("ptr");
- QTest::addColumn<QString>("srv");
- QTest::addColumn<QString>("txt");
-
- QTest::newRow("a-notfound") << int(QDnsLookup::A) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
- QTest::newRow("a-single") << int(QDnsLookup::A) << "a-single" << int(QDnsLookup::NoError) << "" << "192.0.2.1" << "" << "" << "" << "" << "";
- QTest::newRow("a-multi") << int(QDnsLookup::A) << "a-multi" << int(QDnsLookup::NoError) << "" << "192.0.2.1;192.0.2.2;192.0.2.3" << "" << "" << "" << "" << "";
- QTest::newRow("aaaa-notfound") << int(QDnsLookup::AAAA) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
- QTest::newRow("aaaa-single") << int(QDnsLookup::AAAA) << "aaaa-single" << int(QDnsLookup::NoError) << "" << "2001:db8::1" << "" << "" << "" << "" << "";
- QTest::newRow("aaaa-multi") << int(QDnsLookup::AAAA) << "aaaa-multi" << int(QDnsLookup::NoError) << "" << "2001:db8::1;2001:db8::2;2001:db8::3" << "" << "" << "" << "" << "";
-
- QTest::newRow("any-notfound") << int(QDnsLookup::ANY) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
- QTest::newRow("any-a-single") << int(QDnsLookup::ANY) << "a-single" << int(QDnsLookup::NoError) << "" << "192.0.2.1" << "" << "" << "" << "" << "";
- QTest::newRow("any-a-plus-aaaa") << int(QDnsLookup::ANY) << "a-plus-aaaa" << int(QDnsLookup::NoError) << "" << "198.51.100.1;2001:db8::1:1" << "" << "" << "" << "" << "";
- QTest::newRow("any-multi") << int(QDnsLookup::ANY) << "multi" << int(QDnsLookup::NoError) << "" << "198.51.100.1;198.51.100.2;198.51.100.3;2001:db8::1:1;2001:db8::1:2" << "" << "" << "" << "" << "";
-
- QTest::newRow("mx-notfound") << int(QDnsLookup::MX) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
- QTest::newRow("mx-single") << int(QDnsLookup::MX) << "mx-single" << int(QDnsLookup::NoError) << "" << "" << "10 multi" << "" << "" << "" << "";
- QTest::newRow("mx-single-cname") << int(QDnsLookup::MX) << "mx-single-cname" << int(QDnsLookup::NoError) << "" << "" << "10 cname" << "" << "" << "" << "";
- QTest::newRow("mx-multi") << int(QDnsLookup::MX) << "mx-multi" << int(QDnsLookup::NoError) << "" << "" << "10 multi;20 a-single" << "" << "" << "" << "";
- QTest::newRow("mx-multi-sameprio") << int(QDnsLookup::MX) << "mx-multi-sameprio" << int(QDnsLookup::NoError) << "" << ""
- << "10 multi;10 a-single|"
- "10 a-single;10 multi" << "" << "" << "" << "";
-
- QTest::newRow("ns-notfound") << int(QDnsLookup::NS) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
- QTest::newRow("ns-single") << int(QDnsLookup::NS) << "ns-single" << int(QDnsLookup::NoError) << "" << "" << "" << "ns11.cloudns.net." << "" << "" << "";
- QTest::newRow("ns-multi") << int(QDnsLookup::NS) << "ns-multi" << int(QDnsLookup::NoError) << "" << "" << "" << "ns11.cloudns.net.;ns12.cloudns.net." << "" << "" << "";
-
- QTest::newRow("ptr-notfound") << int(QDnsLookup::PTR) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("a-single") << QDnsLookup::A << "a-single"
+ << "A 192.0.2.1";
+ QTest::newRow("a-multi") << QDnsLookup::A << "a-multi"
+ << "A 192.0.2.1;A 192.0.2.2;A 192.0.2.3";
+ QTest::newRow("aaaa-single") << QDnsLookup::AAAA << "aaaa-single"
+ << "AAAA 2001:db8::1";
+ QTest::newRow("aaaa-multi") << QDnsLookup::AAAA << "aaaa-multi"
+ << "AAAA 2001:db8::1;AAAA 2001:db8::2;AAAA 2001:db8::3";
+
+ QTest::newRow("any-a-single") << QDnsLookup::ANY << "a-single"
+ << "A 192.0.2.1";
+ QTest::newRow("any-a-plus-aaaa") << QDnsLookup::ANY << "a-plus-aaaa"
+ << "A 198.51.100.1;AAAA 2001:db8::1:1";
+ QTest::newRow("any-multi") << QDnsLookup::ANY << "multi"
+ << "A 198.51.100.1;A 198.51.100.2;A 198.51.100.3;"
+ "AAAA 2001:db8::1:1;AAAA 2001:db8::1:2" ;
+
+ QTest::newRow("mx-single") << QDnsLookup::MX << "mx-single"
+ << "MX 10 multi";
+ QTest::newRow("mx-single-cname") << QDnsLookup::MX << "mx-single-cname"
+ << "MX 10 cname";
+ QTest::newRow("mx-multi") << QDnsLookup::MX << "mx-multi"
+ << "MX 10 multi;MX 20 a-single";
+ QTest::newRow("mx-multi-sameprio") << QDnsLookup::MX << "mx-multi-sameprio"
+ << "MX 10 a-single;MX 10 multi";
+
+ QTest::newRow("ns-single") << QDnsLookup::NS << "ns-single"
+ << "NS ns11.cloudns.net.";
+ QTest::newRow("ns-multi") << QDnsLookup::NS << "ns-multi"
+ << "NS ns11.cloudns.net.;NS ns12.cloudns.net.";
+
#if 0
// temporarily disabled since the new hosting provider can't insert
// PTR records outside of the in-addr.arpa zone
- QTest::newRow("ptr-single") << int(QDnsLookup::PTR) << "ptr-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "a-single" << "" << "";
+ QTest::newRow("ptr-single") << QDnsLookup::PTR << "ptr-single"
+ << "PTR a-single";
#endif
-
- QTest::newRow("srv-notfound") << int(QDnsLookup::SRV) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
- QTest::newRow("srv-single") << int(QDnsLookup::SRV) << "_echo._tcp.srv-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "5 0 7 multi" << "";
- QTest::newRow("srv-prio") << int(QDnsLookup::SRV) << "_echo._tcp.srv-prio" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "1 0 7 multi;2 0 7 a-plus-aaaa" << "";
- QTest::newRow("srv-weighted") << int(QDnsLookup::SRV) << "_echo._tcp.srv-weighted" << int(QDnsLookup::NoError) << "" << "" << "" << "" << ""
- << "5 75 7 multi;5 25 7 a-plus-aaaa|"
- "5 25 7 a-plus-aaaa;5 75 7 multi" << "";
- QTest::newRow("srv-multi") << int(QDnsLookup::SRV) << "_echo._tcp.srv-multi" << int(QDnsLookup::NoError) << "" << "" << "" << "" << ""
- << "1 50 7 multi;2 50 7 a-single;2 50 7 aaaa-single;3 50 7 a-multi|"
- "1 50 7 multi;2 50 7 aaaa-single;2 50 7 a-single;3 50 7 a-multi" << "";
-
- QTest::newRow("txt-notfound") << int(QDnsLookup::TXT) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
- QTest::newRow("txt-single") << int(QDnsLookup::TXT) << "txt-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" << "Hello";
- QTest::newRow("txt-multi-onerr") << int(QDnsLookup::TXT) << "txt-multi-onerr" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << ""
- << QString::fromLatin1("Hello\0World", sizeof("Hello\0World") - 1);
- QTest::newRow("txt-multi-multirr") << int(QDnsLookup::TXT) << "txt-multi-multirr" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" << "Hello;World";
+ QTest::newRow("ptr-1.1.1.1") << QDnsLookup::PTR << "1.1.1.1.in-addr.arpa."
+ << "PTR one.one.one.one.";
+ QTest::newRow("ptr-8.8.8.8") << QDnsLookup::PTR << "8.8.8.8.in-addr.arpa."
+ << "PTR dns.google.";
+ QTest::newRow("ptr-2001:4860:4860::8888")
+ << QDnsLookup::PTR << "8.8.8.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.6.8.4.0.6.8.4.1.0.0.2.ip6.arpa."
+ << "PTR dns.google.";
+ QTest::newRow("ptr-2606:4700:4700::1111")
+ << QDnsLookup::PTR << "1.1.1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.4.0.0.7.4.6.0.6.2.ip6.arpa."
+ << "PTR one.one.one.one.";
+
+ QTest::newRow("srv-single") << QDnsLookup::SRV << "_echo._tcp.srv-single"
+ << "SRV 5 0 7 multi";
+ QTest::newRow("srv-prio") << QDnsLookup::SRV << "_echo._tcp.srv-prio"
+ << "SRV 1 0 7 multi;SRV 2 0 7 a-plus-aaaa";
+ QTest::newRow("srv-weighted") << QDnsLookup::SRV << "_echo._tcp.srv-weighted"
+ << "SRV 5 25 7 a-plus-aaaa;SRV 5 75 7 multi";
+ QTest::newRow("srv-multi") << QDnsLookup::SRV << "_echo._tcp.srv-multi"
+ << "SRV 1 50 7 multi;"
+ "SRV 2 50 7 a-single;"
+ "SRV 2 50 7 aaaa-single;"
+ "SRV 3 50 7 a-multi";
+
+ QTest::newRow("tlsa") << QDnsLookup::Type::TLSA << "_25._tcp.multi"
+ << "TLSA 3 1 1 0123456789ABCDEFFEDCBA9876543210"
+ "0123456789ABCDEFFEDCBA9876543210";
+
+ QTest::newRow("txt-single") << QDnsLookup::TXT << "txt-single"
+ << "TXT \"Hello\"";
+ QTest::newRow("txt-multi-onerr") << QDnsLookup::TXT << "txt-multi-onerr"
+ << "TXT \"Hello\" \"World\"";
+ QTest::newRow("txt-multi-multirr") << QDnsLookup::TXT << "txt-multi-multirr"
+ << "TXT \"Hello\";TXT \"World\"";
}
void tst_QDnsLookup::lookup()
{
- QFETCH(int, type);
+ QFETCH(QDnsLookup::Type, type);
QFETCH(QString, domain);
- QFETCH(int, error);
- QFETCH(QString, cname);
- QFETCH(QString, host);
- QFETCH(QString, mx);
- QFETCH(QString, ns);
- QFETCH(QString, ptr);
- QFETCH(QString, srv);
- QFETCH(QString, txt);
-
- // transform the inputs
- domain = domainName(domain);
- cname = domainName(cname);
- ns = domainNameList(ns);
- ptr = domainNameList(ptr);
-
- // SRV and MX have reply entries that can change order
- // and we can't sort
- QStringList mx_alternatives = domainNameListAlternatives(mx);
- QStringList srv_alternatives = domainNameListAlternatives(srv);
+ QFETCH(QString, expected);
- QDnsLookup lookup;
- lookup.setType(static_cast<QDnsLookup::Type>(type));
- lookup.setName(domain);
- lookup.lookup();
- QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
-
- auto extraErrorMsg = [&] () {
- QString result;
- QTextStream str(&result);
- str << "Actual error: " << lookup.error();
- if (QString errorString = lookup.errorString(); !errorString.isEmpty())
- str << " (" << errorString << ')';
- str << ", expected: " << error;
- str << ", domain: " << domain;
- if (!cname.isEmpty())
- str << ", cname: " << cname;
- str << ", host: " << host;
- if (!srv.isEmpty())
- str << " server: " << srv;
- if (!mx.isEmpty())
- str << " mx: " << mx;
- if (!ns.isEmpty())
- str << " ns: " << ns;
- if (!ptr.isEmpty())
- str << " ptr: " << ptr;
- return result.toLocal8Bit();
- };
-
- if (!dnsServersMustWork && (lookup.error() == QDnsLookup::ServerFailureError
- || lookup.error() == QDnsLookup::ServerRefusedError
- || lookup.error() == QDnsLookup::TimeoutError)) {
- // It's not a QDnsLookup problem if the server refuses to answer the query.
- // This happens for queries of type ANY through Dnsmasq, for example.
- qWarning("Server refused or was unable to answer query; %s", extraErrorMsg().constData());
+ std::unique_ptr<QDnsLookup> lookup = lookupCommon(type, domain);
+ if (!lookup)
return;
- }
-
- QVERIFY2(int(lookup.error()) == error, extraErrorMsg());
- if (error == QDnsLookup::NoError)
- QVERIFY(lookup.errorString().isEmpty());
- QCOMPARE(int(lookup.type()), type);
- QCOMPARE(lookup.name(), domain);
-
- // canonical names
- if (!cname.isEmpty()) {
- QVERIFY(!lookup.canonicalNameRecords().isEmpty());
- const QDnsDomainNameRecord cnameRecord = lookup.canonicalNameRecords().first();
- QCOMPARE(cnameRecord.name(), domain);
- QCOMPARE(cnameRecord.value(), cname);
- } else {
- QVERIFY(lookup.canonicalNameRecords().isEmpty());
- }
-
- // host addresses
- const QString hostName = cname.isEmpty() ? domain : cname;
- QStringList addresses;
- const auto records = lookup.hostAddressRecords();
- for (const QDnsHostAddressRecord &record : records) {
- //reply may include A & AAAA records for nameservers, ignore them and only look at records matching the query
- if (record.name() == hostName)
- addresses << record.value().toString().toLower();
- }
- addresses.sort();
- QCOMPARE(addresses.join(';'), host);
-
- // mail exchanges
- QStringList mailExchanges;
- const auto mailRecords = lookup.mailExchangeRecords();
- for (const QDnsMailExchangeRecord &record : mailRecords) {
- QCOMPARE(record.name(), domain);
- mailExchanges << QString::number(record.preference()) + QLatin1Char(' ') + record.exchange();
- }
- QVERIFY2(mx_alternatives.contains(mailExchanges.join(';')),
- qPrintable("Actual: " + mailExchanges.join(';') + "\nExpected one of:\n" + mx_alternatives.join('\n')));
-
- // name servers
- QStringList nameServers;
- const auto nameServerRecords = lookup.nameServerRecords();
- for (const QDnsDomainNameRecord &record : nameServerRecords) {
- //reply may include NS records for authoritative nameservers, ignore them and only look at records matching the query
- if (record.name() == domain)
- nameServers << record.value();
- }
- nameServers.sort();
- QCOMPARE(nameServers.join(';'), ns);
-
- // pointers
- if (!ptr.isEmpty()) {
- QVERIFY(!lookup.pointerRecords().isEmpty());
- const QDnsDomainNameRecord ptrRecord = lookup.pointerRecords().first();
- QCOMPARE(ptrRecord.name(), domain);
- QCOMPARE(ptrRecord.value(), ptr);
- } else {
- QVERIFY(lookup.pointerRecords().isEmpty());
- }
- // services
- QStringList services;
- const auto serviceRecords = lookup.serviceRecords();
- for (const QDnsServiceRecord &record : serviceRecords) {
- QCOMPARE(record.name(), domain);
- services << (QString::number(record.priority()) + QLatin1Char(' ')
- + QString::number(record.weight()) + QLatin1Char(' ')
- + QString::number(record.port()) + QLatin1Char(' ') + record.target());
- }
- QVERIFY2(srv_alternatives.contains(services.join(';')),
- qPrintable("Actual: " + services.join(';') + "\nExpected one of:\n" + srv_alternatives.join('\n')));
-
- // text
- QStringList texts;
- const auto textRecords = lookup.textRecords();
- for (const QDnsTextRecord &record : textRecords) {
- QCOMPARE(record.name(), domain);
- QString text;
- const auto values = record.values();
- for (const QByteArray &ba : values) {
- if (!text.isEmpty())
- text += '\0';
- text += QString::fromLatin1(ba);
- }
- texts << text;
- }
- texts.sort();
- QCOMPARE(texts.join(';'), txt);
+#ifdef Q_OS_WIN
+ if (QTest::currentDataTag() == "tlsa"_L1)
+ QSKIP("WinDNS doesn't work properly with TLSA records and we don't know why");
+#endif
+ QCOMPARE(lookup->errorString(), QString());
+ QCOMPARE(lookup->error(), QDnsLookup::NoError);
+ QCOMPARE(lookup->type(), type);
+ QCOMPARE(lookup->name(), domainName(domain));
+
+ QString result = formatReply(lookup.get()).join(u';');
+ QCOMPARE(result, expected);
+
+ // confirm that MX and SRV records are properly sorted
+ const QList<QDnsMailExchangeRecord> mx = lookup->mailExchangeRecords();
+ for (qsizetype i = 1; i < mx.size(); ++i)
+ QCOMPARE_GE(mx[i].preference(), mx[i - 1].preference());
+
+ const QList<QDnsServiceRecord> srv = lookup->serviceRecords();
+ for (qsizetype i = 1; i < srv.size(); ++i)
+ QCOMPARE_GE(srv[i].priority(), srv[i - 1].priority());
}
void tst_QDnsLookup::lookupIdn()
@@ -556,9 +659,10 @@ void tst_QDnsLookup::setNameserverLoopback()
// send an NXDOMAIN reply to release the lookup thread
QByteArray reply = data;
- reply[2] = 0x80; // header->qr = true;
+ reply[2] = 0x80U; // header->qr = true;
reply[3] = 3; // header->rcode = NXDOMAIN;
- server.writeDatagram(dgram.makeReply(reply));
+ server.writeDatagram(reply.constData(), reply.size(), dgram.senderAddress(),
+ dgram.senderPort());
server.close();
// now check that the QDnsLookup finished
@@ -568,34 +672,57 @@ void tst_QDnsLookup::setNameserverLoopback()
QCOMPARE(lookup.error(), QDnsLookup::NotFoundError);
}
-void tst_QDnsLookup::setNameserver_data()
+template <QDnsLookup::Protocol Protocol>
+static void setNameserver_data_helper(const QByteArray &protoName)
{
- static QList<QHostAddress> servers = systemNameservers() + globalPublicNameservers();
+ if (!QDnsLookup::isProtocolSupported(Protocol))
+ QSKIP(protoName + " not supported");
+
+ static QList<QHostAddress> servers = systemNameservers(Protocol)
+ + globalPublicNameservers(Protocol);
QTest::addColumn<QHostAddress>("server");
if (servers.isEmpty()) {
- QSKIP("No reachable DNS servers were found");
+ QSKIP("No reachable " + protoName + " servers were found");
} else {
for (const QHostAddress &h : std::as_const(servers))
QTest::addRow("%s", qUtf8Printable(h.toString())) << h;
}
}
-void tst_QDnsLookup::setNameserver()
+void tst_QDnsLookup::setNameserver_data()
+{
+ setNameserver_data_helper<QDnsLookup::Standard>("DNS");
+}
+
+void tst_QDnsLookup::setNameserver_helper(QDnsLookup::Protocol protocol)
{
QFETCH(QHostAddress, server);
- QDnsLookup lookup;
- lookup.setNameserver(server);
+ QElapsedTimer timer;
+ timer.start();
+ std::unique_ptr<QDnsLookup> lookup =
+ lookupCommon(QDnsLookup::Type::A, "a-single", server, 0, protocol);
+ if (!lookup)
+ return;
+ qDebug() << "Lookup took" << timer.elapsed() << "ms";
+ QCOMPARE(lookup->error(), QDnsLookup::NoError);
+ QString result = formatReply(lookup.get()).join(';');
+ QCOMPARE(result, "A 192.0.2.1");
+}
- lookup.setType(QDnsLookup::Type::A);
- lookup.setName(domainName("a-single"));
- lookup.lookup();
+void tst_QDnsLookup::setNameserver()
+{
+ setNameserver_helper(QDnsLookup::Standard);
+}
- QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
- QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError));
- QVERIFY(!lookup.hostAddressRecords().isEmpty());
- QCOMPARE(lookup.hostAddressRecords().first().name(), domainName("a-single"));
- QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("192.0.2.1"));
+void tst_QDnsLookup::dnsOverTls_data()
+{
+ setNameserver_data_helper<QDnsLookup::DnsOverTls>("DNS-over-TLS");
+}
+
+void tst_QDnsLookup::dnsOverTls()
+{
+ setNameserver_helper(QDnsLookup::DnsOverTls);
}
void tst_QDnsLookup::bindingsAndProperties()
diff --git a/tests/auto/network/socket/CMakeLists.txt b/tests/auto/network/socket/CMakeLists.txt
index c3f8e8f87f..7136017f39 100644
--- a/tests/auto/network/socket/CMakeLists.txt
+++ b/tests/auto/network/socket/CMakeLists.txt
@@ -7,14 +7,20 @@ if(QT_FEATURE_private_tests)
add_subdirectory(qsocks5socketengine)
add_subdirectory(platformsocketengine)
endif()
-add_subdirectory(qudpsocket)
+if(QT_FEATURE_udpsocket)
+ add_subdirectory(qudpsocket)
+endif()
add_subdirectory(qabstractsocket)
-if(NOT ANDROID)
+if(QT_FEATURE_localserver AND NOT ANDROID)
# QTBUG-87387
add_subdirectory(qlocalsocket)
+endif()
+
+if(QT_FEATURE_networkinterface AND NOT ANDROID)
# QTBUG-87388
add_subdirectory(qtcpserver)
endif()
+
if(QT_FEATURE_sctp)
add_subdirectory(qsctpsocket)
endif()
diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
index 1ecd871ceb..30ffb50d23 100644
--- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
+++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
@@ -1664,6 +1664,9 @@ void tst_QLocalSocket::asyncDisconnectNotify()
void tst_QLocalSocket::verifySocketOptions_data()
{
#ifdef Q_OS_LINUX
+ if (::geteuid() == 0)
+ QSKIP("Running this test as root doesn't make sense");
+
QTest::addColumn<QString>("service");
QTest::addColumn<QLocalServer::SocketOption>("opts");
QTest::addColumn<QFile::Permissions>("perms");
diff --git a/tests/auto/other/CMakeLists.txt b/tests/auto/other/CMakeLists.txt
index 16f96cd5f4..e261ea234d 100644
--- a/tests/auto/other/CMakeLists.txt
+++ b/tests/auto/other/CMakeLists.txt
@@ -1,9 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-if(NOT CMAKE_CROSSCOMPILING)
- # add_subdirectory(atwrapper) <- does not exist
-endif()
if(TARGET Qt::Widgets)
add_subdirectory(gestures)
add_subdirectory(languagechange)
diff --git a/tests/auto/other/android_deployment_settings/CMakeLists.txt b/tests/auto/other/android_deployment_settings/CMakeLists.txt
index f2ba135328..9ef457189a 100644
--- a/tests/auto/other/android_deployment_settings/CMakeLists.txt
+++ b/tests/auto/other/android_deployment_settings/CMakeLists.txt
@@ -30,6 +30,7 @@ set_target_properties(${target} PROPERTIES
QT_ANDROID_SDK_BUILD_TOOLS_REVISION "23.0.2"
QT_ANDROID_MIN_SDK_VERSION "1"
QT_ANDROID_TARGET_SDK_VERSION "2"
+ QT_ANDROID_PACKAGE_NAME "org.qtproject.android_deployment_settings_test"
QT_ANDROID_DEPLOYMENT_DEPENDENCIES "dep1.so;dep2.so;dep3.so"
QT_ANDROID_DEPLOYMENT_SETTINGS_FILE "attempt_to_rewrite.json"
QT_ANDROID_EXTRA_LIBS
@@ -53,6 +54,7 @@ set_target_properties(${target} PROPERTIES
QT_ANDROID_SDK_BUILD_TOOLS_REVISION "23.0.2"
QT_ANDROID_MIN_SDK_VERSION "1"
QT_ANDROID_TARGET_SDK_VERSION "2"
+ QT_ANDROID_PACKAGE_NAME "org.qtproject.android_deployment_settings_test"
QT_ANDROID_DEPLOYMENT_DEPENDENCIES "dep1.so;dep2.so;dep3.so"
QT_ANDROID_EXTRA_LIBS
"some/path/to/lib1.so;some/path\\to/lib2.so;some\\path\\to\\lib3.so;some/path/to/lib4.so"
diff --git a/tests/auto/other/android_deployment_settings/tst_android_deployment_settings.cpp b/tests/auto/other/android_deployment_settings/tst_android_deployment_settings.cpp
index d68d08b58e..f8428aaf43 100644
--- a/tests/auto/other/android_deployment_settings/tst_android_deployment_settings.cpp
+++ b/tests/auto/other/android_deployment_settings/tst_android_deployment_settings.cpp
@@ -76,6 +76,8 @@ void tst_android_deployment_settings::DeploymentSettings_data()
<< "1";
QTest::newRow("android-target-sdk-version") << "android-target-sdk-version"
<< "2";
+ QTest::newRow("android-package-name") << "android-package-name"
+ << "org.qtproject.android_deployment_settings_test";
}
void tst_android_deployment_settings::DeploymentSettings()
diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
index 0c019544bd..5fd695e2e6 100644
--- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
+++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
@@ -2936,7 +2936,8 @@ void tst_QAccessibility::listTest()
QVERIFY(!(cell4->state().expandable));
QVERIFY( (cell4->state().selectable));
QVERIFY(!(cell4->state().selected));
- table2->selectRow(3);
+ QAccessibleSelectionInterface *selection2 = iface->selectionInterface();
+ selection2->select(cell4);
QCOMPARE(listView->selectedItems().size(), 1);
QCOMPARE(listView->selectedItems().at(0)->text(), QLatin1String("Munich"));
QVERIFY(cell4->state().selected);
diff --git a/tests/auto/other/qfocusevent/tst_qfocusevent.cpp b/tests/auto/other/qfocusevent/tst_qfocusevent.cpp
index cca5994673..8297b53ea1 100644
--- a/tests/auto/other/qfocusevent/tst_qfocusevent.cpp
+++ b/tests/auto/other/qfocusevent/tst_qfocusevent.cpp
@@ -312,7 +312,6 @@ void tst_QFocusEvent::checkReason_ActiveWindow()
QVERIFY(QTest::qWaitForWindowExposed(d));
d->activateWindow(); // ### CDE
- QApplicationPrivate::setActiveWindow(d);
QVERIFY(QTest::qWaitForWindowActive(d));
QTRY_VERIFY(childFocusWidgetOne->focusOutEventRecieved);
diff --git a/tests/auto/other/qvariant_common/tst_qvariant_common.h b/tests/auto/other/qvariant_common/tst_qvariant_common.h
index 553c396e47..4007cc7db8 100644
--- a/tests/auto/other/qvariant_common/tst_qvariant_common.h
+++ b/tests/auto/other/qvariant_common/tst_qvariant_common.h
@@ -119,6 +119,13 @@ protected:
QFETCH(bool, UIntCast); \
QFETCH(bool, ULongLongCast);
+#if QT_CONFIG(shortcut)
+#define QMETATYPE_QKEYSEQUENCE \
+ QCOMPARE(val.canConvert(QMetaType(QMetaType::QKeySequence)), KeySequenceCast);
+#else
+#define QMETATYPE_QKEYSEQUENCE
+#endif
+
#define TST_QVARIANT_CANCONVERT_COMPARE_DATA \
QCOMPARE(val.canConvert(QMetaType(QMetaType::QBitArray)), BitArrayCast); \
QCOMPARE(val.canConvert(QMetaType(QMetaType::QBitmap)), BitmapCast); \
@@ -135,7 +142,7 @@ protected:
QCOMPARE(val.canConvert(QMetaType(QMetaType::QImage)), ImageCast); \
QCOMPARE(val.canConvert(QMetaType(QMetaType::Int)), IntCast); \
QCOMPARE(val.canConvert(QMetaType(QMetaType::UnknownType)), InvalidCast); \
- QCOMPARE(val.canConvert(QMetaType(QMetaType::QKeySequence)), KeySequenceCast); \
+ QMETATYPE_QKEYSEQUENCE \
QCOMPARE(val.canConvert(QMetaType(QMetaType::QVariantList)), ListCast); \
QCOMPARE(val.canConvert(QMetaType(QMetaType::LongLong)), LongLongCast); \
QCOMPARE(val.canConvert(QMetaType(QMetaType::QVariantMap)), MapCast); \
diff --git a/tests/auto/sql/kernel/qsqldatabase/tst_databases.h b/tests/auto/sql/kernel/qsqldatabase/tst_databases.h
index f81fe5548b..5a10bde814 100644
--- a/tests/auto/sql/kernel/qsqldatabase/tst_databases.h
+++ b/tests/auto/sql/kernel/qsqldatabase/tst_databases.h
@@ -518,7 +518,10 @@ protected:
void cleanup()
{
QSqlQuery q(m_db);
- q.exec("DROP PROCEDURE IF EXISTS " + m_procName);
+ if (m_db.driverName() == "QIBASE")
+ q.exec("DROP PROCEDURE " + m_procName);
+ else
+ q.exec("DROP PROCEDURE IF EXISTS " + m_procName);
}
private:
QSqlDatabase m_db;
diff --git a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp
index 1b762abc68..19afacf6f9 100644
--- a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp
+++ b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp
@@ -104,6 +104,8 @@ private slots:
void infinityAndNan();
void multipleThreads_data() { generic_data(); }
void multipleThreads();
+ void moveToThread_data() { generic_data(); }
+ void moveToThread();
void db2_valueCacheUpdate_data() { generic_data("QDB2"); }
void db2_valueCacheUpdate();
@@ -2335,5 +2337,32 @@ void tst_QSqlDatabase::multipleThreads()
QTRY_VERIFY(t.isFinished());
}
+void tst_QSqlDatabase::moveToThread()
+{
+ QFETCH(QString, dbName);
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ auto clonedDb = QSqlDatabase::cloneDatabase(db, "clonedDb");
+ auto mainThread = QThread::currentThread();
+ CHECK_DATABASE(db);
+ QCOMPARE(db.currentThread(), mainThread);
+ QCOMPARE(clonedDb.currentThread(), mainThread);
+ std::unique_ptr<QThread> t(QThread::create([&] {
+ db.moveToThread(mainThread);
+ QThread::currentThread()->exit();
+ }));
+ db.moveToThread(t.get());
+ QCOMPARE(db.currentThread(), t.get());
+ QCOMPARE(clonedDb.currentThread(), mainThread);
+ t->start();
+ QTRY_VERIFY(t->isRunning());
+ QTRY_VERIFY(t->wait(30000));
+ QCOMPARE(db.currentThread(), mainThread);
+ QCOMPARE(clonedDb.currentThread(), mainThread);
+ db = QSqlDatabase();
+ clonedDb = QSqlDatabase();
+ QSqlDatabase::removeDatabase("clonedDb");
+}
+
+
QTEST_MAIN(tst_QSqlDatabase)
#include "tst_qsqldatabase.moc"
diff --git a/tests/auto/testlib/selftests/expected_testlib.junitxml b/tests/auto/testlib/selftests/expected_testlib.junitxml
index f5d3a94126..33c8bfe403 100644
--- a/tests/auto/testlib/selftests/expected_testlib.junitxml
+++ b/tests/auto/testlib/selftests/expected_testlib.junitxml
@@ -9,7 +9,7 @@
<testcase name="basics" classname="tst_TestLib" time="@TEST_DURATION@">
<failure type="fail" message="Compared QObject pointers are not the same">
<![CDATA[ Actual (QTest::testObject()): tst_TestLib/"TestObject"
- Expected (nullptr) : (nullptr)]]>
+ Expected (nullptr) : "nullptr"]]>
</failure>
</testcase>
<testcase name="delays" classname="tst_TestLib" time="@TEST_DURATION@"/>
diff --git a/tests/auto/testlib/selftests/expected_testlib.lightxml b/tests/auto/testlib/selftests/expected_testlib.lightxml
index cd0f96d6d4..76435eb9f0 100644
--- a/tests/auto/testlib/selftests/expected_testlib.lightxml
+++ b/tests/auto/testlib/selftests/expected_testlib.lightxml
@@ -11,7 +11,7 @@
<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/testlib/tst_testlib.cpp" line="0">
<Description><![CDATA[Compared QObject pointers are not the same
Actual (QTest::testObject()): tst_TestLib/"TestObject"
- Expected (nullptr) : (nullptr)]]></Description>
+ Expected (nullptr) : "nullptr"]]></Description>
</Incident>
<Duration msecs="0"/>
</TestFunction>
diff --git a/tests/auto/testlib/selftests/expected_testlib.tap b/tests/auto/testlib/selftests/expected_testlib.tap
index 4a6056bc77..1fa7dc77c4 100644
--- a/tests/auto/testlib/selftests/expected_testlib.tap
+++ b/tests/auto/testlib/selftests/expected_testlib.tap
@@ -5,9 +5,9 @@ not ok 2 - basics()
---
type: QCOMPARE
message: Compared QObject pointers are not the same
- wanted: (nullptr) (nullptr)
+ wanted: "nullptr" (nullptr)
found: tst_TestLib/"TestObject" (QTest::testObject())
- expected: (nullptr) (nullptr)
+ expected: "nullptr" (nullptr)
actual: tst_TestLib/"TestObject" (QTest::testObject())
at: tst_TestLib::basics() (qtbase/tests/auto/testlib/selftests/testlib/tst_testlib.cpp:0)
file: qtbase/tests/auto/testlib/selftests/testlib/tst_testlib.cpp
diff --git a/tests/auto/testlib/selftests/expected_testlib.teamcity b/tests/auto/testlib/selftests/expected_testlib.teamcity
index 279ef03f3f..52f7fa244c 100644
--- a/tests/auto/testlib/selftests/expected_testlib.teamcity
+++ b/tests/auto/testlib/selftests/expected_testlib.teamcity
@@ -2,7 +2,7 @@
##teamcity[testStarted name='initTestCase()' flowId='tst_TestLib']
##teamcity[testFinished name='initTestCase()' flowId='tst_TestLib']
##teamcity[testStarted name='basics()' flowId='tst_TestLib']
-##teamcity[testFailed name='basics()' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/testlib/tst_testlib.cpp(0)|]' details='Compared QObject pointers are not the same|n Actual (QTest::testObject()): tst_TestLib/"TestObject"|n Expected (nullptr) : (nullptr)' flowId='tst_TestLib']
+##teamcity[testFailed name='basics()' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/testlib/tst_testlib.cpp(0)|]' details='Compared QObject pointers are not the same|n Actual (QTest::testObject()): tst_TestLib/"TestObject"|n Expected (nullptr) : "nullptr"' flowId='tst_TestLib']
##teamcity[testFinished name='basics()' flowId='tst_TestLib']
##teamcity[testStarted name='delays()' flowId='tst_TestLib']
##teamcity[testFinished name='delays()' flowId='tst_TestLib']
diff --git a/tests/auto/testlib/selftests/expected_testlib.txt b/tests/auto/testlib/selftests/expected_testlib.txt
index a0b8a275d0..4d652626e9 100644
--- a/tests/auto/testlib/selftests/expected_testlib.txt
+++ b/tests/auto/testlib/selftests/expected_testlib.txt
@@ -3,7 +3,7 @@ Config: Using QtTest library
PASS : tst_TestLib::initTestCase()
FAIL! : tst_TestLib::basics() Compared QObject pointers are not the same
Actual (QTest::testObject()): tst_TestLib/"TestObject"
- Expected (nullptr) : (nullptr)
+ Expected (nullptr) : "nullptr"
Loc: [qtbase/tests/auto/testlib/selftests/testlib/tst_testlib.cpp(0)]
PASS : tst_TestLib::delays()
PASS : tst_TestLib::reals(zero)
diff --git a/tests/auto/testlib/selftests/expected_testlib.xml b/tests/auto/testlib/selftests/expected_testlib.xml
index 241fd3f8d1..8b66b003d0 100644
--- a/tests/auto/testlib/selftests/expected_testlib.xml
+++ b/tests/auto/testlib/selftests/expected_testlib.xml
@@ -13,7 +13,7 @@
<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/testlib/tst_testlib.cpp" line="0">
<Description><![CDATA[Compared QObject pointers are not the same
Actual (QTest::testObject()): tst_TestLib/"TestObject"
- Expected (nullptr) : (nullptr)]]></Description>
+ Expected (nullptr) : "nullptr"]]></Description>
</Incident>
<Duration msecs="0"/>
</TestFunction>
diff --git a/tests/auto/testlib/selftests/extendedcompare/tst_extendedcompare.cpp b/tests/auto/testlib/selftests/extendedcompare/tst_extendedcompare.cpp
index cc75e7f7fb..70a7798667 100644
--- a/tests/auto/testlib/selftests/extendedcompare/tst_extendedcompare.cpp
+++ b/tests/auto/testlib/selftests/extendedcompare/tst_extendedcompare.cpp
@@ -93,11 +93,13 @@ static ClassWithPointerGetter getClassForValue(int val)
// various toString() overloads
namespace QTest {
-char *toString(const int *val)
+template <> char *toString(const int *const &val)
{
return val ? toString(*val) : toString(nullptr);
}
+} // namespace QTest
+
char *toString(const MyClass &val)
{
char *msg = new char[128];
@@ -117,8 +119,6 @@ char *toString(const MyClass *val)
return toString(nullptr);
}
-} // namespace QTest
-
enum MyUnregisteredEnum { MyUnregisteredEnumValue1, MyUnregisteredEnumValue2 };
class tst_ExtendedCompare : public QObject
@@ -293,8 +293,6 @@ public:
}
};
-namespace QTest {
-
char *toString(const ClassWithDeferredSetter &val)
{
char *msg = new char[128];
@@ -302,8 +300,6 @@ char *toString(const ClassWithDeferredSetter &val)
return msg;
}
-} // namespace QTest
-
void tst_ExtendedCompare::checkComparisonWithTimeout()
{
QFETCH_GLOBAL(QTest::ComparisonOperation, operation);
diff --git a/tests/auto/tools/moc/os9-newlines.h b/tests/auto/tools/moc/os9-newlines.h
index 82bddd117d..2da70f6a89 100644
--- a/tests/auto/tools/moc/os9-newlines.h
+++ b/tests/auto/tools/moc/os9-newlines.h
@@ -1 +1 @@
-// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <QObject> class Os9Newlines : public QObject { Q_OBJECT public Q_SLOTS: inline void testSlot() {} }; \ No newline at end of file
+// REUSE-IgnoreStart // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // REUSE-IgnoreEnd #include <QObject> class Os9Newlines : public QObject { Q_OBJECT public Q_SLOTS: inline void testSlot() {} }; \ No newline at end of file
diff --git a/tests/auto/tools/uic/baseline/icontheme.ui.h b/tests/auto/tools/uic/baseline/icontheme.ui.h
index 633ba81d37..b3e1e3fa0c 100644
--- a/tests/auto/tools/uic/baseline/icontheme.ui.h
+++ b/tests/auto/tools/uic/baseline/icontheme.ui.h
@@ -38,7 +38,7 @@ public:
fileicon = new QPushButton(Form);
fileicon->setObjectName("fileicon");
QIcon icon;
- icon.addFile(QString::fromUtf8("image1.png"), QSize(), QIcon::Normal, QIcon::Off);
+ icon.addFile(QString::fromUtf8("image1.png"), QSize(), QIcon::Mode::Normal, QIcon::State::Off);
fileicon->setIcon(icon);
verticalLayout->addWidget(fileicon);
@@ -50,7 +50,7 @@ public:
if (QIcon::hasThemeIcon(iconThemeName)) {
icon1 = QIcon::fromTheme(iconThemeName);
} else {
- icon1.addFile(QString::fromUtf8("image7.png"), QSize(), QIcon::Normal, QIcon::Off);
+ icon1.addFile(QString::fromUtf8("image7.png"), QSize(), QIcon::Mode::Normal, QIcon::State::Off);
}
fileandthemeicon->setIcon(icon1);
@@ -76,7 +76,7 @@ public:
if (QIcon::hasThemeIcon(QIcon::ThemeIcon::EditCopy)) {
icon4 = QIcon::fromTheme(QIcon::ThemeIcon::EditCopy);
} else {
- icon4.addFile(QString::fromUtf8("image7.png"), QSize(), QIcon::Normal, QIcon::Off);
+ icon4.addFile(QString::fromUtf8("image7.png"), QSize(), QIcon::Mode::Normal, QIcon::State::Off);
}
fileandthemeenum->setIcon(icon4);
diff --git a/tests/auto/tools/uic/baseline/languagesdialog.ui.h b/tests/auto/tools/uic/baseline/languagesdialog.ui.h
index cd2e1b0cd5..d3a927a434 100644
--- a/tests/auto/tools/uic/baseline/languagesdialog.ui.h
+++ b/tests/auto/tools/uic/baseline/languagesdialog.ui.h
@@ -55,7 +55,7 @@ public:
upButton->setObjectName("upButton");
upButton->setEnabled(false);
QIcon icon;
- icon.addFile(QString::fromUtf8(":/images/up.png"), QSize(), QIcon::Normal, QIcon::Off);
+ icon.addFile(QString::fromUtf8(":/images/up.png"), QSize(), QIcon::Mode::Normal, QIcon::State::Off);
upButton->setIcon(icon);
hboxLayout->addWidget(upButton);
@@ -64,7 +64,7 @@ public:
downButton->setObjectName("downButton");
downButton->setEnabled(false);
QIcon icon1;
- icon1.addFile(QString::fromUtf8(":/images/down.png"), QSize(), QIcon::Normal, QIcon::Off);
+ icon1.addFile(QString::fromUtf8(":/images/down.png"), QSize(), QIcon::Mode::Normal, QIcon::State::Off);
downButton->setIcon(icon1);
hboxLayout->addWidget(downButton);
@@ -73,7 +73,7 @@ public:
removeButton->setObjectName("removeButton");
removeButton->setEnabled(false);
QIcon icon2;
- icon2.addFile(QString::fromUtf8(":/images/editdelete.png"), QSize(), QIcon::Normal, QIcon::Off);
+ icon2.addFile(QString::fromUtf8(":/images/editdelete.png"), QSize(), QIcon::Mode::Normal, QIcon::State::Off);
removeButton->setIcon(icon2);
hboxLayout->addWidget(removeButton);
@@ -82,7 +82,7 @@ public:
openFileButton->setObjectName("openFileButton");
openFileButton->setEnabled(true);
QIcon icon3;
- icon3.addFile(QString::fromUtf8(":/images/mac/fileopen.png"), QSize(), QIcon::Normal, QIcon::Off);
+ icon3.addFile(QString::fromUtf8(":/images/mac/fileopen.png"), QSize(), QIcon::Mode::Normal, QIcon::State::Off);
openFileButton->setIcon(icon3);
hboxLayout->addWidget(openFileButton);
diff --git a/tests/auto/tools/uic/baseline/pixmapfunction.ui.h b/tests/auto/tools/uic/baseline/pixmapfunction.ui.h
index 541b4910e4..f7bca4c396 100644
--- a/tests/auto/tools/uic/baseline/pixmapfunction.ui.h
+++ b/tests/auto/tools/uic/baseline/pixmapfunction.ui.h
@@ -42,10 +42,10 @@ public:
pushButton = new QPushButton(Form);
pushButton->setObjectName("pushButton");
QIcon icon;
- icon.addPixmap(QPixmap(pixmapFunction("buttonIconNormalOff")), QIcon::Normal, QIcon::Off);
- icon.addPixmap(QPixmap(pixmapFunction("buttonIconNormalOn")), QIcon::Normal, QIcon::On);
- icon.addPixmap(QPixmap(pixmapFunction("buttonIconDisabledOff")), QIcon::Disabled, QIcon::Off);
- icon.addPixmap(QPixmap(pixmapFunction("buttonIconDisabledOn")), QIcon::Disabled, QIcon::On);
+ icon.addPixmap(QPixmap(pixmapFunction("buttonIconNormalOff")), QIcon::Mode::Normal, QIcon::State::Off);
+ icon.addPixmap(QPixmap(pixmapFunction("buttonIconNormalOn")), QIcon::Mode::Normal, QIcon::State::On);
+ icon.addPixmap(QPixmap(pixmapFunction("buttonIconDisabledOff")), QIcon::Mode::Disabled, QIcon::State::Off);
+ icon.addPixmap(QPixmap(pixmapFunction("buttonIconDisabledOn")), QIcon::Mode::Disabled, QIcon::State::On);
pushButton->setIcon(icon);
verticalLayout->addWidget(pushButton);
diff --git a/tests/auto/wasm/fetchapi/tst_fetchapi.cpp b/tests/auto/wasm/fetchapi/tst_fetchapi.cpp
index 3dcd8dd916..e37316b2db 100644
--- a/tests/auto/wasm/fetchapi/tst_fetchapi.cpp
+++ b/tests/auto/wasm/fetchapi/tst_fetchapi.cpp
@@ -69,11 +69,9 @@ void tst_FetchApi::sendRequestOnMainThread()
void tst_FetchApi::sendRequestOnBackgroundThread()
{
- QSKIP("Skip this test until we fix fetching from background threads.");
QEventLoop mainEventLoop;
BackgroundThread *backgroundThread = new BackgroundThread();
connect(backgroundThread, &BackgroundThread::finished, &mainEventLoop, &QEventLoop::quit);
- connect(backgroundThread, &BackgroundThread::finished, backgroundThread, &QObject::deleteLater);
backgroundThread->start();
mainEventLoop.exec();
diff --git a/tests/auto/wasm/selenium/run.bat b/tests/auto/wasm/selenium/run.bat
index 031e0b13ab..56305c72c3 100644
--- a/tests/auto/wasm/selenium/run.bat
+++ b/tests/auto/wasm/selenium/run.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
::
:: The highest version of python that can be used is 3.11
:: Download from here: https://www.python.org/downloads/release/python-3118/
diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp
index 4eaa592022..6ebf255f31 100644
--- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp
+++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp
@@ -1117,7 +1117,6 @@ void tst_QFiledialog::focus()
QFileDialog fd;
fd.setDirectory(QDir::currentPath());
fd.show();
- QApplicationPrivate::setActiveWindow(&fd);
QVERIFY(QTest::qWaitForWindowActive(&fd));
QCOMPARE(fd.isVisible(), true);
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd));
diff --git a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp
index b330d4d869..c34c8559da 100644
--- a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp
+++ b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp
@@ -1265,7 +1265,6 @@ void tst_QFileDialog2::QTBUG6558_showDirsOnly()
fd.setOption(QFileDialog::ShowDirsOnly, true);
fd.show();
- QApplicationPrivate::setActiveWindow(&fd);
QVERIFY(QTest::qWaitForWindowActive(&fd));
QCOMPARE(fd.isVisible(), true);
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd));
@@ -1309,7 +1308,6 @@ void tst_QFileDialog2::QTBUG4842_selectFilterWithHideNameFilterDetails()
fd.selectNameFilter(chosenFilterString);
fd.show();
- QApplicationPrivate::setActiveWindow(&fd);
QVERIFY(QTest::qWaitForWindowActive(&fd));
QCOMPARE(fd.isVisible(), true);
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd));
@@ -1325,7 +1323,6 @@ void tst_QFileDialog2::QTBUG4842_selectFilterWithHideNameFilterDetails()
fd2.selectNameFilter(chosenFilterString);
fd2.show();
- QApplicationPrivate::setActiveWindow(&fd2);
QVERIFY(QTest::qWaitForWindowActive(&fd2));
QCOMPARE(fd2.isVisible(), true);
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd2));
@@ -1345,7 +1342,6 @@ void tst_QFileDialog2::dontShowCompleterOnRoot()
fd.setAcceptMode(QFileDialog::AcceptSave);
fd.show();
- QApplicationPrivate::setActiveWindow(&fd);
QVERIFY(QTest::qWaitForWindowActive(&fd));
QCOMPARE(fd.isVisible(), true);
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd));
diff --git a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
index c91a0803ee..fad75ec045 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
@@ -2976,11 +2976,6 @@ static QSizeF wfh(Qt::SizeHint /*which*/, const QSizeF &constraint)
return result;
}
-bool qFuzzyCompare(const QSizeF &a, const QSizeF &b)
-{
- return qFuzzyCompare(a.width(), b.width()) && qFuzzyCompare(a.height(), b.height());
-}
-
void tst_QGraphicsGridLayout::heightForWidth()
{
QGraphicsWidget *widget = new QGraphicsWidget;
diff --git a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp
index a9fccaf4b2..35356adcfc 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -993,7 +993,6 @@ void tst_QGraphicsItem::inputMethodHints()
scene.addItem(item);
scene.addItem(item2);
QGraphicsView view(&scene);
- QApplicationPrivate::setActiveWindow(&view);
view.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
@@ -1050,7 +1049,6 @@ void tst_QGraphicsItem::toolTip()
view.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
view.setFixedSize(200, 200);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
{
@@ -4946,7 +4944,6 @@ void tst_QGraphicsItem::sceneEventFilter()
QGraphicsView view(&scene);
view.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -5567,7 +5564,6 @@ void tst_QGraphicsItem::itemClipsChildrenToShape4()
scene.addEllipse( 100, 100, 100, 50 ); // <-- this is important to trigger the right codepath*
//now the label is shown
outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false );
- QApplicationPrivate::setActiveWindow(&view);
view.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
view.show();
QTRY_COMPARE(QApplication::activeWindow(), &view);
@@ -10931,7 +10927,6 @@ void tst_QGraphicsItem::focusHandling()
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
- QApplicationPrivate::setActiveWindow(&view);
QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
QVERIFY(itemWithFocus->hasFocus());
diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
index c5cbecff65..ee1a8c530a 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
@@ -709,7 +709,6 @@ void tst_QGraphicsProxyWidget::focusNextPrevChild()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
if (hasScene) {
scene.addItem(proxyGuard.release());
@@ -751,7 +750,6 @@ void tst_QGraphicsProxyWidget::focusOutEvent()
SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
scene.addItem(proxy);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
view.activateWindow();
view.setFocus();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -933,7 +931,6 @@ void tst_QGraphicsProxyWidget::hoverEnterLeaveEvent()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
@@ -987,7 +984,6 @@ void tst_QGraphicsProxyWidget::keyPressEvent()
QGraphicsView view(&scene);
view.show();
view.viewport()->setFocus();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), (QWidget*)&view);
@@ -1026,7 +1022,6 @@ void tst_QGraphicsProxyWidget::keyReleaseEvent()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), (QWidget*)&view);
@@ -1072,7 +1067,6 @@ void tst_QGraphicsProxyWidget::mouseDoubleClickEvent()
view.resize(100, 100);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), (QWidget*)&view);
// wait for scene to be updated before doing any coordinate mappings on it
@@ -1158,7 +1152,6 @@ void tst_QGraphicsProxyWidget::paintEvent()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(view.isActiveWindow());
@@ -1545,7 +1538,6 @@ void tst_QGraphicsProxyWidget::tabFocus_simpleWidget()
window.setLayout(layout);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
@@ -1629,7 +1621,6 @@ void tst_QGraphicsProxyWidget::tabFocus_simpleTwoWidgets()
window.setLayout(layout);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
@@ -1762,7 +1753,6 @@ void tst_QGraphicsProxyWidget::tabFocus_complexWidget()
window.setLayout(layout);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
@@ -1899,7 +1889,6 @@ void tst_QGraphicsProxyWidget::tabFocus_complexTwoWidgets()
window.setLayout(layout);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
@@ -2073,7 +2062,6 @@ void tst_QGraphicsProxyWidget::setFocus_simpleWidget()
window.setLayout(layout);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(QApplication::activeWindow(), &window);
@@ -2145,7 +2133,6 @@ void tst_QGraphicsProxyWidget::setFocus_simpleTwoWidgets()
window.setLayout(layout);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(QApplication::activeWindow(), &window);
@@ -2224,7 +2211,6 @@ void tst_QGraphicsProxyWidget::setFocus_complexTwoWidgets()
window.setLayout(layout);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(QApplication::activeWindow(), &window);
@@ -2469,7 +2455,6 @@ void tst_QGraphicsProxyWidget::tooltip_basic()
QGraphicsView view(&scene);
view.setFixedSize(200, 200);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
{
QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
@@ -3005,7 +2990,6 @@ void tst_QGraphicsProxyWidget::actionsContextMenu()
view.resize(200, 200);
view.move(QGuiApplication::primaryScreen()->geometry().center() - QPoint(100, 100));
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
view.setFocus();
QTRY_VERIFY(view.hasFocus());
@@ -3087,7 +3071,6 @@ void tst_QGraphicsProxyWidget::bypassGraphicsProxyWidget()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QGraphicsProxyWidget *proxy = scene.addWidget(widgetGuard.release());
@@ -3353,7 +3336,6 @@ void tst_QGraphicsProxyWidget::clickFocus()
view.setFrameStyle(0);
view.resize(300, 300);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(!proxy->hasFocus());
@@ -3497,7 +3479,6 @@ void tst_QGraphicsProxyWidget::QTBUG_6986_sendMouseEventToAlienWidget()
QGraphicsView view(&scene);
view.resize(600, 600);
- QApplicationPrivate::setActiveWindow(&view);
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -3541,7 +3522,6 @@ void tst_QGraphicsProxyWidget::mapToGlobal() // QTBUG-41135
childWidget->resize(embeddedWidget->size() / 2);
childWidget->move(embeddedWidget->width() / 4, embeddedWidget->height() / 4); // center in embeddedWidget
scene.addWidget(embeddedWidget);
- QApplicationPrivate::setActiveWindow(&view);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
const QPoint embeddedCenter = embeddedWidget->rect().center();
diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
index 3ea728abf6..515ba80bbe 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
@@ -1294,7 +1294,6 @@ void tst_QGraphicsScene::removeItem()
view.setWindowTitle(QTest::currentTestFunction());
view.setFixedSize(150, 150);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QTest::mouseMove(view.windowHandle(), view.mapFromScene(hoverItem->scenePos() + QPointF(20, 20)));
QTRY_VERIFY(!hoverItem->isHovered);
@@ -1602,7 +1601,6 @@ void tst_QGraphicsScene::hoverEvents_siblings()
view.rotate(10);
view.scale(1.7, 1.7);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
view.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -1672,7 +1670,6 @@ void tst_QGraphicsScene::hoverEvents_parentChild()
view.rotate(10);
view.scale(1.7, 1.7);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
@@ -2854,7 +2851,6 @@ void tst_QGraphicsScene::update2()
view.resize(m_testSize);
view.setScene(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QTRY_VERIFY(view.repaints >= 1);
view.repaints = 0;
@@ -3044,7 +3040,6 @@ void tst_QGraphicsScene::tabFocus_emptyScene()
widget.setLayout(layout);
widget.setWindowTitle(QTest::currentTestFunction());
widget.show();
- QApplicationPrivate::setActiveWindow(&widget);
widget.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&widget));
@@ -3096,7 +3091,6 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusableItems()
widget.setWindowTitle(QTest::currentTestFunction());
widget.setLayout(layout);
widget.show();
- QApplicationPrivate::setActiveWindow(&widget);
widget.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&widget));
@@ -3825,7 +3819,6 @@ void tst_QGraphicsScene::inputMethod()
view.resize(m_testSize);
view.show();
view.setWindowTitle(QTest::currentTestFunction());
- QApplicationPrivate::setActiveWindow(&view);
view.setFocus();
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), &view);
@@ -4069,7 +4062,6 @@ void tst_QGraphicsScene::isActive()
view1->setVisible(false);
toplevel1.show();
- QApplicationPrivate::setActiveWindow(&toplevel1);
QVERIFY(QTest::qWaitForWindowActive(&toplevel1));
QCOMPARE(QApplication::activeWindow(), &toplevel1);
@@ -4246,7 +4238,6 @@ void tst_QGraphicsScene::isActive()
toplevel3.show();
- QApplicationPrivate::setActiveWindow(&toplevel3);
QVERIFY(QTest::qWaitForWindowActive(&toplevel3));
QCOMPARE(QApplication::activeWindow(), &toplevel3);
@@ -4359,7 +4350,6 @@ void tst_QGraphicsScene::removeFullyTransparentItem()
view.resize(m_testSize);
view.setScene(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCoreApplication::processEvents(); // Process all queued paint events
@@ -4817,7 +4807,6 @@ void tst_QGraphicsScene::focusOnTouch()
rect->setFlag(QGraphicsItem::ItemIsFocusable, true);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(!rect->hasFocus());
@@ -4918,7 +4907,6 @@ void tst_QGraphicsScene::taskQTBUG_16401_focusItem()
rect->setFlag(QGraphicsItem::ItemIsFocusable);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(!scene.focusItem());
@@ -4960,7 +4948,6 @@ void tst_QGraphicsScene::taskQTBUG_42915_focusNextPrevChild()
widget2->setFocusPolicy(Qt::NoFocus);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QTest::keyEvent(QTest::Click, &view, Qt::Key_Tab);
diff --git a/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp b/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp
index b62a24eaef..b6d48b52d5 100644
--- a/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp
@@ -291,7 +291,6 @@ void tst_QGraphicsSceneIndex::removeItems()
QGraphicsView view(&scene);
view.resize(600, 600);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
scene.removeItem(widgetChild1);
@@ -323,7 +322,6 @@ void tst_QGraphicsSceneIndex::clear()
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
scene.clear();
diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
index 346469a6ea..7ed1f28b0a 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
@@ -2153,7 +2153,6 @@ void tst_QGraphicsView::sendEvent()
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
@@ -2221,7 +2220,6 @@ void tst_QGraphicsView::wheelEvent()
// Assign a view.
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
@@ -2458,7 +2456,6 @@ void tst_QGraphicsView::viewportUpdateMode()
// Show the view, and initialize our test.
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
QTRY_VERIFY(!view.lastUpdateRegions.isEmpty());
@@ -2541,7 +2538,6 @@ void tst_QGraphicsView::viewportUpdateMode2()
const QMargins margins = view.contentsMargins();
view.resize(200 + margins.left() + margins.right(), 200 + margins.top() + margins.bottom());
toplevel.show();
- QApplicationPrivate::setActiveWindow(&toplevel);
QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
QVERIFY(QTest::qWaitForWindowActive(&toplevel));
QTRY_VERIFY(view.painted);
@@ -3189,7 +3185,6 @@ void tst_QGraphicsView::task172231_untransformableItems()
view.scale(2, 1);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
@@ -3251,7 +3246,6 @@ void tst_QGraphicsView::task187791_setSceneCausesUpdate()
QGraphicsScene scene(0, 0, 200, 200);
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
EventSpy updateSpy(view.viewport(), QEvent::Paint);
@@ -3338,7 +3332,6 @@ void tst_QGraphicsView::task207546_focusCrash()
widget.layout()->addWidget(gr2);
widget.show();
widget.activateWindow();
- QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&widget));
widget.focusNextPrevChild(true);
@@ -3430,7 +3423,6 @@ void tst_QGraphicsView::task239729_noViewUpdate()
QCOMPARE(spy.count(), 0);
view->show();
- QApplicationPrivate::setActiveWindow(view);
QVERIFY(QTest::qWaitForWindowActive(view));
QTRY_VERIFY(spy.count() >= 1);
@@ -4135,7 +4127,6 @@ void tst_QGraphicsView::update()
QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
- QApplicationPrivate::setActiveWindow(&toplevel);
QApplication::processEvents();
QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&toplevel));
@@ -4405,7 +4396,6 @@ void tst_QGraphicsView::inputMethodSensitivity()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
@@ -4503,7 +4493,6 @@ void tst_QGraphicsView::inputContextReset()
QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
@@ -4651,7 +4640,6 @@ void tst_QGraphicsView::task255529_transformationAnchorMouseAndViewportMargins()
VpGraphicsView view(&scene);
view.setWindowFlags(Qt::X11BypassWindowManagerHint);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
const bool isActiveWindow = QTest::qWaitForWindowActive(&view);
if (!isActiveWindow)
@@ -4825,7 +4813,6 @@ void tst_QGraphicsView::QTBUG_5859_exposedRect()
QGraphicsView view(&scene);
view.scale(4.15, 4.15);
view.showNormal();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -4897,7 +4884,6 @@ void tst_QGraphicsView::hoverLeave()
scene.addItem(item);
view.showNormal();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
QWindow *viewWindow = view.window()->windowHandle();
@@ -4976,7 +4962,6 @@ void tst_QGraphicsView::QTBUG_70255_scrollTo()
view.centerOn(0, 0);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
if (!QTest::qWaitForWindowExposed(&view) || !QTest::qWaitForWindowActive(&view))
QSKIP("Failed to show and activate window");
diff --git a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp
index e298747284..9fd93ca91d 100644
--- a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp
@@ -1388,7 +1388,6 @@ void tst_QGraphicsWidget::setTabOrder()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QGraphicsWidget *lastItem = nullptr;
@@ -1460,7 +1459,6 @@ void tst_QGraphicsWidget::setTabOrderAndReparent()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(QApplication::activeWindow(), (QWidget*)&view);
@@ -1590,7 +1588,6 @@ void tst_QGraphicsWidget::verifyFocusChain()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
{
@@ -1682,7 +1679,6 @@ void tst_QGraphicsWidget::verifyFocusChain()
w1_2->setFocusPolicy(Qt::StrongFocus);
scene.addItem(w1_2);
window->show();
- QApplicationPrivate::setActiveWindow(window.data());
QVERIFY(QTest::qWaitForWindowActive(window.data()));
lineEdit->setFocus();
@@ -2694,7 +2690,6 @@ void tst_QGraphicsWidget::task250119_shortcutContext()
QGraphicsView view;
view.setScene(&scene);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QTRY_COMPARE(QApplication::activeWindow(), (QWidget*)&view);
diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp
index b221047798..4f2495375d 100644
--- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp
+++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp
@@ -1051,7 +1051,6 @@ void tst_QAbstractItemView::setItemDelegate()
centerOnScreen(&v);
moveCursorAway(&v);
v.show();
- QApplicationPrivate::setActiveWindow(&v);
QVERIFY(QTest::qWaitForWindowActive(&v));
QModelIndex index = model.index(cellToEdit.y(), cellToEdit.x());
@@ -1260,7 +1259,6 @@ void tst_QAbstractItemView::task221955_selectedEditor()
tree.show();
tree.setFocus();
tree.setCurrentIndex(tree.model()->index(1,0));
- QApplicationPrivate::setActiveWindow(&tree);
QVERIFY(QTest::qWaitForWindowActive(&tree));
QVERIFY(! tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0)));
@@ -1559,7 +1557,6 @@ void tst_QAbstractItemView::QTBUG6407_extendedSelection()
moveCursorAway(&view);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(&view, QApplication::activeWindow());
@@ -1657,7 +1654,6 @@ void tst_QAbstractItemView::testClickedSignal()
centerOnScreen(&view);
moveCursorAway(&view);
view.showNormal();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(&view, QApplication::activeWindow());
@@ -1708,7 +1704,6 @@ void tst_QAbstractItemView::testChangeEditorState()
centerOnScreen(&view);
moveCursorAway(&view);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(&view, QApplication::activeWindow());
@@ -1729,7 +1724,6 @@ void tst_QAbstractItemView::deselectInSingleSelection()
QVERIFY(QTest::qWaitForWindowExposed(&view));
view.setSelectionMode(QAbstractItemView::SingleSelection);
view.setEditTriggers(QAbstractItemView::NoEditTriggers);
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowExposed(&view));
// mouse
QModelIndex index22 = s.index(2, 2);
@@ -1776,7 +1770,6 @@ void tst_QAbstractItemView::testNoActivateOnDisabledItem()
moveCursorAway(&treeView);
treeView.show();
- QApplicationPrivate::setActiveWindow(&treeView);
QVERIFY(QTest::qWaitForWindowActive(&treeView));
QSignalSpy activatedSpy(&treeView, &QAbstractItemView::activated);
@@ -1823,7 +1816,6 @@ void tst_QAbstractItemView::testFocusPolicy()
moveCursorAway(&window);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
// itemview accepts focus => editor is closed => return focus to the itemview
@@ -1861,7 +1853,6 @@ void tst_QAbstractItemView::QTBUG31411_noSelection()
moveCursorAway(&window);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
qRegisterMetaType<QItemSelection>();
@@ -2461,15 +2452,11 @@ void tst_QAbstractItemView::inputMethodEnabled()
// Check focus by switching the activation of the window to force a focus in
view->setCurrentIndex(model->index(1, 0));
- QApplicationPrivate::setActiveWindow(nullptr);
- QApplicationPrivate::setActiveWindow(view.data());
QVERIFY(QTest::qWaitForWindowActive(view.data()));
QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result);
view->setCurrentIndex(QModelIndex());
QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled));
- QApplicationPrivate::setActiveWindow(nullptr);
- QApplicationPrivate::setActiveWindow(view.data());
QVERIFY(QTest::qWaitForWindowActive(view.data()));
QModelIndex index = model->index(1, 0);
QPoint p = view->visualRect(index).center();
@@ -2479,8 +2466,6 @@ void tst_QAbstractItemView::inputMethodEnabled()
QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result);
index = model->index(0, 0);
- QApplicationPrivate::setActiveWindow(nullptr);
- QApplicationPrivate::setActiveWindow(view.data());
QVERIFY(QTest::qWaitForWindowActive(view.data()));
p = view->visualRect(index).center();
QTest::mouseClick(view->viewport(), Qt::LeftButton, Qt::NoModifier, p);
diff --git a/tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp b/tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp
index 82398cd6bb..c3527e4215 100644
--- a/tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp
+++ b/tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp
@@ -420,7 +420,6 @@ void tst_QDataWidgetMapper::textEditDoesntChangeFocusOnTab_qtbug3305()
container.show();
- QApplicationPrivate::setActiveWindow(&container);
QVERIFY(QTest::qWaitForWindowActive(&container));
int closeEditorSpyCount = 0;
diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
index 46d97b4da1..57efa3e349 100644
--- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
+++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
@@ -1620,7 +1620,6 @@ void tst_QHeaderView::focusPolicy()
widget.show();
widget.setFocus(Qt::OtherFocusReason);
- QApplicationPrivate::setActiveWindow(&widget);
widget.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&widget));
QVERIFY(widget.hasFocus());
@@ -3612,7 +3611,6 @@ void tst_QHeaderView::statusTips()
headerView.setGeometry(QRect(QPoint(QGuiApplication::primaryScreen()->geometry().center() - QPoint(250, 250)),
QSize(500, 500)));
headerView.show();
- QApplicationPrivate::setActiveWindow(&headerView);
QVERIFY(QTest::qWaitForWindowActive(&headerView));
// Ensure it is moved away first and then moved to the relevant section
diff --git a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
index e1488e4484..769456951f 100644
--- a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
+++ b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
@@ -747,7 +747,6 @@ void tst_QItemDelegate::dateTimeEditor()
widget.setItem(0, 2, item3);
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
- QApplicationPrivate::setActiveWindow(&widget);
widget.editItem(item1);
@@ -763,7 +762,6 @@ void tst_QItemDelegate::dateTimeEditor()
timeEditor->setTime(time.addSecs(60));
widget.clearFocus();
- QApplicationPrivate::setActiveWindow(&widget);
widget.setFocus();
widget.editItem(item2);
@@ -1027,7 +1025,6 @@ void tst_QItemDelegate::decoration()
TestItemDelegate delegate;
table.setItemDelegate(&delegate);
table.show();
- QApplicationPrivate::setActiveWindow(&table);
QVERIFY(QTest::qWaitForWindowActive(&table));
QVariant value;
@@ -1282,7 +1279,6 @@ void tst_QItemDelegate::enterKey()
QListView view;
view.setModel(&model);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
view.setFocus();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -1342,7 +1338,6 @@ void tst_QItemDelegate::task257859_finalizeEdit()
QListView view;
view.setModel(&model);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
view.setFocus();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -1469,7 +1464,6 @@ void tst_QItemDelegate::testLineEditValidation()
view.setItemDelegate(&delegate);
view.show();
view.setFocus();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QPointer<QLineEdit> editor;
diff --git a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
index fa290d5f6e..236cd6212f 100644
--- a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
+++ b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
@@ -1707,7 +1707,6 @@ void tst_QListView::keyboardSearch()
QListView view;
view.setModel(&model);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QTest::keyClick(&view, Qt::Key_K);
@@ -1809,7 +1808,6 @@ void tst_QListView::shiftSelectionWithItemAlignment()
view.resize(300, view.sizeHintForRow(0) * items.size() / 2 + view.horizontalScrollBar()->height());
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(static_cast<QWidget *>(&view), QApplication::activeWindow());
@@ -1868,7 +1866,6 @@ void tst_QListView::task262152_setModelColumnNavigate()
view.setModelColumn(1);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(&view, QApplication::activeWindow());
QTest::keyClick(&view, Qt::Key_Down);
@@ -2814,7 +2811,6 @@ void tst_QListView::moveLastRow()
view.setViewMode(QListView::IconMode);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QModelIndex sourceParent = model.index(0, 0);
diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
index 1f46f19569..14a6cee0d9 100644
--- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
+++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
@@ -1810,7 +1810,6 @@ void tst_QListWidget::QTBUG14363_completerWithAnyKeyPressedEditTriggers()
new QListWidgetItem(QLatin1String("completer"), &listWidget);
listWidget.show();
listWidget.setCurrentItem(item);
- QApplicationPrivate::setActiveWindow(&listWidget);
QVERIFY(QTest::qWaitForWindowActive(&listWidget));
listWidget.setFocus();
QCOMPARE(QApplication::focusWidget(), &listWidget);
diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
index 45a467d423..681be2491d 100644
--- a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
+++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
@@ -610,7 +610,6 @@ void tst_QTableView::keyboardNavigation()
view.setCurrentIndex(index);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
int row = rowCount - 1;
@@ -3829,7 +3828,6 @@ void tst_QTableView::tabFocus()
QLineEdit *edit = new QLineEdit(&window);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
window.setFocus();
window.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&window));
diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
index 14169976e4..9b02b0e80d 100644
--- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
+++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
@@ -1240,7 +1240,6 @@ void tst_QTreeView::keyboardSearchMultiColumn()
view.setModel(&model);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
view.setCurrentIndex(model.index(0, 1));
@@ -1926,7 +1925,6 @@ void tst_QTreeView::moveCursor()
view.setColumnHidden(0, true);
QVERIFY(view.isColumnHidden(0));
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
//here the first visible index should be selected
@@ -3705,7 +3703,6 @@ void tst_QTreeView::task224091_appendColumns()
treeView->setModel(model);
topLevel->show();
treeView->resize(50, 50);
- QApplicationPrivate::setActiveWindow(topLevel);
QVERIFY(QTest::qWaitForWindowActive(topLevel));
QVERIFY(!treeView->verticalScrollBar()->isVisible());
@@ -4081,7 +4078,6 @@ void tst_QTreeView::doubleClickedWithSpans()
view.setModel(&model);
view.setFirstColumnSpanned(0, QModelIndex(), true);
view.show();
- QApplicationPrivate::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(view.isActiveWindow());
@@ -4183,7 +4179,6 @@ void tst_QTreeView::keyboardNavigationWithDisabled()
view.resize(200, view.visualRect(model.index(0,0)).height()*10);
topLevel.show();
- QApplicationPrivate::setActiveWindow(&topLevel);
QVERIFY(QTest::qWaitForWindowActive(&topLevel));
QVERIFY(topLevel.isActiveWindow());
@@ -4769,7 +4764,6 @@ void tst_QTreeView::statusTip()
mw.setGeometry(QRect(QPoint(QGuiApplication::primaryScreen()->geometry().center() - QPoint(250, 250)),
QSize(500, 500)));
mw.show();
- QApplicationPrivate::setActiveWindow(&mw);
QVERIFY(QTest::qWaitForWindowActive(&mw));
// Ensure it is moved away first and then moved to the relevant section
QTest::mouseMove(mw.windowHandle(), view->mapTo(&mw, view->rect().bottomLeft() + QPoint(20, 20)));
diff --git a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp
index 36985c0de3..2820fd710b 100644
--- a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp
+++ b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp
@@ -113,7 +113,6 @@ void tst_QAction::actionEvent()
// add action
MyWidget testWidget(this);
testWidget.show();
- QApplicationPrivate::setActiveWindow(&testWidget);
testWidget.addAction(&a);
qApp->processEvents();
@@ -273,7 +272,6 @@ void tst_QAction::repeat()
MyWidget testWidget(this);
testWidget.show();
- QApplicationPrivate::setActiveWindow(&testWidget);
QVERIFY(QTest::qWaitForWindowActive(&testWidget));
QAction act(&testWidget);
@@ -352,7 +350,6 @@ void tst_QAction::disableShortcutsWithBlockedWidgets()
dialog.show();
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QSignalSpy spy(&action, &QAction::triggered);
diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
index b71a7a0a31..2eb2d84504 100644
--- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
+++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
@@ -23,6 +23,7 @@
#include <QtGui/QFontDatabase>
#include <QtGui/QClipboard>
+#include <QtGui/QStyleHints>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>
@@ -119,6 +120,7 @@ private slots:
void style();
void applicationPalettePolish();
+ void setColorScheme();
void allWidgets();
void topLevelWidgets();
@@ -311,10 +313,8 @@ void tst_QApplication::alert()
QApplication::alert(&widget, -1);
QApplication::alert(&widget, 250);
widget2.activateWindow();
- QApplicationPrivate::setActiveWindow(&widget2);
QApplication::alert(&widget, 0);
widget.activateWindow();
- QApplicationPrivate::setActiveWindow(&widget);
QApplication::alert(&widget, 200);
}
@@ -1624,7 +1624,6 @@ void tst_QApplication::focusWidget()
QTextEdit te;
te.show();
- QApplicationPrivate::setActiveWindow(&te);
QVERIFY(QTest::qWaitForWindowActive(&te));
const auto focusWidget = QApplication::focusWidget();
@@ -1640,7 +1639,6 @@ void tst_QApplication::focusWidget()
QTextEdit te(&w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
const auto focusWidget = QApplication::focusWidget();
@@ -2055,6 +2053,122 @@ void tst_QApplication::applicationPalettePolish()
}
}
+void tst_QApplication::setColorScheme()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0);
+
+ if (QStringList{"minimal", "offscreen", "wayland", "xcb", "wasm", "webassembly"}
+ .contains(QGuiApplication::platformName(), Qt::CaseInsensitive)) {
+ QSKIP("Setting the colorScheme is not implemented on this platform.");
+ }
+ qDebug() << "Testing setColorScheme on platform" << QGuiApplication::platformName();
+
+ if (QByteArrayView(app.style()->metaObject()->className()) == "QWindowsVistaStyle")
+ QSKIP("Setting the colorScheme is not supported with the Windows Vista style.");
+
+ const Qt::ColorScheme defaultColorScheme = QApplication::styleHints()->colorScheme();
+ // if we implement setColorScheme, then we must be able to read it
+ QVERIFY(defaultColorScheme != Qt::ColorScheme::Unknown);
+ const Qt::ColorScheme newColorScheme = defaultColorScheme == Qt::ColorScheme::Light
+ ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
+
+ class TopLevelWidget : public QWidget
+ {
+ QList<QEvent::Type> events;
+ public:
+ TopLevelWidget()
+ {
+ setObjectName("colorScheme TopLevelWidget");
+ }
+
+ void clearEvents()
+ {
+ events.clear();
+ }
+ qsizetype eventCount(QEvent::Type type) const
+ {
+ return events.count(type);
+ }
+ protected:
+ bool event(QEvent *event) override
+ {
+ switch (event->type()) {
+ case QEvent::ApplicationPaletteChange:
+ case QEvent::PaletteChange:
+ case QEvent::ThemeChange:
+ events << event->type();
+ break;
+ default:
+ break;
+ }
+
+ return QWidget::event(event);
+ }
+ } topLevelWidget;
+ topLevelWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevelWidget));
+
+ QSignalSpy colorSchemeChangedSpy(app.styleHints(), &QStyleHints::colorSchemeChanged);
+
+ // always start with a clean list
+ topLevelWidget.clearEvents();
+ const QPalette defaultPalette = topLevelWidget.palette();
+
+ bool oldPaletteWhenSchemeChanged = false;
+ connect(app.styleHints(), &QStyleHints::colorSchemeChanged, this,
+ [defaultPalette, &topLevelWidget, &oldPaletteWhenSchemeChanged]{
+ oldPaletteWhenSchemeChanged = defaultPalette == topLevelWidget.palette();
+ });
+
+ app.styleHints()->setColorScheme(newColorScheme);
+ QTRY_COMPARE(colorSchemeChangedSpy.count(), 1);
+ // We have not yet updated the palette when we emit the colorSchemeChanged
+ // signal, so the toplevel widget should still use the previous palette
+ QVERIFY(oldPaletteWhenSchemeChanged);
+ QCOMPARE(topLevelWidget.eventCount(QEvent::ThemeChange), 1);
+ // We can't guarantee that there is only one ApplicationPaletteChange,
+ // and they might arrive asynchronously in response to ThemeChange
+ QTRY_COMPARE_GE(topLevelWidget.eventCount(QEvent::ApplicationPaletteChange), 1);
+ // But we can guarantee a single PaletteChange event for the widget
+ QCOMPARE(topLevelWidget.eventCount(QEvent::PaletteChange), 1);
+ // The palette should have changed
+ QCOMPARE_NE(topLevelWidget.palette(), defaultPalette);
+
+ topLevelWidget.clearEvents();
+ colorSchemeChangedSpy.clear();
+
+ // verify that a widget shown with a color scheme override in place respect that
+ QWidget newWidget;
+ newWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&newWidget));
+ QCOMPARE(newWidget.palette(), topLevelWidget.palette());
+
+ // Setting to Unknown should follow the system preference again
+ app.styleHints()->setColorScheme(Qt::ColorScheme::Unknown);
+ QTRY_COMPARE(colorSchemeChangedSpy.count(), 1);
+ QCOMPARE(app.styleHints()->colorScheme(), defaultColorScheme);
+ QTRY_COMPARE(topLevelWidget.eventCount(QEvent::PaletteChange), 1);
+
+ auto debugPalette = qScopeGuard([defaultPalette, &topLevelWidget]{
+ qDebug() << "Inspecting palettes for differences";
+ const QPalette palette = topLevelWidget.palette();
+ for (int g = 0; g < QPalette::NColorGroups; ++g) {
+ for (int r = 0; r < QPalette::NColorRoles; ++r) {
+ const auto group = static_cast<QPalette::ColorGroup>(g);
+ const auto role = static_cast<QPalette::ColorRole>(r);
+ qDebug() << "...Checking" << group << role;
+ const auto actualBrush = palette.brush(group, role);
+ const auto expectedBrush = defaultPalette.brush(group, role);
+ if (palette.brush(group, role) != defaultPalette.brush(group, role))
+ qWarning() << "...Difference in" << group << role << actualBrush << expectedBrush;
+ }
+ }
+ });
+ QCOMPARE(topLevelWidget.palette(), defaultPalette);
+ debugPalette.dismiss();
+}
+
void tst_QApplication::allWidgets()
{
int argc = 1;
diff --git a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
index 7468dfa9a6..d34df43b01 100644
--- a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
+++ b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
@@ -1064,7 +1064,6 @@ void tst_QShortcut::context()
// Focus on 'other1' edit, so Active Window context should trigger
other1->activateWindow(); // <---
- QApplicationPrivate::setActiveWindow(other1);
QCOMPARE(QApplication::activeWindow(), other1->window());
QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1));
@@ -1156,7 +1155,6 @@ void tst_QShortcut::duplicatedShortcutOverride()
w.resize(200, 200);
w.move(QGuiApplication::primaryScreen()->availableGeometry().center() - QPoint(100, 100));
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTest::keyPress(w.windowHandle(), Qt::Key_A);
QCoreApplication::processEvents();
diff --git a/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp b/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
index ca002a1375..c73b9725b2 100644
--- a/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
+++ b/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
@@ -289,7 +289,6 @@ void tst_QStackedLayout::keepFocusAfterSetCurrent()
stackLayout->setCurrentIndex(0);
testWidget->show();
- QApplicationPrivate::setActiveWindow(testWidget);
QVERIFY(QTest::qWaitForWindowActive(testWidget));
edit1->setFocus();
diff --git a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
index c3b53addcc..bc0624c9ab 100644
--- a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
+++ b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
@@ -98,7 +98,6 @@ void tst_QToolTip::keyEvent()
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction())
+ QLatin1Char(' ') + QLatin1String(QTest::currentDataTag()));
widget.show();
- QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
widget.showDelayedToolTip(100);
@@ -193,7 +192,6 @@ void tst_QToolTip::qtbug64550_stylesheet()
Widget widget;
widget.setStyleSheet(QStringLiteral("* { font-size: 48pt; }\n"));
widget.show();
- QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
widget.showDelayedToolTip(100);
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index 40d8064562..c741a6717d 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -319,6 +319,7 @@ private slots:
void renderTargetOffset();
void renderInvisible();
void renderWithPainter();
+ void renderRTL();
void render_task188133();
void render_task211796();
void render_task217815();
@@ -476,6 +477,10 @@ private slots:
void reparentWindowHandles_data();
void reparentWindowHandles();
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuTrigger();
+#endif
+
private:
const QString m_platform;
QSize m_testWidgetSize;
@@ -2017,6 +2022,7 @@ static QList<QWidget *> getFocusChain(QWidget *start, bool bForward)
void tst_QWidget::focusAbstraction()
{
+ QLoggingCategory::setFilterRules("qt.widgets.focus=true");
QWidget *widget1 = new QWidget;
widget1->setObjectName("Widget 1");
QWidget *widget2 = new QWidget;
@@ -2417,6 +2423,13 @@ void tst_QWidget::tabOrderWithProxy()
QVERIFY(firstEdit->hasFocus());
}
+static QString focusWidgetName()
+{
+ return QApplication::focusWidget() != nullptr
+ ? QApplication::focusWidget()->objectName()
+ : QStringLiteral("No focus widget");
+}
+
void tst_QWidget::tabOrderWithProxyDisabled()
{
Container container;
@@ -2448,23 +2461,23 @@ void tst_QWidget::tabOrderWithProxyDisabled()
QSKIP("Window failed to activate, skipping test");
QVERIFY2(lineEdit1.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.tab();
QVERIFY2(!lineEdit2.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
QVERIFY2(lineEdit3.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.tab();
QVERIFY2(lineEdit1.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.backTab();
QVERIFY2(lineEdit3.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.backTab();
QVERIFY2(!lineEdit2.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
QVERIFY2(lineEdit1.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
}
//#define DEBUG_FOCUS_CHAIN
@@ -2776,23 +2789,23 @@ void tst_QWidget::tabOrderWithCompoundWidgetsNoFocusPolicy()
QSKIP("Window failed to activate, skipping test");
QVERIFY2(spinbox1.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.tab();
QVERIFY2(!spinbox2.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
QVERIFY2(spinbox3.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.tab();
QVERIFY2(spinbox1.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.backTab();
QVERIFY2(spinbox3.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
container.backTab();
QVERIFY2(!spinbox2.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
QVERIFY2(spinbox1.hasFocus(),
- qPrintable(QApplication::focusWidget()->objectName()));
+ qPrintable(focusWidgetName()));
}
void tst_QWidget::tabOrderNoChange()
@@ -7667,7 +7680,6 @@ void tst_QWidget::clean_qt_x11_enforce_cursor()
child->setAttribute(Qt::WA_SetCursor, true);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QTest::qWait(100);
QCursor::setPos(window.geometry().center());
@@ -8467,6 +8479,47 @@ void tst_QWidget::renderWithPainter()
QCOMPARE(painter.renderHints(), oldRenderHints);
}
+void tst_QWidget::renderRTL()
+{
+ QFont f;
+ f.setStyleStrategy(QFont::NoAntialias);
+ const QScopedPointer<QStyle> style(QStyleFactory::create(QLatin1String("Windows")));
+
+ QMenu menu;
+ menu.setMinimumWidth(200);
+ menu.setFont(f);
+ menu.setStyle(style.data());
+ menu.addAction("I");
+ menu.show();
+ menu.setLayoutDirection(Qt::LeftToRight);
+ QVERIFY(QTest::qWaitForWindowExposed(&menu));
+
+ QImage imageLTR(menu.size(), QImage::Format_ARGB32);
+ menu.render(&imageLTR);
+ //imageLTR.save("/tmp/rendered_1.png");
+
+ menu.setLayoutDirection(Qt::RightToLeft);
+ QImage imageRTL(menu.size(), QImage::Format_ARGB32);
+ menu.render(&imageRTL);
+ imageRTL = imageRTL.mirrored(true, false);
+ //imageRTL.save("/tmp/rendered_2.png");
+
+ QCOMPARE(imageLTR.height(), imageRTL.height());
+ QCOMPARE(imageLTR.width(), imageRTL.width());
+ static constexpr auto border = 4;
+ for (int h = border; h < imageRTL.height() - border; ++h) {
+ // there should be no difference on the right (aka no text)
+ for (int w = imageRTL.width() / 2; w < imageRTL.width() - border; ++w) {
+ auto pixLTR = imageLTR.pixel(w, h);
+ auto pixRTL = imageRTL.pixel(w, h);
+ if (pixLTR != pixRTL)
+ qDebug() << "Pixel do not match at" << w << h << ":"
+ << Qt::hex << pixLTR << "<->" << pixRTL;
+ QCOMPARE(pixLTR, pixRTL);
+ }
+ }
+}
+
void tst_QWidget::render_task188133()
{
QMainWindow mainWindow;
@@ -9821,7 +9874,6 @@ void tst_QWidget::dumpObjectTree()
}
QTestPrivate::androidCompatibleShow(&w);
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
{
@@ -10902,7 +10954,6 @@ void tst_QWidget::enterLeaveOnWindowShowHide()
if (!QTest::qWaitFor([&]{ return widget.geometry().contains(QCursor::pos()); }))
QSKIP("We can't move the cursor");
widget.show();
- QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
++expectedEnter;
@@ -11102,6 +11153,10 @@ void tst_QWidget::hoverPosition()
QVERIFY(QTest::qWaitForWindowExposed(&root));
const QPoint middle(50, 50);
+ // wait until we got the correct global pos
+ QPoint expectedGlobalPos = root.geometry().topLeft() + QPoint(100, 100) + middle;
+ if (!QTest::qWaitFor([&]{ return expectedGlobalPos == h.mapToGlobal(middle); }))
+ QSKIP("Can't move cursor");
QPoint curpos = h.mapToGlobal(middle);
QCursor::setPos(curpos);
if (!QTest::qWaitFor([curpos]{ return QCursor::pos() == curpos; }))
@@ -11722,7 +11777,6 @@ void tst_QWidget::imEnabledNotImplemented()
topLevel.show();
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
- QApplicationPrivate::setActiveWindow(&topLevel);
QVERIFY(QTest::qWaitForWindowActive(&topLevel));
// A plain widget should return false for ImEnabled
@@ -12103,7 +12157,6 @@ void tst_QWidget::grabMouse()
layout->addWidget(grabber);
centerOnScreen(&w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QStringList expectedLog;
@@ -12140,7 +12193,6 @@ void tst_QWidget::grabKeyboard()
layout->addWidget(nonGrabber);
centerOnScreen(&w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
nonGrabber->setFocus();
grabber->grabKeyboard();
@@ -13996,5 +14048,41 @@ void tst_QWidget::reparentWindowHandles()
}
}
+#ifndef QT_NO_CONTEXTMENU
+void tst_QWidget::contextMenuTrigger()
+{
+ class ContextMenuWidget : public QWidget
+ {
+ public:
+ int events = 0;
+
+ protected:
+ void contextMenuEvent(QContextMenuEvent *) override { ++events; }
+ };
+
+ const Qt::ContextMenuTrigger wasTrigger = QGuiApplication::styleHints()->contextMenuTrigger();
+ auto restoreTriggerGuard = qScopeGuard([wasTrigger]{
+ QGuiApplication::styleHints()->setContextMenuTrigger(wasTrigger);
+ });
+
+ ContextMenuWidget widget;
+ widget.show();
+ QVERIFY(!qApp->topLevelWindows().empty());
+ auto *window = qApp->topLevelWindows()[0];
+ QVERIFY(window);
+ QCOMPARE(widget.events, 0);
+ QGuiApplication::styleHints()->setContextMenuTrigger(Qt::ContextMenuTrigger::Press);
+ QTest::mousePress(window, Qt::RightButton);
+ QCOMPARE(widget.events, 1);
+ QTest::mouseRelease(window, Qt::RightButton);
+ QCOMPARE(widget.events, 1);
+ QGuiApplication::styleHints()->setContextMenuTrigger(Qt::ContextMenuTrigger::Release);
+ QTest::mousePress(window, Qt::RightButton);
+ QCOMPARE(widget.events, 1);
+ QTest::mouseRelease(window, Qt::RightButton);
+ QCOMPARE(widget.events, 2);
+}
+#endif
+
QTEST_MAIN(tst_QWidget)
#include "tst_qwidget.moc"
diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
index 8e8cec6d4f..e771737ae0 100644
--- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
+++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
@@ -691,7 +691,6 @@ void tst_QWidget_window::tst_dnd()
dndTestWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&dndTestWidget));
- QApplicationPrivate::setActiveWindow(&dndTestWidget);
QVERIFY(QTest::qWaitForWindowActive(&dndTestWidget));
QMimeData mimeData;
diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
index e620c5e79a..52aaf094b4 100644
--- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
+++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
@@ -7,6 +7,7 @@
#include <qapplication.h>
#include <qwindow.h>
#include <qwidget.h>
+#include <qlineedit.h>
#include <qdockwidget.h>
#include <qmainwindow.h>
@@ -60,6 +61,7 @@ private slots:
void testNativeContainerParent();
void testPlatformSurfaceEvent();
void embedWidgetWindow();
+ void testFocus();
void cleanup();
private:
@@ -468,6 +470,66 @@ void tst_QWindowContainer::embedWidgetWindow()
}
+void tst_QWindowContainer::testFocus()
+{
+ QWidget root;
+ root.setGeometry(m_availableGeometry);
+
+ QLineEdit *lineEdit = new QLineEdit(&root);
+ lineEdit->setGeometry(0, 0, m_availableGeometry.width() * 0.1, 17);
+ lineEdit->setFocusPolicy(Qt::FocusPolicy::StrongFocus);
+
+ QWindow *embedded = new QWindow();
+ QWidget *container = QWidget::createWindowContainer(embedded, &root);
+ container->setGeometry(0, lineEdit->height() + 10, m_availableGeometry.width() * 0.2, m_availableGeometry.height() - (lineEdit->height() + 10));
+ container->setFocusPolicy(Qt::StrongFocus);
+
+ root.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&root));
+ lineEdit->setFocus();
+ QTRY_VERIFY(lineEdit->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), root.windowHandle());
+ QCOMPARE(QApplication::focusWidget(), lineEdit);
+
+ // embedded window gets focused because of mouse click
+ QPoint embeddedCenter = container->rect().center();
+ QTest::mousePress(root.windowHandle(), Qt::LeftButton, {}, embeddedCenter);
+ QVERIFY(QTest::qWaitForWindowFocused(embedded));
+ QVERIFY(container->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), embedded);
+ QCOMPARE(QApplication::focusWidget(), container);
+ QVERIFY(!lineEdit->hasFocus());
+
+ QTest::mouseClick(lineEdit, Qt::LeftButton, {});
+ QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle()));
+ QCOMPARE(QGuiApplication::focusWindow(), root.windowHandle());
+ QCOMPARE(QApplication::focusWidget(), lineEdit);
+ QVERIFY(lineEdit->hasFocus());
+
+ // embedded window gets focused because of Tab key event
+ QTest::keyClick(root.windowHandle(), Qt::Key_Tab);
+ QVERIFY(QTest::qWaitForWindowFocused(embedded));
+ QVERIFY(container->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), embedded);
+ QCOMPARE(QApplication::focusWidget(), container);
+ QVERIFY(!lineEdit->hasFocus());
+ // A key tab event sent to the root window should cause
+ // the nextInFocusChain of the window container to get focused
+ QTest::keyClick(root.windowHandle(), Qt::Key_Tab);
+ QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle()));
+ QCOMPARE(QGuiApplication::focusWindow(), root.windowHandle());
+ QCOMPARE(QApplication::focusWidget(), lineEdit);
+ QVERIFY(lineEdit->hasFocus());
+
+ // embedded window gets focused programmatically
+ embedded->requestActivate();
+ QVERIFY(QTest::qWaitForWindowFocused(embedded));
+ QVERIFY(container->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), embedded);
+ QCOMPARE(QApplication::focusWidget(), container);
+ QVERIFY(!lineEdit->hasFocus());
+}
+
QTEST_MAIN(tst_QWindowContainer)
#include "tst_qwindowcontainer.moc"
diff --git a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
index aba5d906d1..a9a1817b8a 100644
--- a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
+++ b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
@@ -980,7 +980,6 @@ void tst_QStyleSheetStyle::focusColors()
centerOnScreen(&frame);
frame.show();
- QApplicationPrivate::setActiveWindow(&frame);
QVERIFY(QTest::qWaitForWindowActive(&frame));
for (QWidget *widget : frame.widgets()) {
@@ -1026,7 +1025,6 @@ void tst_QStyleSheetStyle::hoverColors()
QCursor::setPos(frame.geometry().topLeft() - QPoint(100, 0));
frame.show();
- QApplicationPrivate::setActiveWindow(&frame);
QVERIFY(QTest::qWaitForWindowActive(&frame));
QWindow *frameWindow = frame.windowHandle();
@@ -1720,7 +1718,6 @@ void tst_QStyleSheetStyle::toolTip()
centerOnScreen(&w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QColor normalToolTipBgColor = QToolTip::palette().color(QPalette::Inactive, QPalette::ToolTipBase);
@@ -1889,7 +1886,6 @@ void tst_QStyleSheetStyle::complexWidgetFocus()
centerOnScreen(&frame);
frame.show();
- QApplicationPrivate::setActiveWindow(&frame);
QVERIFY(QTest::qWaitForWindowActive(&frame));
for (QWidget *widget : widgets) {
widget->setFocus();
@@ -1978,7 +1974,6 @@ void tst_QStyleSheetStyle::task232085_spinBoxLineEditBg()
centerOnScreen(&frame);
frame.show();
- QApplicationPrivate::setActiveWindow(&frame);
spinbox->setFocus();
QVERIFY(QTest::qWaitForWindowActive(&frame));
@@ -2114,7 +2109,6 @@ void tst_QStyleSheetStyle::QTBUG36933_brokenPseudoClassLookup()
QVERIFY(QTest::qWaitForWindowExposed(&widget));
widget.activateWindow();
- QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
QHeaderView *verticalHeader = widget.verticalHeader();
diff --git a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp
index 8b151ec242..b2e77bc935 100644
--- a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp
+++ b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp
@@ -109,6 +109,8 @@ private slots:
void dynamicSortOrder();
void disabledItems();
+ void hideWidget();
+
// task-specific tests below me
void task178797_activatedOnReturn();
void task189564_omitNonSelectableItems();
@@ -1060,7 +1062,6 @@ void tst_QCompleter::multipleWidgets()
window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
window.move(200, 200);
window.show();
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QFocusEvent focusIn(QEvent::FocusIn);
@@ -1072,7 +1073,6 @@ void tst_QCompleter::multipleWidgets()
comboBox->setFocus();
comboBox->show();
window.activateWindow();
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(QApplication::focusWidget(), comboBox);
comboBox->lineEdit()->setText("it");
@@ -1107,7 +1107,6 @@ void tst_QCompleter::focusIn()
window.move(200, 200);
window.show();
window.activateWindow();
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
auto comboBox = new QComboBox(&window);
@@ -1185,6 +1184,32 @@ void tst_QCompleter::disabledItems()
QVERIFY(!view->isVisible());
}
+void tst_QCompleter::hideWidget()
+{
+ // hiding the widget should hide/close the popup
+ QWidget w;
+ w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ w.setLayout(new QVBoxLayout);
+
+ QLineEdit edit;
+ edit.setCompleter(new QCompleter({ "foo", "bar" }));
+
+ w.layout()->addWidget(&edit);
+
+ const auto pos = w.screen()->availableGeometry().topLeft() + QPoint(200, 200);
+ w.move(pos);
+ w.show();
+ QApplicationPrivate::setActiveWindow(&w);
+ QVERIFY(QTest::qWaitForWindowActive(&w));
+
+ // activate the completer
+ QTest::keyClick(&edit, Qt::Key_F);
+ QVERIFY(edit.completer()->popup());
+ QTRY_VERIFY(edit.completer()->popup()->isVisible());
+ edit.hide();
+ QVERIFY(!edit.completer()->popup()->isVisible());
+}
+
void tst_QCompleter::task178797_activatedOnReturn()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
@@ -1198,7 +1223,6 @@ void tst_QCompleter::task178797_activatedOnReturn()
QCOMPARE(spy.size(), 0);
ledit.move(200, 200);
ledit.show();
- QApplicationPrivate::setActiveWindow(&ledit);
QVERIFY(QTest::qWaitForWindowActive(&ledit));
QTest::keyClick(&ledit, Qt::Key_F);
QCoreApplication::processEvents();
@@ -1282,7 +1306,6 @@ void tst_QCompleter::task246056_setCompletionPrefix()
comboBox.addItem("a2");
comboBox.move(200, 200);
comboBox.show();
- QApplicationPrivate::setActiveWindow(&comboBox);
QVERIFY(QTest::qWaitForWindowActive(&comboBox));
QSignalSpy spy(comboBox.completer(), QOverload<const QModelIndex &>::of(&QCompleter::activated));
QTest::keyPress(&comboBox, 'a');
@@ -1348,7 +1371,6 @@ void tst_QCompleter::task250064_lostFocus()
task250064_Widget widget;
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
widget.show();
- QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
QTest::keyPress(widget.textEdit(), 'a');
Qt::FocusPolicy origPolicy = widget.textEdit()->focusPolicy();
@@ -1393,7 +1415,6 @@ void tst_QCompleter::task253125_lineEditCompletion()
edit.move(200, 200);
edit.show();
edit.setFocus();
- QApplicationPrivate::setActiveWindow(&edit);
QVERIFY(QTest::qWaitForWindowActive(&edit));
QTest::keyClick(&edit, 'i');
@@ -1556,7 +1577,6 @@ void tst_QCompleter::task247560_keyboardNavigation()
edit.move(200, 200);
edit.show();
edit.setFocus();
- QApplicationPrivate::setActiveWindow(&edit);
QVERIFY(QTest::qWaitForWindowActive(&edit));
QTest::keyClick(&edit, 'r');
@@ -1670,7 +1690,6 @@ void tst_QCompleter::QTBUG_14292_filesystem()
edit.move(200, 200);
edit.show();
- QApplicationPrivate::setActiveWindow(&edit);
QVERIFY(QTest::qWaitForWindowActive(&edit));
QCOMPARE(QApplication::activeWindow(), &edit);
edit.setFocus();
@@ -1715,7 +1734,6 @@ void tst_QCompleter::QTBUG_14292_filesystem()
QWidget w;
w.move(400, 200);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QVERIFY(!edit.hasFocus() && !comp.popup()->hasFocus());
@@ -1796,7 +1814,6 @@ void tst_QCompleter::QTBUG_51889_activatedSentTwice()
const auto pos = w.screen()->availableGeometry().topLeft() + QPoint(200,200);
w.move(pos);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QSignalSpy activatedSpy(&cbox, &QComboBox::activated);
diff --git a/tests/auto/widgets/util/qscroller/tst_qscroller.cpp b/tests/auto/widgets/util/qscroller/tst_qscroller.cpp
index a328b0c8d7..101b502fc6 100644
--- a/tests/auto/widgets/util/qscroller/tst_qscroller.cpp
+++ b/tests/auto/widgets/util/qscroller/tst_qscroller.cpp
@@ -324,7 +324,6 @@ void tst_QScroller::scrollTo()
{
QScopedPointer<tst_QScrollerWidget> sw(new tst_QScrollerWidget);
sw->show();
- QApplicationPrivate::setActiveWindow(sw.data());
if (!QTest::qWaitForWindowExposed(sw.data()) || !QTest::qWaitForWindowActive(sw.data()))
QSKIP("Failed to show and activate window");
@@ -356,7 +355,6 @@ void tst_QScroller::scroll()
QScroller::grabGesture(sw.data(), QScroller::TouchGesture);
sw->setGeometry(100, 100, 400, 300);
sw->show();
- QApplicationPrivate::setActiveWindow(sw.data());
if (!QTest::qWaitForWindowExposed(sw.data()) || !QTest::qWaitForWindowActive(sw.data()))
QSKIP("Failed to show and activate window");
@@ -397,7 +395,6 @@ void tst_QScroller::overshoot()
QScroller::grabGesture(sw.data(), QScroller::TouchGesture);
sw->setGeometry(100, 100, 400, 300);
sw->show();
- QApplicationPrivate::setActiveWindow(sw.data());
if (!QTest::qWaitForWindowExposed(sw.data()) || !QTest::qWaitForWindowActive(sw.data()))
QSKIP("Failed to show and activate window");
@@ -537,7 +534,6 @@ void tst_QScroller::mouseEventTimestamp()
QScroller::grabGesture(sw.data(), QScroller::LeftMouseButtonGesture);
sw->setGeometry(100, 100, 400, 300);
sw->show();
- QApplicationPrivate::setActiveWindow(sw.data());
if (!QTest::qWaitForWindowExposed(sw.data()) || !QTest::qWaitForWindowActive(sw.data()))
QSKIP("Failed to show and activate window");
diff --git a/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp b/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
index dc5c42513c..cb91f0c6e6 100644
--- a/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
+++ b/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
@@ -480,7 +480,6 @@ void tst_QAbstractButton::setShortcut()
QKeySequence seq( Qt::Key_A );
testWidget->setShortcut( seq );
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->activateWindow();
// must be active to get shortcuts
QVERIFY(QTest::qWaitForWindowActive(testWidget));
diff --git a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
index 06d2435601..3ff748ef27 100644
--- a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
+++ b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
@@ -122,7 +122,6 @@ void tst_QButtonGroup::arrowKeyNavigation()
layout.addWidget(&g2);
dlg.show();
- QApplicationPrivate::setActiveWindow(&dlg);
QVERIFY(QTest::qWaitForWindowActive(&dlg));
bt1.setFocus();
@@ -204,7 +203,6 @@ void tst_QButtonGroup::keyNavigationPushButtons()
buttonGroup->addButton(pb3);
dlg.show();
- QApplicationPrivate::setActiveWindow(&dlg);
if (!QTest::qWaitForWindowActive(&dlg))
QSKIP("Window activation failed, skipping test");
@@ -435,7 +433,6 @@ void tst_QButtonGroup::task106609()
qRegisterMetaType<QAbstractButton*>("QAbstractButton*");
QSignalSpy spy1(buttons, SIGNAL(buttonClicked(QAbstractButton*)));
- QApplicationPrivate::setActiveWindow(&dlg);
QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&dlg));
radio1->setFocus();
diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
index dc6ef789d7..66c1359bd8 100644
--- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
+++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
@@ -849,7 +849,6 @@ void tst_QComboBox::autoCompletionCaseSensitivity()
TestWidget topLevel;
topLevel.show();
QComboBox *testWidget = topLevel.comboBox();
- QApplicationPrivate::setActiveWindow(&topLevel);
testWidget->setFocus();
QVERIFY(QTest::qWaitForWindowActive(&topLevel));
QCOMPARE(qApp->focusWidget(), (QWidget *)testWidget);
@@ -2056,7 +2055,6 @@ void tst_QComboBox::flaggedItems()
comboBox.setView(&listWidget);
comboBox.move(200, 200);
comboBox.show();
- QApplicationPrivate::setActiveWindow(&comboBox);
comboBox.activateWindow();
comboBox.setFocus();
QVERIFY(QTest::qWaitForWindowActive(&comboBox));
@@ -2486,7 +2484,6 @@ void tst_QComboBox::task247863_keyBoardSelection()
combo.addItem( QLatin1String("111"));
combo.addItem( QLatin1String("222"));
combo.show();
- QApplicationPrivate::setActiveWindow(&combo);
QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&combo));
QSignalSpy spy(&combo, &QComboBox::activated);
@@ -2512,7 +2509,6 @@ void tst_QComboBox::task220195_keyBoardSelection2()
combo.addItem( QLatin1String("foo2"));
combo.addItem( QLatin1String("foo3"));
combo.show();
- QApplicationPrivate::setActiveWindow(&combo);
QVERIFY(QTest::qWaitForWindowActive(&combo));
combo.setCurrentIndex(-1);
@@ -2798,7 +2794,6 @@ void tst_QComboBox::keyBoardNavigationWithMouse()
combo.move(200, 200);
combo.showNormal();
- QApplicationPrivate::setActiveWindow(&combo);
QVERIFY(QTest::qWaitForWindowActive(&combo));
QCOMPARE(combo.currentText(), QLatin1String("0"));
@@ -2854,7 +2849,6 @@ void tst_QComboBox::task_QTBUG_1071_changingFocusEmitsActivated()
layout.addWidget(&edit);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
cb.clearEditText();
cb.setFocus();
@@ -3557,7 +3551,6 @@ void tst_QComboBox::task_QTBUG_52027_mapCompleterIndex()
QCOMPARE(spy.size(), 0);
cbox.move(200, 200);
cbox.show();
- QApplicationPrivate::setActiveWindow(&cbox);
QVERIFY(QTest::qWaitForWindowActive(&cbox));
QTest::keyClicks(&cbox, "foobar2");
@@ -3583,7 +3576,6 @@ void tst_QComboBox::task_QTBUG_52027_mapCompleterIndex()
cbox.activateWindow();
}
- QApplicationPrivate::setActiveWindow(&cbox);
QVERIFY(QTest::qWaitForWindowActive(&cbox));
QTest::keyClicks(&cbox, "foobar1");
@@ -3651,7 +3643,6 @@ void tst_QComboBox::checkEmbeddedLineEditWhenStyleSheetIsSet()
layout->addWidget(comboBox);
topLevel.show();
comboBox->setEditable(true);
- QApplicationPrivate::setActiveWindow(&topLevel);
QVERIFY(QTest::qWaitForWindowActive(&topLevel));
QImage grab = comboBox->grab().toImage();
diff --git a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp
index f5f22d05b9..2d9689db41 100644
--- a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp
+++ b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp
@@ -827,7 +827,6 @@ void tst_QDateTimeEdit::selectAndScrollWithKeys()
return;
#endif
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setDate(QDate(2004, 05, 11));
testWidget->setDisplayFormat("dd/MM/yyyy");
testWidget->show();
@@ -929,7 +928,6 @@ void tst_QDateTimeEdit::selectAndScrollWithKeys()
void tst_QDateTimeEdit::backspaceKey()
{
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setDate(QDate(2004, 05, 11));
testWidget->setDisplayFormat("d/MM/yyyy");
testWidget->show();
@@ -995,7 +993,6 @@ void tst_QDateTimeEdit::backspaceKey()
void tst_QDateTimeEdit::deleteKey()
{
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setDate(QDate(2004, 05, 11));
testWidget->setDisplayFormat("d/MM/yyyy");
#ifdef Q_OS_MAC
@@ -1014,7 +1011,6 @@ void tst_QDateTimeEdit::deleteKey()
void tst_QDateTimeEdit::tabKeyNavigation()
{
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setDate(QDate(2004, 05, 11));
testWidget->setDisplayFormat("dd/MM/yyyy");
testWidget->show();
@@ -1032,7 +1028,6 @@ void tst_QDateTimeEdit::tabKeyNavigation()
void tst_QDateTimeEdit::tabKeyNavigationWithPrefix()
{
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setDate(QDate(2004, 05, 11));
testWidget->setDisplayFormat("prefix dd/MM/yyyy");
@@ -1050,7 +1045,6 @@ void tst_QDateTimeEdit::tabKeyNavigationWithPrefix()
void tst_QDateTimeEdit::tabKeyNavigationWithSuffix()
{
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setDate(QDate(2004, 05, 11));
testWidget->setDisplayFormat("dd/MM/yyyy 'suffix'");
@@ -1066,7 +1060,6 @@ void tst_QDateTimeEdit::tabKeyNavigationWithSuffix()
void tst_QDateTimeEdit::enterKey()
{
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setDate(QDate(2004, 5, 11));
testWidget->setDisplayFormat("prefix d/MM/yyyy 'suffix'");
testWidget->lineEdit()->setFocus();
@@ -1354,7 +1347,6 @@ void tst_QDateTimeEdit::editingRanged()
});
edit->show();
- QApplicationPrivate::setActiveWindow(edit.get());
if (!QTest::qWaitForWindowActive(edit.get()))
QSKIP("Failed to make window active, aborting");
edit->setFocus();
diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp
index 63a432578e..af62d0d089 100644
--- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp
+++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp
@@ -716,6 +716,9 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged()
QCOMPARE(tabBar->currentIndex(), 0);
QCOMPARE(mw.tabifiedDockWidgets(dw2), {dw3});
+
+ mw.removeDockWidget(dw3);
+ QCOMPARE(mw.tabifiedDockWidgets(dw2).count(), 0);
}
Q_DECLARE_METATYPE(Qt::DockWidgetArea)
diff --git a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp
index 28752cd40d..999b5cac07 100644
--- a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp
+++ b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp
@@ -1154,7 +1154,6 @@ void tst_QDoubleSpinBox::taskQTBUG_5008_textFromValueAndValidate()
spinbox.show();
spinbox.activateWindow();
spinbox.setFocus();
- QApplicationPrivate::setActiveWindow(&spinbox);
QVERIFY(QTest::qWaitForWindowActive(&spinbox));
QCOMPARE(static_cast<QWidget *>(&spinbox), QApplication::activeWindow());
QTRY_VERIFY(spinbox.hasFocus());
diff --git a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
index 0d716cce97..b178707e7a 100644
--- a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
+++ b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
@@ -462,7 +462,6 @@ void tst_QGroupBox::propagateFocus()
QGroupBox box;
QLineEdit lineEdit(&box);
box.show();
- QApplicationPrivate::setActiveWindow(&box);
QVERIFY(QTest::qWaitForWindowActive(&box));
box.setFocus();
QTRY_COMPARE(qApp->focusWidget(), static_cast<QWidget*>(&lineEdit));
diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
index be185c1e7a..7a63c156f3 100644
--- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
+++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
@@ -3722,7 +3722,6 @@ void tst_QLineEdit::task174640_editingFinished()
layout->addWidget(le2);
mw.show();
- QApplicationPrivate::setActiveWindow(&mw);
mw.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&mw));
QCOMPARE(&mw, QApplication::activeWindow());
@@ -3830,7 +3829,6 @@ void tst_QLineEdit::task210502_caseInsensitiveInlineCompletion()
completer.setCompletionMode(QCompleter::InlineCompletion);
lineEdit.setCompleter(&completer);
lineEdit.show();
- QApplicationPrivate::setActiveWindow(&lineEdit);
QVERIFY(QTest::qWaitForWindowActive(&lineEdit));
lineEdit.setFocus();
QTRY_VERIFY(lineEdit.hasFocus());
@@ -3931,7 +3929,6 @@ void tst_QLineEdit::task241436_passwordEchoOnEditRestoreEchoMode()
testWidget->setFocus();
centerOnScreen(testWidget);
testWidget->show();
- QApplicationPrivate::setActiveWindow(testWidget);
QVERIFY(QTest::qWaitForWindowActive(testWidget));
QVERIFY(testWidget->hasFocus());
@@ -3982,7 +3979,6 @@ void tst_QLineEdit::taskQTBUG_4401_enterKeyClearsPassword()
testWidget->selectAll();
centerOnScreen(testWidget);
testWidget->show();
- QApplicationPrivate::setActiveWindow(testWidget);
QVERIFY(QTest::qWaitForWindowActive(testWidget));
QTest::keyPress(testWidget, Qt::Key_Enter);
@@ -4065,7 +4061,6 @@ void tst_QLineEdit::taskQTBUG_7395_readOnlyShortcut()
le.show();
QVERIFY(QTest::qWaitForWindowExposed(&le));
- QApplicationPrivate::setActiveWindow(&le);
QVERIFY(QTest::qWaitForWindowActive(&le));
le.setFocus();
QTRY_VERIFY(le.hasFocus());
@@ -4087,7 +4082,6 @@ void tst_QLineEdit::QTBUG697_paletteCurrentColorGroup()
le.setPalette(p);
le.show();
- QApplicationPrivate::setActiveWindow(&le);
QVERIFY(QTest::qWaitForWindowActive(&le));
le.setFocus();
QTRY_VERIFY(le.hasFocus());
@@ -4582,7 +4576,6 @@ void tst_QLineEdit::clearButton()
l->addWidget(listView);
testWidget.move(300, 300);
testWidget.show();
- QApplicationPrivate::setActiveWindow(&testWidget);
QVERIFY(QTest::qWaitForWindowActive(&testWidget));
// Flip the clear button on,off, trying to detect crashes.
filterLineEdit->setClearButtonEnabled(true);
diff --git a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp
index 0f652f2900..ef00dcaac0 100644
--- a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp
+++ b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp
@@ -515,7 +515,6 @@ void tst_QMdiArea::subWindowActivatedWithMinimize()
QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)));
connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*)) );
mw.show();
- QApplicationPrivate::setActiveWindow(&mw);
QWidget *widget = new QWidget(workspace);
widget->setAttribute(Qt::WA_DeleteOnClose);
QMdiSubWindow *window1 = workspace->addSubWindow(widget);
@@ -660,7 +659,6 @@ void tst_QMdiArea::changeWindowTitle()
#endif
mw->show();
- QApplicationPrivate::setActiveWindow(mw);
#ifdef USE_SHOW
mw->showFullScreen();
@@ -964,7 +962,6 @@ void tst_QMdiArea::activeSubWindow()
mainWindow.addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
mainWindow.show();
- QApplicationPrivate::setActiveWindow(&mainWindow);
QVERIFY(QTest::qWaitForWindowActive(&mainWindow));
QCOMPARE(mdiArea->activeSubWindow(), subWindow);
QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit);
@@ -987,10 +984,8 @@ void tst_QMdiArea::activeSubWindow()
dummyTopLevel.show();
QVERIFY(QTest::qWaitForWindowExposed(&dummyTopLevel));
- QApplicationPrivate::setActiveWindow(&dummyTopLevel);
QCOMPARE(mdiArea->activeSubWindow(), subWindow);
- QApplicationPrivate::setActiveWindow(&mainWindow);
QCOMPARE(mdiArea->activeSubWindow(), subWindow);
//task 202657
@@ -1023,7 +1018,6 @@ void tst_QMdiArea::currentSubWindow()
// Move focus to another top-level and check that we still
// have an active window.
- QApplicationPrivate::setActiveWindow(&dummyTopLevel);
QCOMPARE(qApp->activeWindow(), (QWidget *)&dummyTopLevel);
QVERIFY(mdiArea.activeSubWindow());
@@ -1045,11 +1039,9 @@ void tst_QMdiArea::currentSubWindow()
QCOMPARE(mdiArea.activeSubWindow(), active);
QCOMPARE(mdiArea.currentSubWindow(), active);
- QApplicationPrivate::setActiveWindow(&dummyTopLevel);
QVERIFY(mdiArea.activeSubWindow());
QCOMPARE(mdiArea.currentSubWindow(), active);
- QApplicationPrivate::setActiveWindow(&mdiArea);
active->show();
QCOMPARE(mdiArea.activeSubWindow(), active);
@@ -1255,7 +1247,6 @@ void tst_QMdiArea::closeWindows()
{
QMdiArea workspace;
workspace.show();
- QApplicationPrivate::setActiveWindow(&workspace);
// Close widget
QWidget *widget = new QWidget;
@@ -1307,7 +1298,6 @@ void tst_QMdiArea::activateNextAndPreviousWindow()
{
QMdiArea workspace;
workspace.show();
- QApplicationPrivate::setActiveWindow(&workspace);
const int windowCount = 10;
QMdiSubWindow *windows[windowCount];
@@ -1391,7 +1381,6 @@ void tst_QMdiArea::subWindowList()
QMdiArea workspace;
workspace.show();
- QApplicationPrivate::setActiveWindow(&workspace);
QVERIFY(QTest::qWaitForWindowActive(&workspace));
QList<QMdiSubWindow *> activationOrder;
@@ -1880,7 +1869,6 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation()
QMdiArea mdiArea;
mdiArea.show();
QVERIFY(QTest::qWaitForWindowExposed(&mdiArea));
- QApplicationPrivate::setActiveWindow(&mdiArea);
// Add one maximized window.
mdiArea.addSubWindow(new QWidget)->showMaximized();
@@ -2265,7 +2253,6 @@ void tst_QMdiArea::tabBetweenSubWindows()
mdiArea.show();
QVERIFY(QTest::qWaitForWindowExposed(&mdiArea));
- QApplicationPrivate::setActiveWindow(&mdiArea);
QWidget *focusWidget = subWindows.back()->widget();
QCOMPARE(qApp->focusWidget(), focusWidget);
diff --git a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp
index 38808d1702..60b675b18a 100644
--- a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp
+++ b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp
@@ -384,7 +384,6 @@ void tst_QMdiSubWindow::mainWindowSupport()
mainWindow.setCentralWidget(workspace);
mainWindow.show();
mainWindow.menuBar()->setVisible(true);
- QApplicationPrivate::setActiveWindow(&mainWindow);
bool nativeMenuBar = mainWindow.menuBar()->isNativeMenuBar();
// QMainWindow's window title is empty, so on a platform which does NOT have a native menubar,
@@ -510,7 +509,6 @@ void tst_QMdiSubWindow::emittingOfSignals()
workspace.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
workspace.show();
QCoreApplication::processEvents();
- QApplicationPrivate::setActiveWindow(&workspace);
QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
QCoreApplication::processEvents();
window->show();
@@ -1232,7 +1230,6 @@ void tst_QMdiSubWindow::restoreFocusOverCreation()
subWidget1->m_lineEdit2->setFocus();
subWindow1->show();
mdiArea.show();
- QApplicationPrivate::setActiveWindow(&mdiArea);
QVERIFY(QTest::qWaitForWindowActive(&mdiArea));
QCOMPARE(QApplication::focusWidget(), subWidget1->m_lineEdit2);
@@ -1956,7 +1953,6 @@ void tst_QMdiSubWindow::task_182852()
mainWindow.setCentralWidget(workspace);
mainWindow.show();
mainWindow.menuBar()->setVisible(true);
- QApplicationPrivate::setActiveWindow(&mainWindow);
if (mainWindow.menuBar()->isNativeMenuBar())
return; // The main window's title is not overwritten if we have a native menubar (macOS, Unity etc.)
diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
index 5602b8cd3f..57cc404fc7 100644
--- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
+++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
@@ -531,7 +531,6 @@ void tst_QMenu::overrideMenuAction()
m->addAction(aQuit);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
w.setFocus();
QVERIFY(QTest::qWaitForWindowActive(&w));
QVERIFY(w.hasFocus());
@@ -1613,7 +1612,6 @@ void tst_QMenu::transientParent()
QWindow *topLevel = window.windowHandle();
QVERIFY(topLevel);
- QApplicationPrivate::setActiveWindow(&window);
window.setFocus();
QVERIFY(QTest::qWaitForWindowActive(&window));
QVERIFY(window.hasFocus());
diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
index 8524b4212c..7c1fb97b97 100644
--- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
+++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
@@ -329,7 +329,6 @@ void tst_QMenuBar::accel()
QMainWindow w;
const TestMenu menu = initWindowWithSimpleMenuBar(w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
// shortcuts won't work unless the window is active
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_A, Qt::ControlModifier );
@@ -351,7 +350,6 @@ void tst_QMenuBar::activatedCount()
QFETCH( bool, forceNonNative );
initWindowWithSimpleMenuBar(w, forceNonNative);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_A, Qt::ControlModifier );
@@ -551,7 +549,6 @@ void tst_QMenuBar::check_accelKeys()
QMainWindow w;
initWindowWithComplexMenuBar(w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
// start with a bogus key that shouldn't trigger anything
@@ -630,7 +627,6 @@ void tst_QMenuBar::check_cursorKeys1()
QMainWindow w;
initWindowWithComplexMenuBar(w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
// start with a ALT + 1 that activates the first popupmenu
@@ -670,7 +666,6 @@ void tst_QMenuBar::check_cursorKeys2()
QMainWindow w;
initWindowWithComplexMenuBar(w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
// select popupmenu2
@@ -709,7 +704,6 @@ void tst_QMenuBar::check_cursorKeys3()
QMainWindow w;
initWindowWithComplexMenuBar(w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
// select Popupmenu 2
@@ -751,7 +745,6 @@ void tst_QMenuBar::taskQTBUG56860_focus()
w.setCentralWidget(e);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTRY_COMPARE(QApplication::focusWidget(), e);
@@ -794,7 +787,6 @@ void tst_QMenuBar::check_escKey()
const TestMenu menu = initWindowWithComplexMenuBar(w);
w.show();
w.setFocus();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QVERIFY( !menu.menus.at(0)->isActiveWindow() );
@@ -886,7 +878,6 @@ void tst_QMenuBar::check_altPress()
initWindowWithSimpleMenuBar(w);
w.show();
w.setFocus();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTest::keyClick( &w, Qt::Key_Alt );
@@ -916,7 +907,6 @@ void tst_QMenuBar::check_altClosePress()
w.show();
w.move(QGuiApplication::primaryScreen()->availableGeometry().center());
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTest::keyClick(&w, Qt::Key_F, Qt::AltModifier);
@@ -937,7 +927,6 @@ void tst_QMenuBar::check_shortcutPress()
const TestMenu menu = initWindowWithComplexMenuBar(w);
w.show();
w.setFocus();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QCOMPARE(m_complexTriggerCount[3], 0);
@@ -994,7 +983,6 @@ void tst_QMenuBar::check_menuPosition()
QAction *menu_action = w.menuBar()->addMenu(&menu);
centerOnScreen(&w);
w.show();
- QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
//the menu should be below the menubar item
@@ -1113,7 +1101,6 @@ void tst_QMenuBar::task256322_highlight()
centerOnScreen(&win);
win.show();
- QApplicationPrivate::setActiveWindow(&win);
QVERIFY(QTest::qWaitForWindowActive(&win));
const QPoint filePos = menuBarActionWindowPos(win.menuBar(), file);
@@ -1253,7 +1240,6 @@ void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions()
centerOnScreen(&menubar);
menubar.show();
- QApplicationPrivate::setActiveWindow(&menubar);
QVERIFY(QTest::qWaitForWindowActive(&menubar));
menubar.setActiveAction(m);
QCOMPARE(menubar.activeAction(), m);
@@ -1284,7 +1270,6 @@ void tst_QMenuBar::closeOnSecondClickAndOpenOnThirdClick() // QTBUG-32807, menu
QMenu *fileMenu = menuBar->addMenu(QStringLiteral("OpenCloseOpen"));
fileMenu->addAction(QStringLiteral("Quit"));
mainWindow.show();
- QApplicationPrivate::setActiveWindow(&mainWindow);
QVERIFY(QTest::qWaitForWindowActive(&mainWindow));
const QPoint center = menuBarActionWindowPos(mainWindow.menuBar(), fileMenu->menuAction());
@@ -1379,7 +1364,6 @@ void tst_QMenuBar::taskQTBUG53205_crashReparentNested()
mainWindow.resize(300, 200);
centerOnScreen(&mainWindow);
const TestMenu testMenus = initWindowWithComplexMenuBar(mainWindow);
- QApplicationPrivate::setActiveWindow(&mainWindow);
// they can't be windows
QWidget hiddenParent(&mainWindow, {});
@@ -1429,7 +1413,6 @@ void tst_QMenuBar::QTBUG_65488_hiddenActionTriggered()
// resize to action's size to make Action1 hidden
win.resize(actRect.width() - 10, win.size().height());
win.show();
- QApplicationPrivate::setActiveWindow(&win);
QVERIFY(QTest::qWaitForWindowExposed(&win));
// click center of the blank area on the menubar where Action1 resided
QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, win.menuBar()->geometry().center());
@@ -1501,7 +1484,6 @@ void tst_QMenuBar::QTBUG_25669_menubarActionDoubleTriggered()
QSignalSpy spy(win.menuBar(), &QMenuBar::triggered);
win.show();
- QApplicationPrivate::setActiveWindow(&win);
QVERIFY(QTest::qWaitForWindowExposed(&win));
QPoint posAct1 = menuBarActionWindowPos(win.menuBar(), act1);
@@ -1538,7 +1520,6 @@ void tst_QMenuBar::taskQTBUG46812_doNotLeaveMenubarHighlighted()
initWindowWithSimpleMenuBar(mainWindow);
mainWindow.show();
- QApplicationPrivate::setActiveWindow(&mainWindow);
QVERIFY(QTest::qWaitForWindowActive(&mainWindow));
QVERIFY(!mainWindow.menuBar()->hasFocus());
@@ -1650,7 +1631,6 @@ void tst_QMenuBar::taskQTBUG55966_subMenuRemoved()
delete subMenu;
window.show();
- QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QTest::qWait(500);
}
diff --git a/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp b/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
index 92ce1f5419..73360ae21d 100644
--- a/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
+++ b/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
@@ -339,7 +339,6 @@ void tst_QPushButton::setAccel()
// The shortcut will not be activated unless the button is in a active
// window and has focus
- QApplicationPrivate::setActiveWindow(testWidget);
testWidget->setFocus();
QVERIFY(QTest::qWaitForWindowActive(testWidget));
QTest::keyClick(testWidget, 'A', Qt::AltModifier);
diff --git a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp
index dfb0f71139..27343edcde 100644
--- a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp
+++ b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp
@@ -927,7 +927,6 @@ void tst_QSpinBox::editingFinished()
layout->addWidget(box2);
testFocusWidget.show();
- QApplicationPrivate::setActiveWindow(&testFocusWidget);
QVERIFY(QTest::qWaitForWindowActive(&testFocusWidget));
box->activateWindow();
box->setFocus();
@@ -1106,7 +1105,6 @@ void tst_QSpinBox::specialValue()
spin.setValue(50);
topWidget.show();
//make sure we have the focus (even if editingFinished fails)
- QApplicationPrivate::setActiveWindow(&topWidget);
topWidget.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&topWidget));
spin.setFocus();
@@ -1210,7 +1208,6 @@ void tst_QSpinBox::taskQTBUG_5008_textFromValueAndValidate()
spinbox.show();
spinbox.activateWindow();
spinbox.setFocus();
- QApplicationPrivate::setActiveWindow(&spinbox);
QVERIFY(QTest::qWaitForWindowActive(&spinbox));
QVERIFY(spinbox.hasFocus());
QTRY_COMPARE(static_cast<QWidget *>(&spinbox), QApplication::activeWindow());
diff --git a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
index 0a1b140867..3c28ad324a 100644
--- a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
+++ b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
@@ -159,7 +159,6 @@ void tst_QStackedWidget::dynamicPages()
le11->setFocus(); // set focus to second widget in the page
sw->resize(200, 200);
sw->show();
- QApplicationPrivate::setActiveWindow(sw);
QVERIFY(QTest::qWaitForWindowActive(sw));
QTRY_COMPARE(QApplication::focusWidget(), le11);
diff --git a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp
index 5d66f5922a..6dfab07fed 100644
--- a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp
+++ b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp
@@ -19,7 +19,6 @@ class TestBrowser : public QTextBrowser
public:
inline TestBrowser() {
show();
- QApplicationPrivate::setActiveWindow(this);
activateWindow();
setFocus();
QVERIFY(QTest::qWaitForWindowActive(this));
diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
index 0136e5b5de..ddf2bcfa85 100644
--- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
+++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
@@ -2545,7 +2545,6 @@ void tst_QTextEdit::inputMethodEvent()
// test that input method gets chance to commit preedit when removing focus
ed->setText("");
- QApplicationPrivate::setActiveWindow(ed);
QTRY_VERIFY(QApplication::focusWindow());
QCOMPARE(qApp->focusObject(), ed);
diff --git a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp
index 6336b792ed..8b8c74b1e7 100644
--- a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp
+++ b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp
@@ -1022,7 +1022,6 @@ void tst_QToolBar::accel()
QSignalSpy spy(action, SIGNAL(triggered(bool)));
mw.show();
- QApplicationPrivate::setActiveWindow(&mw);
QVERIFY(QTest::qWaitForWindowActive(&mw));
QTest::keyClick(&mw, Qt::Key_T, Qt::AltModifier);
diff --git a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp
index 20472861d9..b77a9c0eec 100644
--- a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp
+++ b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp
@@ -182,7 +182,6 @@ void tst_QToolButton::task176137_autoRepeatOfAction()
label->move(0, 50);
mainWidget.show();
- QApplicationPrivate::setActiveWindow(&mainWidget);
QVERIFY(QTest::qWaitForWindowActive(&mainWidget));
QSignalSpy spy(&action,SIGNAL(triggered()));
diff --git a/tests/baseline/shared/paintcommands.cpp b/tests/baseline/shared/paintcommands.cpp
index 20201b66b0..2cb3cd3bba 100644
--- a/tests/baseline/shared/paintcommands.cpp
+++ b/tests/baseline/shared/paintcommands.cpp
@@ -450,10 +450,12 @@ void PaintCommands::staticInit()
"^drawGlyphRun\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
"drawGlyphRun <x> <y> <text> - Will create glyph run using QTextLayout and draw this",
"drawGlyphRun 10 10 \"my text\"");
+#ifndef QT_NO_TEXTHTMLPARSER
DECL_PAINTCOMMAND("drawTextDocument", command_drawTextDocument,
"^drawTextDocument\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
"drawTextDocument <x> <y> <html>",
"drawTextDocument 10 10 \"html\"");
+#endif
DECL_PAINTCOMMAND("drawTiledPixmap", command_drawTiledPixmap,
"^drawTiledPixmap\\s+([\\w.:\\/]*)"
"\\s+(-?\\w*)\\s+(-?\\w*)\\s*(-?\\w*)\\s*(-?\\w*)"
@@ -1404,6 +1406,7 @@ void PaintCommands::command_drawGlyphRun(QRegularExpressionMatch re)
m_painter->drawGlyphRun(QPointF(x, y), glyphRun);
}
+#ifndef QT_NO_TEXTHTMLPARSER
void PaintCommands::command_drawTextDocument(QRegularExpressionMatch re)
{
if (!m_shouldDrawText)
@@ -1425,6 +1428,7 @@ void PaintCommands::command_drawTextDocument(QRegularExpressionMatch re)
doc.drawContents(m_painter);
m_painter->restore();
}
+#endif
/***************************************************************************************************/
void PaintCommands::command_fillRect(QRegularExpressionMatch re)
diff --git a/tests/baseline/shared/paintcommands.h b/tests/baseline/shared/paintcommands.h
index 45f78f9af6..de412e246e 100644
--- a/tests/baseline/shared/paintcommands.h
+++ b/tests/baseline/shared/paintcommands.h
@@ -179,7 +179,9 @@ private:
void command_drawText(QRegularExpressionMatch re);
void command_drawStaticText(QRegularExpressionMatch re);
void command_drawGlyphRun(QRegularExpressionMatch re);
+#ifndef QT_NO_TEXTHTMLPARSER
void command_drawTextDocument(QRegularExpressionMatch re);
+#endif
void command_drawTiledPixmap(QRegularExpressionMatch re);
void command_fillRect(QRegularExpressionMatch re);
void command_fillRectF(QRegularExpressionMatch re);
diff --git a/tests/benchmarks/corelib/CMakeLists.txt b/tests/benchmarks/corelib/CMakeLists.txt
index 855e7ee2fa..890cbcfc6b 100644
--- a/tests/benchmarks/corelib/CMakeLists.txt
+++ b/tests/benchmarks/corelib/CMakeLists.txt
@@ -4,7 +4,9 @@
add_subdirectory(io)
add_subdirectory(itemmodels)
add_subdirectory(json)
-add_subdirectory(mimetypes)
+if(QT_FEATURE_mimetype)
+ add_subdirectory(mimetypes)
+endif()
add_subdirectory(kernel)
add_subdirectory(text)
add_subdirectory(thread)
diff --git a/tests/benchmarks/corelib/itemmodels/CMakeLists.txt b/tests/benchmarks/corelib/itemmodels/CMakeLists.txt
index c74f36709c..cff884ebcc 100644
--- a/tests/benchmarks/corelib/itemmodels/CMakeLists.txt
+++ b/tests/benchmarks/corelib/itemmodels/CMakeLists.txt
@@ -1 +1,4 @@
-add_subdirectory(qsortfilterproxymodel)
+
+if(QT_FEATURE_proxymodel)
+ add_subdirectory(qsortfilterproxymodel)
+endif()
diff --git a/tests/benchmarks/corelib/thread/CMakeLists.txt b/tests/benchmarks/corelib/thread/CMakeLists.txt
index 48bf0572a6..fd7cbe6117 100644
--- a/tests/benchmarks/corelib/thread/CMakeLists.txt
+++ b/tests/benchmarks/corelib/thread/CMakeLists.txt
@@ -1,7 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-add_subdirectory(qfuture)
+if(QT_FEATURE_future)
+ add_subdirectory(qfuture)
+endif()
add_subdirectory(qmutex)
add_subdirectory(qreadwritelock)
add_subdirectory(qthreadstorage)
diff --git a/tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp b/tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp
index 581c300d36..7dde3bf426 100644
--- a/tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp
+++ b/tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp
@@ -4,6 +4,7 @@
#include <QDate>
#include <QTest>
#include <QList>
+using namespace Qt::StringLiterals;
class tst_QDate : public QObject
{
@@ -33,6 +34,9 @@ private Q_SLOTS:
void addDays();
void addMonths();
void addYears();
+
+ void fromString_data();
+ void fromString();
};
QList<QDate> tst_QDate::daily(qint64 start, qint64 end)
@@ -184,5 +188,28 @@ void tst_QDate::addYears()
Q_UNUSED(store);
}
+void tst_QDate::fromString_data()
+{
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<QString>("format");
+ QTest::addColumn<int>("baseYear");
+
+ QTest::newRow("yyyyMMdd") << u"20240412"_s << u"yyyyMMdd"_s << 2000;
+ QTest::newRow("yyyy-MM-dd") << u"2024-04-12"_s << u"yyyy-MM-dd"_s << 2000;
+ QTest::newRow("YYYYMMDD") << u"20240412"_s << u"YYYYMMDD"_s << 2000; // Invalid, QTBUG-124465.
+}
+
+void tst_QDate::fromString()
+{
+ QFETCH(const QString, string);
+ QFETCH(const QString, format);
+ QFETCH(const int, baseYear);
+ QDate date;
+ QBENCHMARK {
+ date = QDate::fromString(string, format, baseYear);
+ }
+ Q_UNUSED(date);
+}
+
QTEST_MAIN(tst_QDate)
#include "tst_bench_qdate.moc"
diff --git a/tests/benchmarks/gui/text/qtext/main.cpp b/tests/benchmarks/gui/text/qtext/main.cpp
index 121bc43573..9a2740253c 100644
--- a/tests/benchmarks/gui/text/qtext/main.cpp
+++ b/tests/benchmarks/gui/text/qtext/main.cpp
@@ -25,7 +25,9 @@ public:
private slots:
void loadHtml_data();
+#ifndef QT_NO_TEXTHTMLPARSER
void loadHtml();
+#endif
void shaping_data();
void shaping();
@@ -47,9 +49,11 @@ private slots:
void paintLayoutToPixmap();
void paintLayoutToPixmap_painterFill();
+#ifndef QT_NO_TEXTHTMLPARSER
void document();
void paintDocToPixmap();
void paintDocToPixmap_painterFill();
+#endif
private:
QSize setupTextLayout(QTextLayout *layout, bool wrap = true, int wrapWidth = 100);
@@ -76,6 +80,7 @@ void tst_QText::loadHtml_data()
+ parag;
}
+#ifndef QT_NO_TEXTHTMLPARSER
void tst_QText::loadHtml()
{
QFETCH(QString, source);
@@ -84,6 +89,7 @@ void tst_QText::loadHtml()
doc.setHtml(source);
}
}
+#endif
void tst_QText::shaping_data()
{
@@ -371,6 +377,7 @@ void tst_QText::paintLayoutToPixmap_painterFill()
}
}
+#ifndef QT_NO_TEXTHTMLPARSER
void tst_QText::document()
{
QTextDocument *doc = new QTextDocument;
@@ -413,6 +420,7 @@ void tst_QText::paintDocToPixmap_painterFill()
doc->drawContents(&p);
}
}
+#endif
QTEST_MAIN(tst_QText)
diff --git a/tests/benchmarks/network/access/CMakeLists.txt b/tests/benchmarks/network/access/CMakeLists.txt
index bc085cad61..bc5148af55 100644
--- a/tests/benchmarks/network/access/CMakeLists.txt
+++ b/tests/benchmarks/network/access/CMakeLists.txt
@@ -4,8 +4,10 @@
add_subdirectory(qfile_vs_qnetworkaccessmanager)
add_subdirectory(qhttpheaders)
add_subdirectory(qnetworkreply)
-add_subdirectory(qnetworkreply_from_cache)
-add_subdirectory(qnetworkdiskcache)
+if(QT_FEATURE_networkdiskcache)
+ add_subdirectory(qnetworkreply_from_cache)
+ add_subdirectory(qnetworkdiskcache)
+endif()
if(QT_FEATURE_private_tests)
add_subdirectory(qdecompresshelper)
endif()
diff --git a/tests/benchmarks/network/access/qdecompresshelper/main.cpp b/tests/benchmarks/network/access/qdecompresshelper/main.cpp
index 09c24af668..7f8b09ef0e 100644
--- a/tests/benchmarks/network/access/qdecompresshelper/main.cpp
+++ b/tests/benchmarks/network/access/qdecompresshelper/main.cpp
@@ -51,13 +51,14 @@ void tst_QDecompressHelper::decompress()
file.seek(0);
QDecompressHelper helper;
helper.setEncoding(encoding);
+ helper.setDecompressedSafetyCheckThreshold(-1);
QVERIFY(helper.isValid());
helper.feed(file.readAll());
qsizetype bytes = 0;
+ QByteArray out(64 * 1024, Qt::Uninitialized);
while (helper.hasData()) {
- QByteArray out(64 * 1024, Qt::Uninitialized);
qsizetype bytesRead = helper.read(out.data(), out.size());
bytes += bytesRead;
}
diff --git a/tests/benchmarks/network/socket/CMakeLists.txt b/tests/benchmarks/network/socket/CMakeLists.txt
index 034f618737..411a933dbb 100644
--- a/tests/benchmarks/network/socket/CMakeLists.txt
+++ b/tests/benchmarks/network/socket/CMakeLists.txt
@@ -1,6 +1,12 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-add_subdirectory(qlocalsocket)
+if(QT_FEATURE_localserver)
+ add_subdirectory(qlocalsocket)
+endif()
+
+if(QT_FEATURE_udpsocket)
+ add_subdirectory(qudpsocket)
+endif()
+
add_subdirectory(qtcpserver)
-add_subdirectory(qudpsocket)
diff --git a/tests/manual/dialogs/wizardpanel.cpp b/tests/manual/dialogs/wizardpanel.cpp
index 6fa7d1803a..5e413960e3 100644
--- a/tests/manual/dialogs/wizardpanel.cpp
+++ b/tests/manual/dialogs/wizardpanel.cpp
@@ -229,7 +229,7 @@ Wizard::Wizard(QWidget *parent, Qt::WindowFlags flags)
addPage(new WizardPage(tr("Page 3"), this));
}
-// A dialog using a Wizard as child widget (emulating Qt Designer).
+// A dialog using a Wizard as child widget (emulating Qt Widgets Designer).
class WizardEmbeddingDialog : public QDialog {
public:
explicit WizardEmbeddingDialog(QWidget *parent = nullptr);
diff --git a/tests/manual/examples/widgets/richtext/textedit/example.html b/tests/manual/examples/widgets/richtext/textedit/example.html
index ebae3362e9..038f71acfe 100644
--- a/tests/manual/examples/widgets/richtext/textedit/example.html
+++ b/tests/manual/examples/widgets/richtext/textedit/example.html
@@ -19,7 +19,7 @@ hr { height: 1px; border-width: 0; }
<ol style="-qt-list-indent: 1;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Introduction</li>
<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Tools </li></ol>
<ol type=a style="-qt-list-indent: 2;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Assistant</li>
-<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Designer</li>
+<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Widgets Designer</li>
<ol type=A style="-qt-list-indent: 3;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Form Editor</li>
<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Component Architecture</li></ol>
<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Linguist</li></ol>
@@ -64,7 +64,7 @@ hr { height: 1px; border-width: 0; }
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">13:00 - 15:00 </span></p></td>
<td>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Qt Designer</span> Tutorial </p></td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Qt Widgets Designer</span> Tutorial </p></td>
<td rowspan="2">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Extreme Programming </p></td>
<td>
diff --git a/tests/manual/examples/widgets/richtext/textedit/example.md b/tests/manual/examples/widgets/richtext/textedit/example.md
index 15f3c3cacf..8a5eed72f6 100644
--- a/tests/manual/examples/widgets/richtext/textedit/example.md
+++ b/tests/manual/examples/widgets/richtext/textedit/example.md
@@ -43,7 +43,7 @@ numerals in the same list structure:
1. Introduction
2. Qt Tools
1) Qt Assistant
- 2) Qt Designer
+ 2) Qt Widgets Designer
1. Form Editor
2. Component Architecture
3) Qt Linguist
@@ -78,7 +78,7 @@ column spans, text formatting within cells, and size constraints for columns.
| ------------: | ----------------- | ---------------------- | ------------------------- |
| 9:00 - 11:00 | Introduction to Qt |||
| 11:00 - 13:00 | Using qmake | Object-oriented Programming | Layouts in Qt |
-| 13:00 - 15:00 | Qt Designer Tutorial | Extreme Programming | Writing Custom Styles |
+| 13:00 - 15:00 | Qt Widgets Designer Tutorial | Extreme Programming | Writing Custom Styles |
| 15:00 - 17:00 | Qt Linguist and Internationalization | &nbsp; | &nbsp; |
*Try adding text to the cells in the table and experiment with the alignment of
diff --git a/tests/manual/qdnslookup/main.cpp b/tests/manual/qdnslookup/main.cpp
index aa80f4df78..41dda45b8f 100644
--- a/tests/manual/qdnslookup/main.cpp
+++ b/tests/manual/qdnslookup/main.cpp
@@ -11,6 +11,11 @@
#include <QtNetwork/QHostInfo>
#include <QtNetwork/QDnsLookup>
+#if QT_CONFIG(ssl)
+# include <QtNetwork/QSslCipher>
+# include <QtNetwork/QSslConfiguration>
+#endif
+
#include <stdlib.h>
#include <stdio.h>
@@ -32,6 +37,20 @@ static QDnsLookup::Type typeFromString(QString str)
return QDnsLookup::Type(value);
}
+template <typename Enum> QByteArray enumToString(Enum value)
+{
+ QMetaEnum me = QMetaEnum::fromType<Enum>();
+ QByteArray keys = me.valueToKeys(int(value));
+ if (keys.isEmpty())
+ return QByteArrayLiteral("<unknown>");
+
+ // return the last one
+ qsizetype idx = keys.lastIndexOf('|');
+ if (idx > 0)
+ return std::move(keys).sliced(idx + 1);
+ return keys;
+}
+
static int showHelp(const char *argv0, int exitcode)
{
// like dig
@@ -43,7 +62,7 @@ static auto parseServerAddress(QString server)
{
struct R {
QHostAddress address;
- int port = -1;
+ int port;
} r;
// let's use QUrl to help us
@@ -52,8 +71,15 @@ static auto parseServerAddress(QString server)
if (!url.isValid() || !url.userInfo().isNull())
return r; // failed
- r.port = url.port();
+ r.port = url.port(0);
r.address.setAddress(url.host());
+ if (r.address.isNull()) {
+ // try to resolve a hostname
+ QHostInfo hostinfo = QHostInfo::fromName(url.host());
+ const QList<QHostAddress> addresses = hostinfo.addresses();
+ if (!hostinfo.error() && !addresses.isEmpty())
+ r.address = addresses.at(0);
+ }
return r;
}
@@ -95,15 +121,26 @@ static void printAnswers(const QDnsLookup &lookup)
printf("%s ", qPrintable(QDebug::toString(data)));
puts("");
}
+
+ for (const QDnsTlsAssociationRecord &rr : lookup.tlsAssociationRecords()) {
+ printRecordCommon(rr, "TLSA");
+ printf("( %u %u %u ; %s %s %s\n\t%s )\n", quint8(rr.usage()), quint8(rr.selector()),
+ quint8(rr.matchType()), enumToString(rr.usage()).constData(),
+ enumToString(rr.selector()).constData(), enumToString(rr.matchType()).constData(),
+ rr.value().toHex().toUpper().constData());
+ }
}
static void printResults(const QDnsLookup &lookup, QElapsedTimer::Duration duration)
{
if (QDnsLookup::Error error = lookup.error())
- printf(";; status: %s (%s)\n", QMetaEnum::fromType<QDnsLookup::Error>().valueToKey(error),
+ printf(";; status: %s (%s)", QMetaEnum::fromType<QDnsLookup::Error>().valueToKey(error),
qPrintable(lookup.errorString()));
else
- printf(";; status: NoError\n");
+ printf(";; status: NoError");
+ if (lookup.isAuthenticData())
+ printf("; AuthenticData");
+ puts("");
QMetaEnum me = QMetaEnum::fromType<QDnsLookup::Type>();
printf(";; QUESTION:\n");
@@ -114,8 +151,21 @@ static void printResults(const QDnsLookup &lookup, QElapsedTimer::Duration durat
printAnswers(lookup);
printf("\n;; Query time: %lld ms\n", qint64(duration_cast<milliseconds>(duration).count()));
- if (QHostAddress server = lookup.nameserver(); !server.isNull())
- printf(";; SERVER: %s#%d\n", qPrintable(server.toString()), lookup.nameserverPort());
+ if (QHostAddress server = lookup.nameserver(); !server.isNull()) {
+ quint16 port = lookup.nameserverPort();
+ if (port == 0)
+ port = QDnsLookup::defaultPortForProtocol(lookup.nameserverProtocol());
+ printf(";; SERVER: %s#%d", qPrintable(server.toString()), port);
+#if QT_CONFIG(ssl)
+ if (lookup.nameserverProtocol() != QDnsLookup::Standard) {
+ if (QSslConfiguration conf = lookup.sslConfiguration(); !conf.isNull()) {
+ printf(" (%s %s)", enumToString(conf.sessionProtocol()).constData(),
+ qPrintable(conf.sessionCipher().name()));
+ }
+ }
+#endif
+ puts("");
+ }
}
int main(int argc, char *argv[])
@@ -123,6 +173,7 @@ int main(int argc, char *argv[])
QCoreApplication a(argc, argv);
QDnsLookup::Type type = {};
+ QDnsLookup::Protocol protocol = QDnsLookup::Standard;
QString domain, server;
const QStringList args = QCoreApplication::arguments().sliced(1);
for (const QString &arg : args) {
@@ -132,6 +183,14 @@ int main(int argc, char *argv[])
}
if (arg == u"-h")
return showHelp(argv[0], EXIT_SUCCESS);
+ if (arg == "+tls") {
+ protocol = QDnsLookup::DnsOverTls;
+ continue;
+ } else if (arg == "+notls") {
+ protocol = QDnsLookup::Standard;
+ continue;
+ }
+
if (domain.isNull()) {
domain = arg;
continue;
@@ -163,9 +222,7 @@ int main(int argc, char *argv[])
argv[0], qPrintable(server));
return EXIT_FAILURE;
}
- lookup.setNameserver(addr.address);
- if (addr.port > 0)
- lookup.setNameserverPort(addr.port);
+ lookup.setNameserver(protocol, addr.address, addr.port);
}
// execute the lookup
diff --git a/tests/manual/qopenglwidget/dockedopenglwidget/fshader.glsl b/tests/manual/qopenglwidget/dockedopenglwidget/fshader.glsl
index 8e5a4de8fc..ddc6247574 100644
--- a/tests/manual/qopenglwidget/dockedopenglwidget/fshader.glsl
+++ b/tests/manual/qopenglwidget/dockedopenglwidget/fshader.glsl
@@ -1,3 +1,5 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
uniform sampler2D texture;
varying vec2 v_texcoord;
diff --git a/tests/manual/qopenglwidget/dockedopenglwidget/vshader.glsl b/tests/manual/qopenglwidget/dockedopenglwidget/vshader.glsl
index 098eda946e..10f3646aa6 100644
--- a/tests/manual/qopenglwidget/dockedopenglwidget/vshader.glsl
+++ b/tests/manual/qopenglwidget/dockedopenglwidget/vshader.glsl
@@ -1,3 +1,5 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
uniform mat4 mvp_matrix;
attribute vec4 a_position;
diff --git a/tests/manual/rhi/computebuffer/buildshaders.bat b/tests/manual/rhi/computebuffer/buildshaders.bat
index 2768273b70..07a602e18b 100755
--- a/tests/manual/rhi/computebuffer/buildshaders.bat
+++ b/tests/manual/rhi/computebuffer/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "310 es,430" --hlsl 50 --msl 12 buffer.comp -o buffer.comp.qsb
qsb --glsl "310 es,430" --hlsl 50 --msl 12 main.vert -o main.vert.qsb
qsb --glsl "310 es,430" --hlsl 50 --msl 12 main.frag -o main.frag.qsb
diff --git a/tests/manual/rhi/computeimage/buildshaders.bat b/tests/manual/rhi/computeimage/buildshaders.bat
index 41a324d2b2..253d05b625 100755
--- a/tests/manual/rhi/computeimage/buildshaders.bat
+++ b/tests/manual/rhi/computeimage/buildshaders.bat
@@ -1 +1,3 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
qsb --glsl "310 es,430" --hlsl 50 --msl 12 image.comp -o image.comp.qsb
diff --git a/tests/manual/rhi/cubemap/buildshaders.bat b/tests/manual/rhi/cubemap/buildshaders.bat
index ebf673875d..314559490f 100644
--- a/tests/manual/rhi/cubemap/buildshaders.bat
+++ b/tests/manual/rhi/cubemap/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c cubemap.vert -o cubemap.vert.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c cubemap.frag -o cubemap.frag.qsb
diff --git a/tests/manual/rhi/cubemap_render/buildshaders.bat b/tests/manual/rhi/cubemap_render/buildshaders.bat
index 3886c138d8..4bee01d8cd 100644
--- a/tests/manual/rhi/cubemap_render/buildshaders.bat
+++ b/tests/manual/rhi/cubemap_render/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_oneface.vert -o cubemap_oneface.vert.qsb
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_oneface.frag -o cubemap_oneface.frag.qsb
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_mrt.vert -o cubemap_mrt.vert.qsb
diff --git a/tests/manual/rhi/displacement/buildshaders.bat b/tests/manual/rhi/displacement/buildshaders.bat
index 552277491d..95a51c0e91 100644
--- a/tests/manual/rhi/displacement/buildshaders.bat
+++ b/tests/manual/rhi/displacement/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl 320es,410 --hlsl 50 --msl 12 --msltess material.vert -o material.vert.qsb
qsb --glsl 320es,410 --hlsl 50 --msl 12 material.frag -o material.frag.qsb
diff --git a/tests/manual/rhi/float16texture_with_compute/buildshaders.bat b/tests/manual/rhi/float16texture_with_compute/buildshaders.bat
index d1ffecf49d..15f39256c7 100644
--- a/tests/manual/rhi/float16texture_with_compute/buildshaders.bat
+++ b/tests/manual/rhi/float16texture_with_compute/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "430,310 es" --hlsl 50 --msl 12 load.comp -o load.comp.qsb
qsb --glsl "430,310 es" --hlsl 50 --msl 12 prefilter.comp -o prefilter.comp.qsb
diff --git a/tests/manual/rhi/geometryshader/buildshaders.bat b/tests/manual/rhi/geometryshader/buildshaders.bat
index 6da26a6a2a..a3b7296e16 100755
--- a/tests/manual/rhi/geometryshader/buildshaders.bat
+++ b/tests/manual/rhi/geometryshader/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl 320es,410 --hlsl 50 test.vert -o test.vert.qsb
qsb --glsl 320es,410 test.geom -o test.geom.qsb
qsb -r hlsl,50,test_geom.hlsl test.geom.qsb
diff --git a/tests/manual/rhi/hdr/buildshaders.bat b/tests/manual/rhi/hdr/buildshaders.bat
index 7710c85f83..fdae5d0eb7 100644
--- a/tests/manual/rhi/hdr/buildshaders.bat
+++ b/tests/manual/rhi/hdr/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --qt6 hdrtexture.vert -o hdrtexture.vert.qsb
qsb --qt6 hdrtexture.frag -o hdrtexture.frag.qsb
diff --git a/tests/manual/rhi/instancing/buildshaders.bat b/tests/manual/rhi/instancing/buildshaders.bat
index 9053a1c54a..af18c09602 100644
--- a/tests/manual/rhi/instancing/buildshaders.bat
+++ b/tests/manual/rhi/instancing/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "330,300 es" --hlsl 50 --msl 12 inst.vert -o inst.vert.qsb
qsb --glsl "330,300 es" --hlsl 50 --msl 12 inst.frag -o inst.frag.qsb
diff --git a/tests/manual/rhi/mrt/buildshaders.bat b/tests/manual/rhi/mrt/buildshaders.bat
index 75741448b1..b23e01d00e 100644
--- a/tests/manual/rhi/mrt/buildshaders.bat
+++ b/tests/manual/rhi/mrt/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c mrt.vert -o mrt.vert.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c mrt.frag -o mrt.frag.qsb
diff --git a/tests/manual/rhi/multiview/buildshaders.bat b/tests/manual/rhi/multiview/buildshaders.bat
index c53119bd42..d9d2825218 100644
--- a/tests/manual/rhi/multiview/buildshaders.bat
+++ b/tests/manual/rhi/multiview/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --view-count 2 --glsl "300 es,330" --hlsl 61 -c --msl 12 multiview.vert -o multiview.vert.qsb
qsb --glsl "300 es,330" --hlsl 61 -c --msl 12 multiview.frag -o multiview.frag.qsb
qsb --glsl "300 es,330" --hlsl 61 -c --msl 12 texture.vert -o texture.vert.qsb
diff --git a/tests/manual/rhi/noninstanced/buildshaders.bat b/tests/manual/rhi/noninstanced/buildshaders.bat
index fc274eeec2..c1e0fb4722 100644
--- a/tests/manual/rhi/noninstanced/buildshaders.bat
+++ b/tests/manual/rhi/noninstanced/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 material.vert -o material.vert.qsb
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 material.frag -o material.frag.qsb
diff --git a/tests/manual/rhi/polygonmode/buildshaders.bat b/tests/manual/rhi/polygonmode/buildshaders.bat
index 3cd87ed7a2..d1c184109e 100755
--- a/tests/manual/rhi/polygonmode/buildshaders.bat
+++ b/tests/manual/rhi/polygonmode/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl 320es,410,120 test.vert --msl 12 --hlsl 50 -o test.vert.qsb
qsb --glsl 320es,410,120 test.frag --msl 12 --hlsl 50 -o test.frag.qsb
diff --git a/tests/manual/rhi/shadowmap/buildshaders.bat b/tests/manual/rhi/shadowmap/buildshaders.bat
index 7b84cc0952..3e514a90b9 100644
--- a/tests/manual/rhi/shadowmap/buildshaders.bat
+++ b/tests/manual/rhi/shadowmap/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "120,300 es" --hlsl 50 --msl 12 -c shadowmap.vert -o shadowmap.vert.qsb
qsb --glsl "120,300 es" --hlsl 50 --msl 12 -c shadowmap.frag -o shadowmap.frag.qsb
qsb --glsl "120,300 es" --hlsl 50 --msl 12 -c main.vert -o main.vert.qsb
diff --git a/tests/manual/rhi/shared/buildshaders.bat b/tests/manual/rhi/shared/buildshaders.bat
index 59cd69716e..faa253c8bc 100644
--- a/tests/manual/rhi/shared/buildshaders.bat
+++ b/tests/manual/rhi/shared/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c color.vert -o color.vert.qsb
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c color.frag -o color.frag.qsb
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c texture.vert -o texture.vert.qsb
diff --git a/tests/manual/rhi/shared/imgui/buildshaders.bat b/tests/manual/rhi/shared/imgui/buildshaders.bat
index eec4e3a070..560c634134 100644
--- a/tests/manual/rhi/shared/imgui/buildshaders.bat
+++ b/tests/manual/rhi/shared/imgui/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c imgui.vert -o imgui.vert.qsb
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c imgui.frag -o imgui.frag.qsb
diff --git a/tests/manual/rhi/stenciloutline/buildshaders.bat b/tests/manual/rhi/stenciloutline/buildshaders.bat
index fc274eeec2..c1e0fb4722 100644
--- a/tests/manual/rhi/stenciloutline/buildshaders.bat
+++ b/tests/manual/rhi/stenciloutline/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 material.vert -o material.vert.qsb
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 material.frag -o material.frag.qsb
diff --git a/tests/manual/rhi/tessellation/buildshaders.bat b/tests/manual/rhi/tessellation/buildshaders.bat
index bc992dc28c..61345d1906 100644
--- a/tests/manual/rhi/tessellation/buildshaders.bat
+++ b/tests/manual/rhi/tessellation/buildshaders.bat
@@ -1,3 +1,5 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl 320es,410 --hlsl 50 --msl 12 --msltess test.vert -o test.vert.qsb
qsb --glsl 320es,410 --msl 12 --tess-mode triangles test.tesc -o test.tesc.qsb
qsb -r hlsl,50,test_hull.hlsl test.tesc.qsb
diff --git a/tests/manual/rhi/tex1d/buildshaders.bat b/tests/manual/rhi/tex1d/buildshaders.bat
index 37934cf362..27bb8fc0e6 100644
--- a/tests/manual/rhi/tex1d/buildshaders.bat
+++ b/tests/manual/rhi/tex1d/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "120,150,300 es" --hlsl 50 --msl 12 -c texture1d.vert -o texture1d.vert.qsb
qsb --glsl "120,150,300 es" --hlsl 50 --msl 12 -c texture1d.frag -o texture1d.frag.qsb
diff --git a/tests/manual/rhi/tex3d/buildshaders.bat b/tests/manual/rhi/tex3d/buildshaders.bat
index 041c554688..699d2b112b 100644
--- a/tests/manual/rhi/tex3d/buildshaders.bat
+++ b/tests/manual/rhi/tex3d/buildshaders.bat
@@ -1,2 +1,4 @@
+:: Copyright (C) 2024 The Qt Company Ltd.
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb --glsl "300 es,150" --hlsl 50 --msl 12 -c texture3d.vert -o texture3d.vert.qsb
qsb --glsl "300 es,150" --hlsl 50 --msl 12 -c texture3d.frag -o texture3d.frag.qsb
diff --git a/tests/manual/wasm/qtloader_integration/test_body.js b/tests/manual/wasm/qtloader_integration/test_body.js
index e08ffdefbb..4fb49c31aa 100644
--- a/tests/manual/wasm/qtloader_integration/test_body.js
+++ b/tests/manual/wasm/qtloader_integration/test_body.js
@@ -1,5 +1,5 @@
// Copyright (C) 2023 The Qt Company Ltd.
-// SPDXLicenseIdentifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import { Mock, assert, TestRunner } from './testrunner.js';
diff --git a/tests/shared/nativewindow.h b/tests/shared/nativewindow.h
index 932d2d419a..163ca31634 100644
--- a/tests/shared/nativewindow.h
+++ b/tests/shared/nativewindow.h
@@ -28,7 +28,7 @@ class NativeWindow
public:
#if defined(Q_OS_MACOS)
using Handle = NSView*;
-#elif defined(Q_OS_IOS)
+#elif defined(QT_PLATFORM_UIKIT)
using Handle = UIView*;
#elif defined(Q_OS_WIN)
using Handle = HWND;
@@ -53,7 +53,7 @@ private:
Handle m_handle = {};
};
-#if QT_CONFIG(metal)
+#if defined(Q_OS_MACOS) || defined(QT_PLATFORM_UIKIT)
@interface View : VIEW_BASE
@end
diff --git a/tests/testserver/echo/echo.sh b/tests/testserver/echo/echo.sh
index f0da9627d5..516b476357 100755
--- a/tests/testserver/echo/echo.sh
+++ b/tests/testserver/echo/echo.sh
@@ -1,3 +1,5 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#!/usr/bin/env bash
# Disabled by default, enable it.
diff --git a/util/aglfn/main.cpp b/util/aglfn/main.cpp
index afcf8c2b2c..6c8dd78828 100644
--- a/util/aglfn/main.cpp
+++ b/util/aglfn/main.cpp
@@ -1,5 +1,7 @@
+// REUSE-IgnoreStart
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// REUSE-IgnoreEnd
#include <qbytearray.h>
#include <qlist.h>
@@ -120,11 +122,12 @@ static QByteArray createGlyphList()
int main(int, char **)
{
readGlyphList();
-
+// REUSE-IgnoreStart
QByteArray header =
"// Copyright (C) 2016 The Qt Company Ltd.\n"
"// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only\n"
"\n";
+// REUSE-IgnoreEnd
QByteArray note =
"/* This file is autogenerated from the Adobe Glyph List database" +
diff --git a/util/edid/qedidvendortable.py b/util/edid/qedidvendortable.py
index e1c5750695..0991d75db7 100755
--- a/util/edid/qedidvendortable.py
+++ b/util/edid/qedidvendortable.py
@@ -8,12 +8,12 @@ import urllib.request
# 'https://git.fedorahosted.org/cgit/hwdata.git/plain/pnp.ids'
# which is discontinued. For now there seems to be a fork at:
url = 'https://github.com/vcrhonek/hwdata/raw/master/pnp.ids'
-
+# REUSE-IgnoreStart
copyright = """
// Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
"""
-
+# REUSE-IgnoreEnd
notice = """/*
* This lookup table was generated from {}
*
diff --git a/util/gradientgen/gradientgen.cpp b/util/gradientgen/gradientgen.cpp
index a4c5531cc5..23b20d0505 100644
--- a/util/gradientgen/gradientgen.cpp
+++ b/util/gradientgen/gradientgen.cpp
@@ -17,13 +17,13 @@
#include <QColor>
using namespace std;
-
+// REUSE-IgnoreStart
static const char LICENSE_HEADER[] =
R"(
// Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
)";
-
+// REUSE-IgnoreEnd
class Printer {
Q_DISABLE_COPY_MOVE(Printer)
public:
diff --git a/util/locale_database/cldr.py b/util/locale_database/cldr.py
index 345fc50f5f..9e0bae9667 100644
--- a/util/locale_database/cldr.py
+++ b/util/locale_database/cldr.py
@@ -75,9 +75,8 @@ class CldrReader (object):
pass # self.__wrapped(self.whitter, 'Skipping likelySubtags (for unknown codes): ', skips)
def readLocales(self, calendars = ('gregorian',)):
- locales = tuple(self.__allLocales(calendars))
- return dict(((k.language_id, k.script_id, k.territory_id, k.variant_code),
- k) for k in locales)
+ return {(k.language_id, k.script_id, k.territory_id, k.variant_code): k
+ for k in self.__allLocales(calendars)}
def __allLocales(self, calendars):
def skip(locale, reason):
@@ -352,7 +351,11 @@ class CldrAccess (object):
parts.append(text)
if len(parts) > 1:
parts[-1] = 'and ' + parts[-1]
- assert parts
+ else:
+ assert parts
+ if parts[0].startswith('variant'):
+ raise Error(f'No support for {parts[0]}',
+ language, script, territory, variant)
raise Error('Unknown ' + ', '.join(parts),
language, script, territory, variant)
@@ -377,9 +380,9 @@ class CldrAccess (object):
for f in k.split('_'):
scraps.add(f)
from enumdata import language_map, territory_map, script_map
- language = dict((v, k) for k, v in language_map.values() if not v.isspace())
- territory = dict((v, k) for k, v in territory_map.values() if v != 'ZZ')
- script = dict((v, k) for k, v in script_map.values() if v != 'Zzzz')
+ language = {v: k for k, v in language_map.values() if not v.isspace()}
+ territory = {v: k for k, v in territory_map.values() if v != 'ZZ'}
+ script = {v: k for k, v in script_map.values() if v != 'Zzzz'}
lang = dict(self.__checkEnum(language, self.__codeMap('language'), scraps))
land = dict(self.__checkEnum(territory, self.__codeMap('territory'), scraps))
text = dict(self.__checkEnum(script, self.__codeMap('script'), scraps))
diff --git a/util/locale_database/cldr2qlocalexml.py b/util/locale_database/cldr2qlocalexml.py
index 28bf7ae641..d3aa88ec38 100755
--- a/util/locale_database/cldr2qlocalexml.py
+++ b/util/locale_database/cldr2qlocalexml.py
@@ -37,17 +37,25 @@ All the scripts mentioned support --help to tell you how to use them.
"""
from pathlib import Path
-import sys
import argparse
from cldr import CldrReader
from qlocalexml import QLocaleXmlWriter
-def main(out, err):
- all_calendars = ['gregorian', 'persian', 'islamic'] # 'hebrew'
+def main(argv, out, err):
+ """Generate a QLocaleXML file from CLDR data.
+
+ Takes sys.argv, sys.stdout, sys.stderr (or equivalents) as
+ arguments. In argv[1:], it expects the root of the CLDR data
+ directory as first parameter and the name of the file in which to
+ save QLocaleXML data as second parameter. It accepts a --calendars
+ option to select which calendars to support (all available by
+ default)."""
+ all_calendars = ['gregorian', 'persian', 'islamic']
parser = argparse.ArgumentParser(
+ prog=Path(argv[0]).name,
description='Generate QLocaleXML from CLDR data.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('cldr_path', help='path to the root of the CLDR tree')
@@ -57,7 +65,7 @@ def main(out, err):
nargs='+', metavar='CALENDAR',
choices=all_calendars, default=all_calendars)
- args = parser.parse_args()
+ args = parser.parse_args(argv[1:])
root = Path(args.cldr_path)
root_xml_path = 'common/main/root.xml'
@@ -90,4 +98,5 @@ def main(out, err):
return 0
if __name__ == '__main__':
- sys.exit(main(sys.stdout, sys.stderr))
+ import sys
+ sys.exit(main(sys.argv, sys.stdout, sys.stderr))
diff --git a/util/locale_database/cldr2qtimezone.py b/util/locale_database/cldr2qtimezone.py
index 27987d5a58..485177c0bd 100755
--- a/util/locale_database/cldr2qtimezone.py
+++ b/util/locale_database/cldr2qtimezone.py
@@ -19,219 +19,8 @@ import argparse
from localetools import unicode2hex, wrap_list, Error, SourceFileEditor, qtbase_root
from cldr import CldrAccess
-
-### Data that may need updates in response to new entries in the CLDR file ###
-
-# This script shall report the updates you need to make, if any arise.
-# However, you may need to research the relevant zone's standard offset.
-
-# List of currently known Windows IDs.
-# If this script reports missing IDs, please add them here.
-# Look up the offset using (google and) timeanddate.com.
-# Not public so may safely be changed. Please keep in alphabetic order by ID.
-# ( Windows Id, Offset Seconds )
-windowsIdList = (
- ('Afghanistan Standard Time', 16200),
- ('Alaskan Standard Time', -32400),
- ('Aleutian Standard Time', -36000),
- ('Altai Standard Time', 25200),
- ('Arab Standard Time', 10800),
- ('Arabian Standard Time', 14400),
- ('Arabic Standard Time', 10800),
- ('Argentina Standard Time', -10800),
- ('Astrakhan Standard Time', 14400),
- ('Atlantic Standard Time', -14400),
- ('AUS Central Standard Time', 34200),
- ('Aus Central W. Standard Time', 31500),
- ('AUS Eastern Standard Time', 36000),
- ('Azerbaijan Standard Time', 14400),
- ('Azores Standard Time', -3600),
- ('Bahia Standard Time', -10800),
- ('Bangladesh Standard Time', 21600),
- ('Belarus Standard Time', 10800),
- ('Bougainville Standard Time', 39600),
- ('Canada Central Standard Time', -21600),
- ('Cape Verde Standard Time', -3600),
- ('Caucasus Standard Time', 14400),
- ('Cen. Australia Standard Time', 34200),
- ('Central America Standard Time', -21600),
- ('Central Asia Standard Time', 21600),
- ('Central Brazilian Standard Time', -14400),
- ('Central Europe Standard Time', 3600),
- ('Central European Standard Time', 3600),
- ('Central Pacific Standard Time', 39600),
- ('Central Standard Time', -21600),
- ('Central Standard Time (Mexico)', -21600),
- ('Chatham Islands Standard Time', 45900),
- ('China Standard Time', 28800),
- ('Cuba Standard Time', -18000),
- ('Dateline Standard Time', -43200),
- ('E. Africa Standard Time', 10800),
- ('E. Australia Standard Time', 36000),
- ('E. Europe Standard Time', 7200),
- ('E. South America Standard Time', -10800),
- ('Easter Island Standard Time', -21600),
- ('Eastern Standard Time', -18000),
- ('Eastern Standard Time (Mexico)', -18000),
- ('Egypt Standard Time', 7200),
- ('Ekaterinburg Standard Time', 18000),
- ('Fiji Standard Time', 43200),
- ('FLE Standard Time', 7200),
- ('Georgian Standard Time', 14400),
- ('GMT Standard Time', 0),
- ('Greenland Standard Time', -10800),
- ('Greenwich Standard Time', 0),
- ('GTB Standard Time', 7200),
- ('Haiti Standard Time', -18000),
- ('Hawaiian Standard Time', -36000),
- ('India Standard Time', 19800),
- ('Iran Standard Time', 12600),
- ('Israel Standard Time', 7200),
- ('Jordan Standard Time', 7200),
- ('Kaliningrad Standard Time', 7200),
- ('Korea Standard Time', 32400),
- ('Libya Standard Time', 7200),
- ('Line Islands Standard Time', 50400),
- ('Lord Howe Standard Time', 37800),
- ('Magadan Standard Time', 36000),
- ('Magallanes Standard Time', -10800), # permanent DST
- ('Marquesas Standard Time', -34200),
- ('Mauritius Standard Time', 14400),
- ('Middle East Standard Time', 7200),
- ('Montevideo Standard Time', -10800),
- ('Morocco Standard Time', 0),
- ('Mountain Standard Time', -25200),
- ('Mountain Standard Time (Mexico)', -25200),
- ('Myanmar Standard Time', 23400),
- ('N. Central Asia Standard Time', 21600),
- ('Namibia Standard Time', 3600),
- ('Nepal Standard Time', 20700),
- ('New Zealand Standard Time', 43200),
- ('Newfoundland Standard Time', -12600),
- ('Norfolk Standard Time', 39600),
- ('North Asia East Standard Time', 28800),
- ('North Asia Standard Time', 25200),
- ('North Korea Standard Time', 30600),
- ('Omsk Standard Time', 21600),
- ('Pacific SA Standard Time', -10800),
- ('Pacific Standard Time', -28800),
- ('Pacific Standard Time (Mexico)', -28800),
- ('Pakistan Standard Time', 18000),
- ('Paraguay Standard Time', -14400),
- ('Qyzylorda Standard Time', 18000), # a.k.a. Kyzylorda, in Kazakhstan
- ('Romance Standard Time', 3600),
- ('Russia Time Zone 10', 39600),
- ('Russia Time Zone 11', 43200),
- ('Russia Time Zone 3', 14400),
- ('Russian Standard Time', 10800),
- ('SA Eastern Standard Time', -10800),
- ('SA Pacific Standard Time', -18000),
- ('SA Western Standard Time', -14400),
- ('Saint Pierre Standard Time', -10800), # New France
- ('Sakhalin Standard Time', 39600),
- ('Samoa Standard Time', 46800),
- ('Sao Tome Standard Time', 0),
- ('Saratov Standard Time', 14400),
- ('SE Asia Standard Time', 25200),
- ('Singapore Standard Time', 28800),
- ('South Africa Standard Time', 7200),
- ('South Sudan Standard Time', 7200),
- ('Sri Lanka Standard Time', 19800),
- ('Sudan Standard Time', 7200), # unless they mean South Sudan, +03:00
- ('Syria Standard Time', 7200),
- ('Taipei Standard Time', 28800),
- ('Tasmania Standard Time', 36000),
- ('Tocantins Standard Time', -10800),
- ('Tokyo Standard Time', 32400),
- ('Tomsk Standard Time', 25200),
- ('Tonga Standard Time', 46800),
- ('Transbaikal Standard Time', 32400), # Yakutsk
- ('Turkey Standard Time', 7200),
- ('Turks And Caicos Standard Time', -14400),
- ('Ulaanbaatar Standard Time', 28800),
- ('US Eastern Standard Time', -18000),
- ('US Mountain Standard Time', -25200),
- ('UTC', 0),
- # Lexical order: '+' < '-'
- ('UTC+12', 43200),
- ('UTC+13', 46800),
- ('UTC-02', -7200),
- ('UTC-08', -28800),
- ('UTC-09', -32400),
- ('UTC-11', -39600),
- ('Venezuela Standard Time', -16200),
- ('Vladivostok Standard Time', 36000),
- ('Volgograd Standard Time', 14400),
- ('W. Australia Standard Time', 28800),
- ('W. Central Africa Standard Time', 3600),
- ('W. Europe Standard Time', 3600),
- ('W. Mongolia Standard Time', 25200), # Hovd
- ('West Asia Standard Time', 18000),
- ('West Bank Standard Time', 7200),
- ('West Pacific Standard Time', 36000),
- ('Yakutsk Standard Time', 32400),
- ('Yukon Standard Time', -25200), # Non-DST Mountain Standard Time since 2020-11-01
-)
-
-# List of standard UTC IDs to use. Not public so may be safely changed.
-# Do not remove IDs, as each entry is part of the API/behavior guarantee.
-# IDs for the same offset shall be space-joined; list the preferred ID first.
-# ( UTC Id, Offset Seconds )
-utcIdList = (
- ('UTC-14:00', -50400),
- ('UTC-13:00', -46800),
- ('UTC-12:00', -43200),
- ('UTC-11:00', -39600),
- ('UTC-10:00', -36000),
- ('UTC-09:00', -32400),
- ('UTC-08:00', -28800),
- ('UTC-07:00', -25200),
- ('UTC-06:00', -21600),
- ('UTC-05:00', -18000),
- ('UTC-04:30', -16200),
- ('UTC-04:00', -14400),
- ('UTC-03:30', -12600),
- ('UTC-03:00', -10800),
- ('UTC-02:00', -7200),
- ('UTC-01:00', -3600),
- ('UTC', 0), # Goes first (among zero-offset) to be default
- ('UTC+00:00', 0),
- ('UTC-00:00', 0), # Should recognize, but avoid using (see Note below).
- ('UTC+01:00', 3600),
- ('UTC+02:00', 7200),
- ('UTC+03:00', 10800),
- ('UTC+03:30', 12600),
- ('UTC+04:00', 14400),
- ('UTC+04:30', 16200),
- ('UTC+05:00', 18000),
- ('UTC+05:30', 19800),
- ('UTC+05:45', 20700),
- ('UTC+06:00', 21600),
- ('UTC+06:30', 23400),
- ('UTC+07:00', 25200),
- ('UTC+08:00', 28800),
- ('UTC+08:30', 30600),
- ('UTC+09:00', 32400),
- ('UTC+09:30', 34200),
- ('UTC+10:00', 36000),
- ('UTC+11:00', 39600),
- ('UTC+12:00', 43200),
- ('UTC+13:00', 46800),
- ('UTC+14:00', 50400),
-)
-
-### End of data that may need updates in response to CLDR ###
-
-# Note: -00:00 (without the UTC prefix) was introduced in RFC3339 as a
-# way to indicate that a date-time has been converted to UTC but its
-# use should not be understood to say anything about the local time of
-# the origin of the message using it. However, ISO 8601 has, since
-# 2000, forbidden this as an offset suffix. The more recent compromise
-# is to use Z to convey the meaning RFC3339 gave to -00:00. So the use
-# of -00:00 as offset suffix should be avoided (and, by extension,
-# likewise for UTC-00:00 as a zone ID), but this suffix (and ID)
-# should be recognized when consuming data generated by other sources,
-# for backwards compatibility.
+# This script shall report any updates zonedata may need.
+from zonedata import windowsIdList, utcIdList
class ByteArrayData:
def __init__(self):
diff --git a/util/locale_database/dateconverter.py b/util/locale_database/dateconverter.py
index 5e750b76da..8ca15405f7 100644
--- a/util/locale_database/dateconverter.py
+++ b/util/locale_database/dateconverter.py
@@ -87,6 +87,10 @@ class Converter (object):
m = __verbatim # Minute within the hour.
M = L # Plain month names, possibly abbreviated, and numbers.
+ @classmethod
+ def O(cls, text): # Localized GMT±offset formats. Map to Z-or-UTC±HH:mm
+ return 't', cls.__count_first(text)
+
# q: Quarter. Not supported.
# Q: Quarter. Not supported.
@@ -109,21 +113,31 @@ class Converter (object):
# U: Cyclic Year Name. Not supported
@classmethod
- def v(cls, text): # Generic non-location format. Map to abbreviation.
- return 't', cls.__count_first(text)
+ def v(cls, text): # Generic non-location format. Map to name.
+ return 'tttt', cls.__count_first(text)
- V = v # Zone ID in various forms; VV is IANA ID. Map to abbreviation.
+ V = v # Zone ID in various forms; VV is IANA ID. Map to name.
# w: Week of year. Not supported.
# W: Week of month. Not supported.
@classmethod
+ def x(cls, text): # Variations on offset format.
+ n = cls.__count_first(text)
+ # Ignore: n == 1 may omit minutes, n > 3 may include seconds.
+ return ('ttt' if n > 1 and n & 1 else 'tt'), n
+ X = x # Should use Z for zero offset.
+
+ @classmethod
def y(cls, text): # Year number.
n = cls.__count_first(text)
return ('yy' if n == 2 else 'yyyy'), n
# Y: Year for Week-of-year calendars
z = v # Specific (i.e. distinguish standard from DST) non-location format.
- Z = v # Offset format, optionaly with GMT (Qt uses UTC) prefix.
+ @classmethod
+ def Z(cls, text): # Offset format, optionaly with GMT (Qt uses UTC) prefix.
+ n = cls.__count_first(text)
+ return ('tt' if n < 4 else 'ttt' if n > 4 else 't'), n
@staticmethod
def scanQuote(text): # Can't have ' as a method name, so handle specially
diff --git a/util/locale_database/enumdata.py b/util/locale_database/enumdata.py
index 1749b85f63..66b8840cb1 100644
--- a/util/locale_database/enumdata.py
+++ b/util/locale_database/enumdata.py
@@ -434,7 +434,7 @@ language_aliases = {
'Navaho': 'Navajo',
'Oriya': 'Odia',
'Kirghiz': 'Kyrgyz'
- }
+}
territory_map = {
0: ("AnyTerritory", "ZZ"),
diff --git a/util/locale_database/ldml.py b/util/locale_database/ldml.py
index eaf5d66f65..b94c242172 100644
--- a/util/locale_database/ldml.py
+++ b/util/locale_database/ldml.py
@@ -417,7 +417,7 @@ class LocaleScanner (object):
('long', 'format', 'wide'),
('short', 'format', 'abbreviated'),
('narrow', 'format', 'narrow'),
- ) # Used for month and day names
+ ) # Used for month and day names
def __find(self, xpath):
retries, foundNone = [ xpath.split('/') ], True
@@ -485,7 +485,7 @@ class LocaleScanner (object):
return self.find(stem + 'displayName')
except Error:
pass
- for x in ('zero', 'one', 'two', 'few', 'many', 'other'):
+ for x in ('zero', 'one', 'two', 'few', 'many', 'other'):
try:
return self.find(f'{stem}displayName[count={x}]')
except Error:
diff --git a/util/locale_database/qlocalexml.py b/util/locale_database/qlocalexml.py
index 9cb1f63f8b..5cb56c2165 100644
--- a/util/locale_database/qlocalexml.py
+++ b/util/locale_database/qlocalexml.py
@@ -44,59 +44,6 @@ def startCount(c, text): # strspn
except StopIteration:
return len(text)
-def convertFormat(format):
- """Convert date/time format-specier from CLDR to Qt
-
- Match up (as best we can) the differences between:
- * https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
- * QDateTimeParser::parseFormat() and QLocalePrivate::dateTimeToString()
- """
- # Compare and contrast dateconverter.py's convert_date().
- # Need to (check consistency and) reduce redundancy !
- result = ""
- i = 0
- while i < len(format):
- if format[i] == "'":
- result += "'"
- i += 1
- while i < len(format) and format[i] != "'":
- result += format[i]
- i += 1
- if i < len(format):
- result += "'"
- i += 1
- else:
- s = format[i:]
- if s.startswith('E'): # week-day
- n = startCount('E', s)
- if n < 3:
- result += 'ddd'
- elif n == 4:
- result += 'dddd'
- else: # 5: narrow, 6 short; but should be name, not number :-(
- result += 'd' if n < 6 else 'dd'
- i += n
- elif s[0] in 'ab': # am/pm
- # 'b' should distinguish noon/midnight, too :-(
- result += "AP"
- i += startCount('ab', s)
- elif s.startswith('S'): # fractions of seconds: count('S') == number of decimals to show
- result += 'z'
- i += startCount('S', s)
- elif s.startswith('V'): # long time zone specifiers (and a deprecated short ID)
- result += 't'
- i += startCount('V', s)
- elif s[0] in 'zv': # zone
- # Should use full name, e.g. "Central European Time", if 'zzzz' :-(
- # 'v' should get generic non-location format, e.g. PT for "Pacific Time", no DST indicator
- result += "t"
- i += startCount('zv', s)
- else:
- result += format[i]
- i += 1
-
- return result
-
class QLocaleXmlReader (object):
def __init__(self, filename):
self.root = self.__parse(filename)
@@ -109,14 +56,14 @@ class QLocaleXmlReader (object):
self.__likely = tuple(self.__likelySubtagsMap())
# Mappings {ID: (enum name, code, en.xml name)}
- self.languages = dict((v[0], v[1:]) for v in languages)
- self.scripts = dict((v[0], v[1:]) for v in scripts)
- self.territories = dict((v[0], v[1:]) for v in territories)
+ self.languages = {v[0]: v[1:] for v in languages}
+ self.scripts = {v[0]: v[1:] for v in scripts}
+ self.territories = {v[0]: v[1:] for v in territories}
# Private mappings {enum name: (ID, code)}
- self.__langByName = dict((v[1], (v[0], v[2])) for v in languages)
- self.__textByName = dict((v[1], (v[0], v[2])) for v in scripts)
- self.__landByName = dict((v[1], (v[0], v[2])) for v in territories)
+ self.__langByName = {v[1]: (v[0], v[2]) for v in languages}
+ self.__textByName = {v[1]: (v[0], v[2]) for v in scripts}
+ self.__landByName = {v[1]: (v[0], v[2]) for v in territories}
# Other properties:
self.__dupes = set(v[1] for v in languages) & set(v[1] for v in territories)
self.cldrVersion = self.__firstChildText(self.root, "version")
@@ -396,7 +343,7 @@ class QLocaleXmlWriter (object):
self.__write(f'<{tag}>{text}</{tag}>')
def close(self, grumble):
- """Finish writing and grumble any issues discovered."""
+ """Finish writing and grumble about any issues discovered."""
if self.__rawOutput != self.__complain:
self.__write('</localeDatabase>')
self.__rawOutput = self.__complain
@@ -486,8 +433,6 @@ class Locale (object):
__asint = ("currencyDigits", "currencyRounding")
# Convert day-name to Qt day-of-week number:
__asdow = ("firstDayOfWeek", "weekendStart", "weekendEnd")
- # Convert from CLDR format-strings to QDateTimeParser ones:
- __asfmt = ("longDateFormat", "shortDateFormat", "longTimeFormat", "shortTimeFormat")
# Just use the raw text:
__astxt = ("language", "languageEndonym", "script", "territory", "territoryEndonym",
"decimal", "group", "zero",
@@ -496,6 +441,8 @@ class Locale (object):
"alternateQuotationStart", "alternateQuotationEnd",
"listPatternPartStart", "listPatternPartMiddle",
"listPatternPartEnd", "listPatternPartTwo", "am", "pm",
+ "longDateFormat", "shortDateFormat",
+ "longTimeFormat", "shortTimeFormat",
'byte_unit', 'byte_si_quantified', 'byte_iec_quantified',
"currencyIsoCode", "currencySymbol", "currencyDisplayName",
"currencyFormat", "currencyNegativeFormat")
@@ -520,14 +467,11 @@ class Locale (object):
for k in cls.__asdow:
data[k] = cls.__qDoW[lookup(k)]
- for k in cls.__asfmt:
- data[k] = convertFormat(lookup(k))
-
for k in cls.__astxt + tuple(cls.propsMonthDay('days')):
data['listDelim' if k == 'list' else k] = lookup(k)
for k in cls.propsMonthDay('months'):
- data[k] = dict((cal, lookup('_'.join((k, cal)))) for cal in calendars)
+ data[k] = {cal: lookup('_'.join((k, cal))) for cal in calendars}
grouping = lookup('groupSizes').split(';')
data.update(groupLeast = int(grouping[0]),
@@ -619,7 +563,7 @@ class Locale (object):
(fullName, fullName),
(fullName, fullName),
(number, number)),
- },
+ },
sizes=('long', 'short', 'narrow')):
for cal in calendars:
try:
@@ -659,8 +603,8 @@ class Locale (object):
byte_iec_quantified=';'.join(q.upper() + 'iB' for q in quantifiers),
am='AM', pm='PM', firstDayOfWeek='mon',
weekendStart='sat', weekendEnd='sun',
- longDateFormat='EEEE, d MMMM yyyy', shortDateFormat='d MMM yyyy',
- longTimeFormat='HH:mm:ss z', shortTimeFormat='HH:mm:ss',
+ longDateFormat='dddd, d MMMM yyyy', shortDateFormat='d MMM yyyy',
+ longTimeFormat='HH:mm:ss t', shortTimeFormat='HH:mm:ss',
longDays=';'.join(days),
shortDays=';'.join(d[:3] for d in days),
narrowDays='7;1;2;3;4;5;6',
diff --git a/util/locale_database/qlocalexml2cpp.py b/util/locale_database/qlocalexml2cpp.py
index b770049cca..b20e4fd155 100755
--- a/util/locale_database/qlocalexml2cpp.py
+++ b/util/locale_database/qlocalexml2cpp.py
@@ -283,7 +283,7 @@ class LocaleDataWriter (LocaleSourceEditor):
locale.minus, locale.plus, locale.exp,
locale.quotationStart, locale.quotationEnd,
locale.alternateQuotationStart, locale.alternateQuotationEnd)) +
- tuple (date_format_data.append(f) for f in # 2 entries:
+ tuple(date_format_data.append(f) for f in # 2 entries:
(locale.longDateFormat, locale.shortDateFormat)) +
tuple(time_format_data.append(f) for f in # 2 entries:
(locale.longTimeFormat, locale.shortTimeFormat)) +
@@ -458,6 +458,23 @@ class CalendarDataWriter (LocaleSourceEditor):
self.writer.write('};\n')
months_data.write(self.writer)
+
+class TestLocaleWriter (LocaleSourceEditor):
+ def localeList(self, locales):
+ self.writer.write('const LocaleListItem g_locale_list[] = {\n')
+ from enumdata import language_map, territory_map
+ # TODO: update testlocales/ to include script.
+ # For now, only mention each (lang, land) pair once:
+ pairs = set((lang, land) for lang, script, land in locales)
+ for lang, script, land in locales:
+ if (lang, land) in pairs:
+ pairs.discard((lang, land))
+ langName = language_map[lang][0]
+ landName = territory_map[land][0]
+ self.writer.write(f' {{ {lang:6d},{land:6d} }}, // {langName}/{landName}\n')
+ self.writer.write('};\n\n')
+
+
class LocaleHeaderWriter (SourceFileEditor):
def __init__(self, path, temp, enumify):
super().__init__(path, temp)
@@ -504,17 +521,29 @@ class LocaleHeaderWriter (SourceFileEditor):
out('\n };\n')
-def main(out, err):
+def main(argv, out, err):
+ """Updates QLocale's CLDR data from a QLocaleXML file.
+
+ Takes sys.argv, sys.stdout, sys.stderr (or equivalents) as
+ arguments. In argv[1:] it expects the QLocaleXML file as first
+ parameter and the ISO 639-3 data table as second
+ parameter. Accepts the root of the qtbase checkout as third
+ parameter (default is inferred from this script's path) and a
+ --calendars option to select which calendars to support (all
+ available by default).
+
+ Updates various src/corelib/t*/q*_data_p.h files within the qtbase
+ checkout to contain data extracted from the QLocaleXML file."""
calendars_map = {
# CLDR name: Qt file name fragment
'gregorian': 'roman',
'persian': 'jalali',
'islamic': 'hijri',
- # 'hebrew': 'hebrew'
}
all_calendars = list(calendars_map.keys())
parser = argparse.ArgumentParser(
+ prog=Path(argv[0]).name,
description='Generate C++ code from CLDR data in QLocaleXML form.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('input_file', help='input XML file name',
@@ -526,7 +555,7 @@ def main(out, err):
parser.add_argument('--calendars', help='select calendars to emit data for',
nargs='+', metavar='CALENDAR',
choices=all_calendars, default=all_calendars)
- args = parser.parse_args()
+ args = parser.parse_args(argv[1:])
qlocalexml = args.input_file
qtsrcdir = Path(args.qtbase_path)
@@ -594,8 +623,17 @@ def main(out, err):
err.write(f'\nError updating qlocale.h: {e}\n')
return 1
+ # ./testlocales/localemodel.cpp
+ try:
+ path = 'util/locale_database/testlocales/localemodel.cpp'
+ with TestLocaleWriter(qtsrcdir.joinpath(path), qtsrcdir,
+ reader.cldrVersion) as test:
+ test.localeList(locale_keys)
+ except Exception as e:
+ err.write(f'\nError updating localemodel.cpp: {e}\n')
+
return 0
if __name__ == "__main__":
import sys
- sys.exit(main(sys.stdout, sys.stderr))
+ sys.exit(main(sys.argv, sys.stdout, sys.stderr))
diff --git a/util/locale_database/testlocales/localemodel.cpp b/util/locale_database/testlocales/localemodel.cpp
index 9642bb36fa..7f0150c7e0 100644
--- a/util/locale_database/testlocales/localemodel.cpp
+++ b/util/locale_database/testlocales/localemodel.cpp
@@ -14,236 +14,658 @@ struct LocaleListItem
int territory;
};
+// GENERATED PART STARTS HERE
+
+/*
+ This part of the file was generated on 2024-04-22 from the
+ Common Locale Data Repository v44.1
+
+ http://www.unicode.org/cldr/
+
+ Do not edit this section: instead regenerate it using
+ cldr2qlocalexml.py and qlocalexml2cpp.py on updated (or
+ edited) CLDR data; see qtbase/util/locale_database/.
+*/
+
const LocaleListItem g_locale_list[] = {
{ 1, 0 }, // C/AnyTerritory
- { 3, 69 }, // Afan/Ethiopia
- { 3, 111 }, // Afan/Kenya
- { 4, 59 }, // Afar/Djibouti
- { 4, 67 }, // Afar/Eritrea
- { 4, 69 }, // Afar/Ethiopia
- { 5, 195 }, // Afrikaans/SouthAfrica
- { 5, 148 }, // Afrikaans/Namibia
- { 6, 2 }, // Albanian/Albania
- { 7, 69 }, // Amharic/Ethiopia
- { 8, 186 }, // Arabic/SaudiArabia
- { 8, 3 }, // Arabic/Algeria
- { 8, 17 }, // Arabic/Bahrain
- { 8, 64 }, // Arabic/Egypt
- { 8, 103 }, // Arabic/Iraq
- { 8, 109 }, // Arabic/Jordan
- { 8, 115 }, // Arabic/Kuwait
- { 8, 119 }, // Arabic/Lebanon
- { 8, 122 }, // Arabic/LibyanArabJamahiriya
- { 8, 145 }, // Arabic/Morocco
- { 8, 162 }, // Arabic/Oman
- { 8, 175 }, // Arabic/Qatar
- { 8, 201 }, // Arabic/Sudan
- { 8, 207 }, // Arabic/SyrianArabRepublic
- { 8, 216 }, // Arabic/Tunisia
- { 8, 223 }, // Arabic/UnitedArabEmirates
- { 8, 237 }, // Arabic/Yemen
- { 9, 11 }, // Armenian/Armenia
- { 10, 100 }, // Assamese/India
- { 12, 15 }, // Azerbaijani/Azerbaijan
- { 14, 197 }, // Basque/Spain
- { 15, 18 }, // Bengali/Bangladesh
- { 15, 100 }, // Bengali/India
- { 16, 25 }, // Bhutani/Bhutan
- { 20, 33 }, // Bulgarian/Bulgaria
- { 22, 20 }, // Byelorussian/Belarus
- { 23, 36 }, // Cambodian/Cambodia
- { 24, 197 }, // Catalan/Spain
- { 25, 44 }, // Chinese/China
- { 25, 97 }, // Chinese/HongKong
- { 25, 126 }, // Chinese/Macau
- { 25, 190 }, // Chinese/Singapore
- { 25, 208 }, // Chinese/Taiwan
- { 27, 54 }, // Croatian/Croatia
- { 28, 57 }, // Czech/CzechRepublic
- { 29, 58 }, // Danish/Denmark
- { 30, 151 }, // Dutch/Netherlands
- { 30, 21 }, // Dutch/Belgium
- { 31, 225 }, // English/UnitedStates
- { 31, 4 }, // English/AmericanSamoa
- { 31, 13 }, // English/Australia
- { 31, 21 }, // English/Belgium
- { 31, 22 }, // English/Belize
- { 31, 28 }, // English/Botswana
- { 31, 38 }, // English/Canada
- { 31, 89 }, // English/Guam
- { 31, 97 }, // English/HongKong
- { 31, 100 }, // English/India
- { 31, 104 }, // English/Ireland
- { 31, 107 }, // English/Jamaica
- { 31, 133 }, // English/Malta
- { 31, 134 }, // English/MarshallIslands
- { 31, 148 }, // English/Namibia
- { 31, 154 }, // English/NewZealand
- { 31, 160 }, // English/NorthernMarianaIslands
- { 31, 163 }, // English/Pakistan
- { 31, 170 }, // English/Philippines
- { 31, 190 }, // English/Singapore
- { 31, 195 }, // English/SouthAfrica
- { 31, 215 }, // English/TrinidadAndTobago
- { 31, 224 }, // English/UnitedKingdom
- { 31, 226 }, // English/UnitedStatesMinorOutlyingIslands
- { 31, 234 }, // English/USVirginIslands
- { 31, 240 }, // English/Zimbabwe
- { 33, 68 }, // Estonian/Estonia
- { 34, 71 }, // Faroese/FaroeIslands
- { 36, 73 }, // Finnish/Finland
- { 37, 74 }, // French/France
- { 37, 21 }, // French/Belgium
- { 37, 38 }, // French/Canada
- { 37, 125 }, // French/Luxembourg
- { 37, 142 }, // French/Monaco
- { 37, 206 }, // French/Switzerland
- { 40, 197 }, // Galician/Spain
- { 41, 81 }, // Georgian/Georgia
- { 42, 82 }, // German/Germany
- { 42, 14 }, // German/Austria
- { 42, 21 }, // German/Belgium
- { 42, 123 }, // German/Liechtenstein
- { 42, 125 }, // German/Luxembourg
- { 42, 206 }, // German/Switzerland
- { 43, 85 }, // Greek/Greece
- { 43, 56 }, // Greek/Cyprus
- { 44, 86 }, // Greenlandic/Greenland
- { 46, 100 }, // Gujarati/India
- { 47, 83 }, // Hausa/Ghana
- { 47, 156 }, // Hausa/Niger
- { 47, 157 }, // Hausa/Nigeria
- { 48, 105 }, // Hebrew/Israel
- { 49, 100 }, // Hindi/India
- { 50, 98 }, // Hungarian/Hungary
- { 51, 99 }, // Icelandic/Iceland
- { 52, 101 }, // Indonesian/Indonesia
- { 57, 104 }, // Irish/Ireland
- { 58, 106 }, // Italian/Italy
- { 58, 206 }, // Italian/Switzerland
- { 59, 108 }, // Japanese/Japan
- { 61, 100 }, // Kannada/India
- { 63, 110 }, // Kazakh/Kazakhstan
- { 64, 179 }, // Kinyarwanda/Rwanda
- { 65, 116 }, // Kirghiz/Kyrgyzstan
- { 66, 114 }, // Korean/RepublicOfKorea
- { 67, 102 }, // Kurdish/Iran
- { 67, 103 }, // Kurdish/Iraq
- { 67, 207 }, // Kurdish/SyrianArabRepublic
- { 67, 217 }, // Kurdish/Turkey
- { 69, 117 }, // Laothian/Lao
- { 71, 118 }, // Latvian/Latvia
- { 72, 49 }, // Lingala/DemocraticRepublicOfCongo
- { 72, 50 }, // Lingala/PeoplesRepublicOfCongo
- { 73, 124 }, // Lithuanian/Lithuania
- { 74, 127 }, // Macedonian/Macedonia
- { 76, 130 }, // Malay/Malaysia
- { 76, 32 }, // Malay/BruneiDarussalam
- { 77, 100 }, // Malayalam/India
- { 78, 133 }, // Maltese/Malta
- { 80, 100 }, // Marathi/India
- { 82, 143 }, // Mongolian/Mongolia
- { 84, 150 }, // Nepali/Nepal
- { 85, 161 }, // Norwegian/Norway
- { 87, 100 }, // Oriya/India
- { 88, 1 }, // Pashto/Afghanistan
- { 89, 102 }, // Persian/Iran
- { 89, 1 }, // Persian/Afghanistan
- { 90, 172 }, // Polish/Poland
- { 91, 173 }, // Portuguese/Portugal
- { 91, 30 }, // Portuguese/Brazil
- { 92, 100 }, // Punjabi/India
- { 92, 163 }, // Punjabi/Pakistan
- { 95, 177 }, // Romanian/Romania
- { 96, 178 }, // Russian/RussianFederation
- { 96, 222 }, // Russian/Ukraine
- { 99, 100 }, // Sanskrit/India
- { 100, 241 }, // Serbian/SerbiaAndMontenegro
- { 100, 27 }, // Serbian/BosniaAndHerzegowina
- { 100, 238 }, // Serbian/Yugoslavia
- { 101, 241 }, // SerboCroatian/SerbiaAndMontenegro
- { 101, 27 }, // SerboCroatian/BosniaAndHerzegowina
- { 101, 238 }, // SerboCroatian/Yugoslavia
- { 102, 195 }, // Sesotho/SouthAfrica
- { 103, 195 }, // Setswana/SouthAfrica
- { 107, 195 }, // Siswati/SouthAfrica
- { 108, 191 }, // Slovak/Slovakia
- { 109, 192 }, // Slovenian/Slovenia
- { 110, 194 }, // Somali/Somalia
- { 110, 59 }, // Somali/Djibouti
- { 110, 69 }, // Somali/Ethiopia
- { 110, 111 }, // Somali/Kenya
- { 111, 197 }, // Spanish/Spain
- { 111, 10 }, // Spanish/Argentina
- { 111, 26 }, // Spanish/Bolivia
- { 111, 43 }, // Spanish/Chile
- { 111, 47 }, // Spanish/Colombia
- { 111, 52 }, // Spanish/CostaRica
- { 111, 61 }, // Spanish/DominicanRepublic
- { 111, 63 }, // Spanish/Ecuador
- { 111, 65 }, // Spanish/ElSalvador
- { 111, 90 }, // Spanish/Guatemala
- { 111, 96 }, // Spanish/Honduras
- { 111, 139 }, // Spanish/Mexico
- { 111, 155 }, // Spanish/Nicaragua
- { 111, 166 }, // Spanish/Panama
- { 111, 168 }, // Spanish/Paraguay
- { 111, 169 }, // Spanish/Peru
- { 111, 174 }, // Spanish/PuertoRico
- { 111, 225 }, // Spanish/UnitedStates
- { 111, 227 }, // Spanish/Uruguay
- { 111, 231 }, // Spanish/Venezuela
- { 113, 111 }, // Swahili/Kenya
- { 113, 210 }, // Swahili/Tanzania
- { 114, 205 }, // Swedish/Sweden
- { 114, 73 }, // Swedish/Finland
- { 116, 209 }, // Tajik/Tajikistan
- { 117, 100 }, // Tamil/India
- { 118, 178 }, // Tatar/RussianFederation
- { 119, 100 }, // Telugu/India
- { 120, 211 }, // Thai/Thailand
- { 122, 67 }, // Tigrinya/Eritrea
- { 122, 69 }, // Tigrinya/Ethiopia
- { 124, 195 }, // Tsonga/SouthAfrica
- { 125, 217 }, // Turkish/Turkey
- { 129, 222 }, // Ukrainian/Ukraine
- { 130, 100 }, // Urdu/India
- { 130, 163 }, // Urdu/Pakistan
- { 131, 228 }, // Uzbek/Uzbekistan
- { 131, 1 }, // Uzbek/Afghanistan
- { 132, 232 }, // Vietnamese/VietNam
- { 134, 224 }, // Welsh/UnitedKingdom
- { 136, 195 }, // Xhosa/SouthAfrica
- { 138, 157 }, // Yoruba/Nigeria
- { 140, 195 }, // Zulu/SouthAfrica
- { 141, 161 }, // Nynorsk/Norway
- { 142, 27 }, // Bosnian/BosniaAndHerzegowina
- { 143, 131 }, // Divehi/Maldives
- { 144, 224 }, // Manx/UnitedKingdom
- { 145, 224 }, // Cornish/UnitedKingdom
- { 146, 83 }, // Akan/Ghana
- { 147, 100 }, // Konkani/India
- { 148, 83 }, // Ga/Ghana
- { 149, 157 }, // Igbo/Nigeria
- { 150, 111 }, // Kamba/Kenya
- { 151, 207 }, // Syriac/SyrianArabRepublic
- { 152, 67 }, // Blin/Eritrea
- { 153, 67 }, // Geez/Eritrea
- { 153, 69 }, // Geez/Ethiopia
- { 154, 157 }, // Koro/Nigeria
- { 155, 69 }, // Sidamo/Ethiopia
- { 156, 157 }, // Atsam/Nigeria
- { 157, 67 }, // Tigre/Eritrea
- { 158, 157 }, // Jju/Nigeria
- { 159, 106 }, // Friulian/Italy
- { 160, 195 }, // Venda/SouthAfrica
- { 161, 83 }, // Ewe/Ghana
- { 161, 212 }, // Ewe/Togo
- { 163, 225 }, // Hawaiian/UnitedStates
- { 164, 157 }, // Tyap/Nigeria
- { 165, 129 }, // Chewa/Malawi
+ { 2, 90 }, // Abkhazian/Georgia
+ { 3, 77 }, // Afar/Ethiopia
+ { 3, 67 }, // Afar/Djibouti
+ { 3, 74 }, // Afar/Eritrea
+ { 4, 216 }, // Afrikaans/South Africa
+ { 4, 162 }, // Afrikaans/Namibia
+ { 5, 40 }, // Aghem/Cameroon
+ { 6, 92 }, // Akan/Ghana
+ { 8, 40 }, // Akoose/Cameroon
+ { 9, 3 }, // Albanian/Albania
+ { 9, 126 }, // Albanian/Kosovo
+ { 9, 140 }, // Albanian/Macedonia
+ { 11, 77 }, // Amharic/Ethiopia
+ { 14, 71 }, // Arabic/Egypt
+ { 14, 4 }, // Arabic/Algeria
+ { 14, 19 }, // Arabic/Bahrain
+ { 14, 48 }, // Arabic/Chad
+ { 14, 55 }, // Arabic/Comoros
+ { 14, 67 }, // Arabic/Djibouti
+ { 14, 74 }, // Arabic/Eritrea
+ { 14, 113 }, // Arabic/Iraq
+ { 14, 116 }, // Arabic/Israel
+ { 14, 122 }, // Arabic/Jordan
+ { 14, 127 }, // Arabic/Kuwait
+ { 14, 132 }, // Arabic/Lebanon
+ { 14, 135 }, // Arabic/Libya
+ { 14, 149 }, // Arabic/Mauritania
+ { 14, 159 }, // Arabic/Morocco
+ { 14, 176 }, // Arabic/Oman
+ { 14, 180 }, // Arabic/Palestinian Territories
+ { 14, 190 }, // Arabic/Qatar
+ { 14, 205 }, // Arabic/Saudi Arabia
+ { 14, 215 }, // Arabic/Somalia
+ { 14, 219 }, // Arabic/South Sudan
+ { 14, 222 }, // Arabic/Sudan
+ { 14, 227 }, // Arabic/Syria
+ { 14, 238 }, // Arabic/Tunisia
+ { 14, 245 }, // Arabic/United Arab Emirates
+ { 14, 257 }, // Arabic/Western Sahara
+ { 14, 258 }, // Arabic/world
+ { 14, 259 }, // Arabic/Yemen
+ { 15, 220 }, // Aragonese/Spain
+ { 17, 12 }, // Armenian/Armenia
+ { 18, 110 }, // Assamese/India
+ { 19, 220 }, // Asturian/Spain
+ { 20, 230 }, // Asu/Tanzania
+ { 21, 169 }, // Atsam/Nigeria
+ { 25, 17 }, // Azerbaijani/Azerbaijan
+ { 25, 112 }, // Azerbaijani/Iran
+ { 25, 113 }, // Azerbaijani/Iraq
+ { 25, 239 }, // Azerbaijani/Turkey
+ { 26, 40 }, // Bafia/Cameroon
+ { 28, 145 }, // Bambara/Mali
+ { 30, 20 }, // Bangla/Bangladesh
+ { 30, 110 }, // Bangla/India
+ { 31, 40 }, // Basaa/Cameroon
+ { 32, 193 }, // Bashkir/Russia
+ { 33, 220 }, // Basque/Spain
+ { 35, 22 }, // Belarusian/Belarus
+ { 36, 260 }, // Bemba/Zambia
+ { 37, 230 }, // Bena/Tanzania
+ { 38, 110 }, // Bhojpuri/India
+ { 40, 74 }, // Blin/Eritrea
+ { 41, 110 }, // Bodo/India
+ { 42, 29 }, // Bosnian/Bosnia and Herzegovina
+ { 43, 84 }, // Breton/France
+ { 45, 36 }, // Bulgarian/Bulgaria
+ { 46, 161 }, // Burmese/Myanmar
+ { 47, 107 }, // Cantonese/Hong Kong
+ { 47, 50 }, // Cantonese/China
+ { 48, 220 }, // Catalan/Spain
+ { 48, 6 }, // Catalan/Andorra
+ { 48, 84 }, // Catalan/France
+ { 48, 117 }, // Catalan/Italy
+ { 49, 185 }, // Cebuano/Philippines
+ { 50, 159 }, // Central Atlas Tamazight/Morocco
+ { 51, 113 }, // Central Kurdish/Iraq
+ { 51, 112 }, // Central Kurdish/Iran
+ { 52, 20 }, // Chakma/Bangladesh
+ { 52, 110 }, // Chakma/India
+ { 54, 193 }, // Chechen/Russia
+ { 55, 248 }, // Cherokee/United States
+ { 56, 248 }, // Chickasaw/United States
+ { 57, 243 }, // Chiga/Uganda
+ { 58, 50 }, // Chinese/China
+ { 58, 107 }, // Chinese/Hong Kong
+ { 58, 139 }, // Chinese/Macao
+ { 58, 210 }, // Chinese/Singapore
+ { 58, 228 }, // Chinese/Taiwan
+ { 59, 193 }, // Church/Russia
+ { 60, 193 }, // Chuvash/Russia
+ { 61, 91 }, // Colognian/Germany
+ { 63, 246 }, // Cornish/United Kingdom
+ { 64, 84 }, // Corsican/France
+ { 66, 60 }, // Croatian/Croatia
+ { 66, 29 }, // Croatian/Bosnia and Herzegovina
+ { 67, 64 }, // Czech/Czechia
+ { 68, 65 }, // Danish/Denmark
+ { 68, 95 }, // Danish/Greenland
+ { 69, 144 }, // Divehi/Maldives
+ { 70, 110 }, // Dogri/India
+ { 71, 40 }, // Duala/Cameroon
+ { 72, 165 }, // Dutch/Netherlands
+ { 72, 13 }, // Dutch/Aruba
+ { 72, 23 }, // Dutch/Belgium
+ { 72, 44 }, // Dutch/Caribbean Netherlands
+ { 72, 62 }, // Dutch/Curacao
+ { 72, 211 }, // Dutch/Sint Maarten
+ { 72, 223 }, // Dutch/Suriname
+ { 73, 27 }, // Dzongkha/Bhutan
+ { 74, 124 }, // Embu/Kenya
+ { 75, 248 }, // English/United States
+ { 75, 5 }, // English/American Samoa
+ { 75, 8 }, // English/Anguilla
+ { 75, 10 }, // English/Antigua and Barbuda
+ { 75, 15 }, // English/Australia
+ { 75, 16 }, // English/Austria
+ { 75, 18 }, // English/Bahamas
+ { 75, 21 }, // English/Barbados
+ { 75, 23 }, // English/Belgium
+ { 75, 24 }, // English/Belize
+ { 75, 26 }, // English/Bermuda
+ { 75, 30 }, // English/Botswana
+ { 75, 33 }, // English/British Indian Ocean Territory
+ { 75, 34 }, // English/British Virgin Islands
+ { 75, 38 }, // English/Burundi
+ { 75, 40 }, // English/Cameroon
+ { 75, 41 }, // English/Canada
+ { 75, 45 }, // English/Cayman Islands
+ { 75, 51 }, // English/Christmas Island
+ { 75, 53 }, // English/Cocos Islands
+ { 75, 58 }, // English/Cook Islands
+ { 75, 63 }, // English/Cyprus
+ { 75, 65 }, // English/Denmark
+ { 75, 66 }, // English/Diego Garcia
+ { 75, 68 }, // English/Dominica
+ { 75, 74 }, // English/Eritrea
+ { 75, 76 }, // English/Eswatini
+ { 75, 78 }, // English/Europe
+ { 75, 80 }, // English/Falkland Islands
+ { 75, 82 }, // English/Fiji
+ { 75, 83 }, // English/Finland
+ { 75, 89 }, // English/Gambia
+ { 75, 91 }, // English/Germany
+ { 75, 92 }, // English/Ghana
+ { 75, 93 }, // English/Gibraltar
+ { 75, 96 }, // English/Grenada
+ { 75, 98 }, // English/Guam
+ { 75, 100 }, // English/Guernsey
+ { 75, 103 }, // English/Guyana
+ { 75, 107 }, // English/Hong Kong
+ { 75, 110 }, // English/India
+ { 75, 111 }, // English/Indonesia
+ { 75, 114 }, // English/Ireland
+ { 75, 115 }, // English/Isle of Man
+ { 75, 116 }, // English/Israel
+ { 75, 119 }, // English/Jamaica
+ { 75, 121 }, // English/Jersey
+ { 75, 124 }, // English/Kenya
+ { 75, 125 }, // English/Kiribati
+ { 75, 133 }, // English/Lesotho
+ { 75, 134 }, // English/Liberia
+ { 75, 139 }, // English/Macao
+ { 75, 141 }, // English/Madagascar
+ { 75, 142 }, // English/Malawi
+ { 75, 143 }, // English/Malaysia
+ { 75, 144 }, // English/Maldives
+ { 75, 146 }, // English/Malta
+ { 75, 147 }, // English/Marshall Islands
+ { 75, 150 }, // English/Mauritius
+ { 75, 153 }, // English/Micronesia
+ { 75, 158 }, // English/Montserrat
+ { 75, 162 }, // English/Namibia
+ { 75, 163 }, // English/Nauru
+ { 75, 165 }, // English/Netherlands
+ { 75, 167 }, // English/New Zealand
+ { 75, 169 }, // English/Nigeria
+ { 75, 171 }, // English/Niue
+ { 75, 172 }, // English/Norfolk Island
+ { 75, 173 }, // English/Northern Mariana Islands
+ { 75, 178 }, // English/Pakistan
+ { 75, 179 }, // English/Palau
+ { 75, 182 }, // English/Papua New Guinea
+ { 75, 185 }, // English/Philippines
+ { 75, 186 }, // English/Pitcairn
+ { 75, 189 }, // English/Puerto Rico
+ { 75, 194 }, // English/Rwanda
+ { 75, 196 }, // English/Saint Helena
+ { 75, 197 }, // English/Saint Kitts and Nevis
+ { 75, 198 }, // English/Saint Lucia
+ { 75, 201 }, // English/Saint Vincent and Grenadines
+ { 75, 202 }, // English/Samoa
+ { 75, 208 }, // English/Seychelles
+ { 75, 209 }, // English/Sierra Leone
+ { 75, 210 }, // English/Singapore
+ { 75, 211 }, // English/Sint Maarten
+ { 75, 213 }, // English/Slovenia
+ { 75, 214 }, // English/Solomon Islands
+ { 75, 216 }, // English/South Africa
+ { 75, 219 }, // English/South Sudan
+ { 75, 222 }, // English/Sudan
+ { 75, 225 }, // English/Sweden
+ { 75, 226 }, // English/Switzerland
+ { 75, 230 }, // English/Tanzania
+ { 75, 234 }, // English/Tokelau
+ { 75, 235 }, // English/Tonga
+ { 75, 236 }, // English/Trinidad and Tobago
+ { 75, 241 }, // English/Turks and Caicos Islands
+ { 75, 242 }, // English/Tuvalu
+ { 75, 243 }, // English/Uganda
+ { 75, 245 }, // English/United Arab Emirates
+ { 75, 246 }, // English/United Kingdom
+ { 75, 247 }, // English/United States Outlying Islands
+ { 75, 249 }, // English/United States Virgin Islands
+ { 75, 252 }, // English/Vanuatu
+ { 75, 258 }, // English/world
+ { 75, 260 }, // English/Zambia
+ { 75, 261 }, // English/Zimbabwe
+ { 76, 193 }, // Erzya/Russia
+ { 77, 258 }, // Esperanto/world
+ { 78, 75 }, // Estonian/Estonia
+ { 79, 92 }, // Ewe/Ghana
+ { 79, 233 }, // Ewe/Togo
+ { 80, 40 }, // Ewondo/Cameroon
+ { 81, 81 }, // Faroese/Faroe Islands
+ { 81, 65 }, // Faroese/Denmark
+ { 83, 185 }, // Filipino/Philippines
+ { 84, 83 }, // Finnish/Finland
+ { 85, 84 }, // French/France
+ { 85, 4 }, // French/Algeria
+ { 85, 23 }, // French/Belgium
+ { 85, 25 }, // French/Benin
+ { 85, 37 }, // French/Burkina Faso
+ { 85, 38 }, // French/Burundi
+ { 85, 40 }, // French/Cameroon
+ { 85, 41 }, // French/Canada
+ { 85, 46 }, // French/Central African Republic
+ { 85, 48 }, // French/Chad
+ { 85, 55 }, // French/Comoros
+ { 85, 56 }, // French/Congo - Brazzaville
+ { 85, 57 }, // French/Congo - Kinshasa
+ { 85, 67 }, // French/Djibouti
+ { 85, 73 }, // French/Equatorial Guinea
+ { 85, 85 }, // French/French Guiana
+ { 85, 86 }, // French/French Polynesia
+ { 85, 88 }, // French/Gabon
+ { 85, 97 }, // French/Guadeloupe
+ { 85, 102 }, // French/Guinea
+ { 85, 104 }, // French/Haiti
+ { 85, 118 }, // French/Ivory Coast
+ { 85, 138 }, // French/Luxembourg
+ { 85, 141 }, // French/Madagascar
+ { 85, 145 }, // French/Mali
+ { 85, 148 }, // French/Martinique
+ { 85, 149 }, // French/Mauritania
+ { 85, 150 }, // French/Mauritius
+ { 85, 151 }, // French/Mayotte
+ { 85, 155 }, // French/Monaco
+ { 85, 159 }, // French/Morocco
+ { 85, 166 }, // French/New Caledonia
+ { 85, 170 }, // French/Niger
+ { 85, 191 }, // French/Reunion
+ { 85, 194 }, // French/Rwanda
+ { 85, 195 }, // French/Saint Barthelemy
+ { 85, 199 }, // French/Saint Martin
+ { 85, 200 }, // French/Saint Pierre and Miquelon
+ { 85, 206 }, // French/Senegal
+ { 85, 208 }, // French/Seychelles
+ { 85, 226 }, // French/Switzerland
+ { 85, 227 }, // French/Syria
+ { 85, 233 }, // French/Togo
+ { 85, 238 }, // French/Tunisia
+ { 85, 252 }, // French/Vanuatu
+ { 85, 256 }, // French/Wallis and Futuna
+ { 86, 117 }, // Friulian/Italy
+ { 87, 206 }, // Fulah/Senegal
+ { 87, 37 }, // Fulah/Burkina Faso
+ { 87, 40 }, // Fulah/Cameroon
+ { 87, 89 }, // Fulah/Gambia
+ { 87, 92 }, // Fulah/Ghana
+ { 87, 101 }, // Fulah/Guinea-Bissau
+ { 87, 102 }, // Fulah/Guinea
+ { 87, 134 }, // Fulah/Liberia
+ { 87, 149 }, // Fulah/Mauritania
+ { 87, 169 }, // Fulah/Nigeria
+ { 87, 170 }, // Fulah/Niger
+ { 87, 209 }, // Fulah/Sierra Leone
+ { 88, 246 }, // Gaelic/United Kingdom
+ { 89, 92 }, // Ga/Ghana
+ { 90, 220 }, // Galician/Spain
+ { 91, 243 }, // Ganda/Uganda
+ { 92, 77 }, // Geez/Ethiopia
+ { 92, 74 }, // Geez/Eritrea
+ { 93, 90 }, // Georgian/Georgia
+ { 94, 91 }, // German/Germany
+ { 94, 16 }, // German/Austria
+ { 94, 23 }, // German/Belgium
+ { 94, 117 }, // German/Italy
+ { 94, 136 }, // German/Liechtenstein
+ { 94, 138 }, // German/Luxembourg
+ { 94, 226 }, // German/Switzerland
+ { 96, 94 }, // Greek/Greece
+ { 96, 63 }, // Greek/Cyprus
+ { 97, 183 }, // Guarani/Paraguay
+ { 98, 110 }, // Gujarati/India
+ { 99, 124 }, // Gusii/Kenya
+ { 101, 169 }, // Hausa/Nigeria
+ { 101, 222 }, // Hausa/Sudan
+ { 101, 92 }, // Hausa/Ghana
+ { 101, 170 }, // Hausa/Niger
+ { 102, 248 }, // Hawaiian/United States
+ { 103, 116 }, // Hebrew/Israel
+ { 105, 110 }, // Hindi/India
+ { 107, 108 }, // Hungarian/Hungary
+ { 108, 109 }, // Icelandic/Iceland
+ { 109, 258 }, // Ido/world
+ { 110, 169 }, // Igbo/Nigeria
+ { 111, 83 }, // Inari Sami/Finland
+ { 112, 111 }, // Indonesian/Indonesia
+ { 114, 258 }, // Interlingua/world
+ { 115, 75 }, // Interlingue/Estonia
+ { 116, 41 }, // Inuktitut/Canada
+ { 118, 114 }, // Irish/Ireland
+ { 118, 246 }, // Irish/United Kingdom
+ { 119, 117 }, // Italian/Italy
+ { 119, 203 }, // Italian/San Marino
+ { 119, 226 }, // Italian/Switzerland
+ { 119, 253 }, // Italian/Vatican City
+ { 120, 120 }, // Japanese/Japan
+ { 121, 111 }, // Javanese/Indonesia
+ { 122, 169 }, // Jju/Nigeria
+ { 123, 206 }, // Jola-Fonyi/Senegal
+ { 124, 43 }, // Kabuverdianu/Cape Verde
+ { 125, 4 }, // Kabyle/Algeria
+ { 126, 40 }, // Kako/Cameroon
+ { 127, 95 }, // Kalaallisut/Greenland
+ { 128, 124 }, // Kalenjin/Kenya
+ { 129, 124 }, // Kamba/Kenya
+ { 130, 110 }, // Kannada/India
+ { 132, 110 }, // Kashmiri/India
+ { 133, 123 }, // Kazakh/Kazakhstan
+ { 134, 40 }, // Kenyang/Cameroon
+ { 135, 39 }, // Khmer/Cambodia
+ { 136, 99 }, // Kiche/Guatemala
+ { 137, 124 }, // Kikuyu/Kenya
+ { 138, 194 }, // Kinyarwanda/Rwanda
+ { 141, 110 }, // Konkani/India
+ { 142, 218 }, // Korean/South Korea
+ { 142, 50 }, // Korean/China
+ { 142, 174 }, // Korean/North Korea
+ { 144, 145 }, // Koyraboro Senni/Mali
+ { 145, 145 }, // Koyra Chiini/Mali
+ { 146, 134 }, // Kpelle/Liberia
+ { 146, 102 }, // Kpelle/Guinea
+ { 148, 239 }, // Kurdish/Turkey
+ { 149, 40 }, // Kwasio/Cameroon
+ { 150, 128 }, // Kyrgyz/Kyrgyzstan
+ { 151, 248 }, // Lakota/United States
+ { 152, 230 }, // Langi/Tanzania
+ { 153, 129 }, // Lao/Laos
+ { 154, 253 }, // Latin/Vatican City
+ { 155, 131 }, // Latvian/Latvia
+ { 158, 57 }, // Lingala/Congo - Kinshasa
+ { 158, 7 }, // Lingala/Angola
+ { 158, 46 }, // Lingala/Central African Republic
+ { 158, 56 }, // Lingala/Congo - Brazzaville
+ { 160, 137 }, // Lithuanian/Lithuania
+ { 161, 258 }, // Lojban/world
+ { 162, 91 }, // Lower Sorbian/Germany
+ { 163, 91 }, // Low German/Germany
+ { 163, 165 }, // Low German/Netherlands
+ { 164, 57 }, // Luba-Katanga/Congo - Kinshasa
+ { 165, 225 }, // Lule Sami/Sweden
+ { 165, 175 }, // Lule Sami/Norway
+ { 166, 124 }, // Luo/Kenya
+ { 167, 138 }, // Luxembourgish/Luxembourg
+ { 168, 124 }, // Luyia/Kenya
+ { 169, 140 }, // Macedonian/Macedonia
+ { 170, 230 }, // Machame/Tanzania
+ { 171, 110 }, // Maithili/India
+ { 172, 160 }, // Makhuwa-Meetto/Mozambique
+ { 173, 230 }, // Makonde/Tanzania
+ { 174, 141 }, // Malagasy/Madagascar
+ { 175, 110 }, // Malayalam/India
+ { 176, 143 }, // Malay/Malaysia
+ { 176, 35 }, // Malay/Brunei
+ { 176, 111 }, // Malay/Indonesia
+ { 176, 210 }, // Malay/Singapore
+ { 177, 146 }, // Maltese/Malta
+ { 179, 110 }, // Manipuri/India
+ { 180, 115 }, // Manx/Isle of Man
+ { 181, 167 }, // Maori/New Zealand
+ { 182, 49 }, // Mapuche/Chile
+ { 183, 110 }, // Marathi/India
+ { 185, 124 }, // Masai/Kenya
+ { 185, 230 }, // Masai/Tanzania
+ { 186, 112 }, // Mazanderani/Iran
+ { 188, 124 }, // Meru/Kenya
+ { 189, 40 }, // Meta/Cameroon
+ { 190, 41 }, // Mohawk/Canada
+ { 191, 156 }, // Mongolian/Mongolia
+ { 191, 50 }, // Mongolian/China
+ { 192, 150 }, // Morisyen/Mauritius
+ { 193, 40 }, // Mundang/Cameroon
+ { 194, 248 }, // Muscogee/United States
+ { 195, 162 }, // Nama/Namibia
+ { 197, 248 }, // Navajo/United States
+ { 199, 164 }, // Nepali/Nepal
+ { 199, 110 }, // Nepali/India
+ { 201, 40 }, // Ngiemboon/Cameroon
+ { 202, 40 }, // Ngomba/Cameroon
+ { 203, 169 }, // Nigerian Pidgin/Nigeria
+ { 204, 102 }, // Nko/Guinea
+ { 205, 112 }, // Northern Luri/Iran
+ { 205, 113 }, // Northern Luri/Iraq
+ { 206, 175 }, // Northern Sami/Norway
+ { 206, 83 }, // Northern Sami/Finland
+ { 206, 225 }, // Northern Sami/Sweden
+ { 207, 216 }, // Northern Sotho/South Africa
+ { 208, 261 }, // North Ndebele/Zimbabwe
+ { 209, 175 }, // Norwegian Bokmal/Norway
+ { 209, 224 }, // Norwegian Bokmal/Svalbard and Jan Mayen
+ { 210, 175 }, // Norwegian Nynorsk/Norway
+ { 211, 219 }, // Nuer/South Sudan
+ { 212, 142 }, // Nyanja/Malawi
+ { 213, 243 }, // Nyankole/Uganda
+ { 214, 84 }, // Occitan/France
+ { 214, 220 }, // Occitan/Spain
+ { 215, 110 }, // Odia/India
+ { 220, 77 }, // Oromo/Ethiopia
+ { 220, 124 }, // Oromo/Kenya
+ { 221, 248 }, // Osage/United States
+ { 222, 90 }, // Ossetic/Georgia
+ { 222, 193 }, // Ossetic/Russia
+ { 226, 62 }, // Papiamento/Curacao
+ { 226, 13 }, // Papiamento/Aruba
+ { 227, 1 }, // Pashto/Afghanistan
+ { 227, 178 }, // Pashto/Pakistan
+ { 228, 112 }, // Persian/Iran
+ { 228, 1 }, // Persian/Afghanistan
+ { 230, 187 }, // Polish/Poland
+ { 231, 32 }, // Portuguese/Brazil
+ { 231, 7 }, // Portuguese/Angola
+ { 231, 43 }, // Portuguese/Cape Verde
+ { 231, 73 }, // Portuguese/Equatorial Guinea
+ { 231, 101 }, // Portuguese/Guinea-Bissau
+ { 231, 138 }, // Portuguese/Luxembourg
+ { 231, 139 }, // Portuguese/Macao
+ { 231, 160 }, // Portuguese/Mozambique
+ { 231, 188 }, // Portuguese/Portugal
+ { 231, 204 }, // Portuguese/Sao Tome and Principe
+ { 231, 226 }, // Portuguese/Switzerland
+ { 231, 232 }, // Portuguese/Timor-Leste
+ { 232, 187 }, // Prussian/Poland
+ { 233, 110 }, // Punjabi/India
+ { 233, 178 }, // Punjabi/Pakistan
+ { 234, 184 }, // Quechua/Peru
+ { 234, 28 }, // Quechua/Bolivia
+ { 234, 70 }, // Quechua/Ecuador
+ { 235, 192 }, // Romanian/Romania
+ { 235, 154 }, // Romanian/Moldova
+ { 236, 226 }, // Romansh/Switzerland
+ { 237, 230 }, // Rombo/Tanzania
+ { 238, 38 }, // Rundi/Burundi
+ { 239, 193 }, // Russian/Russia
+ { 239, 22 }, // Russian/Belarus
+ { 239, 123 }, // Russian/Kazakhstan
+ { 239, 128 }, // Russian/Kyrgyzstan
+ { 239, 154 }, // Russian/Moldova
+ { 239, 244 }, // Russian/Ukraine
+ { 240, 230 }, // Rwa/Tanzania
+ { 241, 74 }, // Saho/Eritrea
+ { 242, 193 }, // Sakha/Russia
+ { 243, 124 }, // Samburu/Kenya
+ { 245, 46 }, // Sango/Central African Republic
+ { 246, 230 }, // Sangu/Tanzania
+ { 247, 110 }, // Sanskrit/India
+ { 248, 110 }, // Santali/India
+ { 249, 117 }, // Sardinian/Italy
+ { 251, 160 }, // Sena/Mozambique
+ { 252, 207 }, // Serbian/Serbia
+ { 252, 29 }, // Serbian/Bosnia and Herzegovina
+ { 252, 126 }, // Serbian/Kosovo
+ { 252, 157 }, // Serbian/Montenegro
+ { 253, 230 }, // Shambala/Tanzania
+ { 254, 261 }, // Shona/Zimbabwe
+ { 255, 50 }, // Sichuan Yi/China
+ { 256, 117 }, // Sicilian/Italy
+ { 257, 77 }, // Sidamo/Ethiopia
+ { 258, 187 }, // Silesian/Poland
+ { 259, 178 }, // Sindhi/Pakistan
+ { 259, 110 }, // Sindhi/India
+ { 260, 221 }, // Sinhala/Sri Lanka
+ { 261, 83 }, // Skolt Sami/Finland
+ { 262, 212 }, // Slovak/Slovakia
+ { 263, 213 }, // Slovenian/Slovenia
+ { 264, 243 }, // Soga/Uganda
+ { 265, 215 }, // Somali/Somalia
+ { 265, 67 }, // Somali/Djibouti
+ { 265, 77 }, // Somali/Ethiopia
+ { 265, 124 }, // Somali/Kenya
+ { 266, 112 }, // Southern Kurdish/Iran
+ { 266, 113 }, // Southern Kurdish/Iraq
+ { 267, 225 }, // Southern Sami/Sweden
+ { 267, 175 }, // Southern Sami/Norway
+ { 268, 216 }, // Southern Sotho/South Africa
+ { 268, 133 }, // Southern Sotho/Lesotho
+ { 269, 216 }, // South Ndebele/South Africa
+ { 270, 220 }, // Spanish/Spain
+ { 270, 11 }, // Spanish/Argentina
+ { 270, 24 }, // Spanish/Belize
+ { 270, 28 }, // Spanish/Bolivia
+ { 270, 32 }, // Spanish/Brazil
+ { 270, 42 }, // Spanish/Canary Islands
+ { 270, 47 }, // Spanish/Ceuta and Melilla
+ { 270, 49 }, // Spanish/Chile
+ { 270, 54 }, // Spanish/Colombia
+ { 270, 59 }, // Spanish/Costa Rica
+ { 270, 61 }, // Spanish/Cuba
+ { 270, 69 }, // Spanish/Dominican Republic
+ { 270, 70 }, // Spanish/Ecuador
+ { 270, 72 }, // Spanish/El Salvador
+ { 270, 73 }, // Spanish/Equatorial Guinea
+ { 270, 99 }, // Spanish/Guatemala
+ { 270, 106 }, // Spanish/Honduras
+ { 270, 130 }, // Spanish/Latin America
+ { 270, 152 }, // Spanish/Mexico
+ { 270, 168 }, // Spanish/Nicaragua
+ { 270, 181 }, // Spanish/Panama
+ { 270, 183 }, // Spanish/Paraguay
+ { 270, 184 }, // Spanish/Peru
+ { 270, 185 }, // Spanish/Philippines
+ { 270, 189 }, // Spanish/Puerto Rico
+ { 270, 248 }, // Spanish/United States
+ { 270, 250 }, // Spanish/Uruguay
+ { 270, 254 }, // Spanish/Venezuela
+ { 271, 159 }, // Standard Moroccan Tamazight/Morocco
+ { 272, 111 }, // Sundanese/Indonesia
+ { 273, 230 }, // Swahili/Tanzania
+ { 273, 57 }, // Swahili/Congo - Kinshasa
+ { 273, 124 }, // Swahili/Kenya
+ { 273, 243 }, // Swahili/Uganda
+ { 274, 216 }, // Swati/South Africa
+ { 274, 76 }, // Swati/Eswatini
+ { 275, 225 }, // Swedish/Sweden
+ { 275, 2 }, // Swedish/Aland Islands
+ { 275, 83 }, // Swedish/Finland
+ { 276, 226 }, // Swiss German/Switzerland
+ { 276, 84 }, // Swiss German/France
+ { 276, 136 }, // Swiss German/Liechtenstein
+ { 277, 113 }, // Syriac/Iraq
+ { 277, 227 }, // Syriac/Syria
+ { 278, 159 }, // Tachelhit/Morocco
+ { 280, 255 }, // Tai Dam/Vietnam
+ { 281, 124 }, // Taita/Kenya
+ { 282, 229 }, // Tajik/Tajikistan
+ { 283, 110 }, // Tamil/India
+ { 283, 143 }, // Tamil/Malaysia
+ { 283, 210 }, // Tamil/Singapore
+ { 283, 221 }, // Tamil/Sri Lanka
+ { 284, 228 }, // Taroko/Taiwan
+ { 285, 170 }, // Tasawaq/Niger
+ { 286, 193 }, // Tatar/Russia
+ { 287, 110 }, // Telugu/India
+ { 288, 243 }, // Teso/Uganda
+ { 288, 124 }, // Teso/Kenya
+ { 289, 231 }, // Thai/Thailand
+ { 290, 50 }, // Tibetan/China
+ { 290, 110 }, // Tibetan/India
+ { 291, 74 }, // Tigre/Eritrea
+ { 292, 77 }, // Tigrinya/Ethiopia
+ { 292, 74 }, // Tigrinya/Eritrea
+ { 294, 182 }, // Tok Pisin/Papua New Guinea
+ { 295, 235 }, // Tongan/Tonga
+ { 296, 216 }, // Tsonga/South Africa
+ { 297, 216 }, // Tswana/South Africa
+ { 297, 30 }, // Tswana/Botswana
+ { 298, 239 }, // Turkish/Turkey
+ { 298, 63 }, // Turkish/Cyprus
+ { 299, 240 }, // Turkmen/Turkmenistan
+ { 301, 169 }, // Tyap/Nigeria
+ { 303, 244 }, // Ukrainian/Ukraine
+ { 304, 91 }, // Upper Sorbian/Germany
+ { 305, 178 }, // Urdu/Pakistan
+ { 305, 110 }, // Urdu/India
+ { 306, 50 }, // Uyghur/China
+ { 307, 251 }, // Uzbek/Uzbekistan
+ { 307, 1 }, // Uzbek/Afghanistan
+ { 308, 134 }, // Vai/Liberia
+ { 309, 216 }, // Venda/South Africa
+ { 310, 255 }, // Vietnamese/Vietnam
+ { 311, 258 }, // Volapuk/world
+ { 312, 230 }, // Vunjo/Tanzania
+ { 313, 23 }, // Walloon/Belgium
+ { 314, 226 }, // Walser/Switzerland
+ { 315, 15 }, // Warlpiri/Australia
+ { 316, 246 }, // Welsh/United Kingdom
+ { 317, 178 }, // Western Balochi/Pakistan
+ { 317, 1 }, // Western Balochi/Afghanistan
+ { 317, 112 }, // Western Balochi/Iran
+ { 317, 176 }, // Western Balochi/Oman
+ { 317, 245 }, // Western Balochi/United Arab Emirates
+ { 318, 165 }, // Western Frisian/Netherlands
+ { 319, 77 }, // Wolaytta/Ethiopia
+ { 320, 206 }, // Wolof/Senegal
+ { 321, 216 }, // Xhosa/South Africa
+ { 322, 40 }, // Yangben/Cameroon
+ { 323, 244 }, // Yiddish/Ukraine
+ { 324, 169 }, // Yoruba/Nigeria
+ { 324, 25 }, // Yoruba/Benin
+ { 325, 170 }, // Zarma/Niger
+ { 326, 50 }, // Zhuang/China
+ { 327, 216 }, // Zulu/South Africa
+ { 328, 32 }, // Kaingang/Brazil
+ { 329, 32 }, // Nheengatu/Brazil
+ { 329, 54 }, // Nheengatu/Colombia
+ { 329, 254 }, // Nheengatu/Venezuela
+ { 330, 110 }, // Haryanvi/India
+ { 331, 91 }, // Northern Frisian/Germany
+ { 332, 110 }, // Rajasthani/India
+ { 333, 193 }, // Moksha/Russia
+ { 334, 258 }, // Toki Pona/world
+ { 335, 214 }, // Pijin/Solomon Islands
+ { 336, 169 }, // Obolo/Nigeria
+ { 337, 178 }, // Baluchi/Pakistan
+ { 338, 117 }, // Ligurian/Italy
+ { 339, 161 }, // Rohingya/Myanmar
+ { 339, 20 }, // Rohingya/Bangladesh
+ { 340, 178 }, // Torwali/Pakistan
+ { 341, 25 }, // Anii/Benin
+ { 342, 110 }, // Kangri/India
+ { 343, 117 }, // Venetian/Italy
};
-static const int g_locale_list_count = sizeof(g_locale_list)/sizeof(g_locale_list[0]);
+
+// GENERATED PART ENDS HERE
+
+static const int g_locale_list_count = std::size(g_locale_list);
LocaleModel::LocaleModel(QObject *parent)
: QAbstractItemModel(parent)
@@ -258,7 +680,7 @@ LocaleModel::LocaleModel(QObject *parent)
QVariant LocaleModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()
- || role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ToolTipRole
+ || (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ToolTipRole)
|| index.column() >= g_model_cols
|| index.row() >= g_locale_list_count + 2)
return QVariant();
@@ -399,9 +821,9 @@ int LocaleModel::rowCount(const QModelIndex &parent) const
Qt::ItemFlags LocaleModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
- return 0;
+ return {};
if (index.row() == 0 && index.column() == g_model_cols - 1)
- return 0;
+ return {};
if (index.row() == 0)
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
return QAbstractItemModel::flags(index);
@@ -413,7 +835,7 @@ bool LocaleModel::setData(const QModelIndex &index, const QVariant &value, int r
|| index.row() != 0
|| index.column() >= g_model_cols - 1
|| role != Qt::EditRole
- || m_data_list.at(index.column()).type() != value.type())
+ || m_data_list.at(index.column()).typeId() != value.typeId())
return false;
m_data_list[index.column()] = value;
diff --git a/util/locale_database/testlocales/localemodel.h b/util/locale_database/testlocales/localemodel.h
index 666ea8493d..a0ba45bb15 100644
--- a/util/locale_database/testlocales/localemodel.h
+++ b/util/locale_database/testlocales/localemodel.h
@@ -13,17 +13,17 @@ class LocaleModel : public QAbstractItemModel
public:
LocaleModel(QObject *parent = nullptr);
- virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
- virtual QModelIndex index(int row, int column,
- const QModelIndex &parent = QModelIndex()) const;
- virtual QModelIndex parent(const QModelIndex &index) const;
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
- virtual QVariant headerData(int section, Qt::Orientation orientation,
- int role = Qt::DisplayRole ) const;
- virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- virtual bool setData(const QModelIndex &index, const QVariant &value,
- int role = Qt::EditRole);
+ 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;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole ) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ bool setData(const QModelIndex &index, const QVariant &value,
+ int role = Qt::EditRole) override;
private:
QList<QVariant> m_data_list;
};
diff --git a/util/locale_database/testlocales/localewidget.cpp b/util/locale_database/testlocales/localewidget.cpp
index c35c3dc1d8..df8a3c28ab 100644
--- a/util/locale_database/testlocales/localewidget.cpp
+++ b/util/locale_database/testlocales/localewidget.cpp
@@ -26,26 +26,26 @@ public:
class EditorFactory : public QItemEditorFactory
{
public:
- EditorFactory() {
- static DoubleEditorCreator double_editor_creator;
- registerEditor(QVariant::Double, &double_editor_creator);
+ EditorFactory()
+ {
+ // registerEditor() assumes ownership of the creator.
+ registerEditor(QVariant::Double, new DoubleEditorCreator);
}
};
LocaleWidget::LocaleWidget(QWidget *parent)
- : QWidget(parent)
+ : QWidget(parent),
+ m_model(new LocaleModel(this)),
+ m_view(new QTableView(this))
{
- m_model = new LocaleModel(this);
- m_view = new QTableView(this);
-
QStyledItemDelegate *delegate = qobject_cast<QStyledItemDelegate*>(m_view->itemDelegate());
Q_ASSERT(delegate != 0);
- static EditorFactory editor_factory;
- delegate->setItemEditorFactory(&editor_factory);
+ static EditorFactory editorFactory;
+ delegate->setItemEditorFactory(&editorFactory);
m_view->setModel(m_model);
QVBoxLayout *layout = new QVBoxLayout(this);
- layout->setMargin(0);
+ layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_view);
}
diff --git a/util/locale_database/testlocales/testlocales.pro b/util/locale_database/testlocales/testlocales.pro
index a9a6247f96..126c19589b 100644
--- a/util/locale_database/testlocales/testlocales.pro
+++ b/util/locale_database/testlocales/testlocales.pro
@@ -1,4 +1,5 @@
TARGET = testlocales
CONFIG += debug
+QT += widgets
SOURCES += localemodel.cpp localewidget.cpp main.cpp
-HEADERS += localemodel.h localewidget.h \ No newline at end of file
+HEADERS += localemodel.h localewidget.h
diff --git a/util/locale_database/zonedata.py b/util/locale_database/zonedata.py
new file mode 100644
index 0000000000..bf32038801
--- /dev/null
+++ b/util/locale_database/zonedata.py
@@ -0,0 +1,233 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+"""Data relating to timezones and CLDR.
+
+This is not implicated in public APIs, so may safely be changed.
+Contrast the enumdata.py, where public API is implicated.
+
+Scripts digesting CLDR data shall report the updates you need to make,
+if any arise.
+
+The windowsIdList is a list of twoples (ID, offset), associating each
+Windows-specific ID for a zone with that zone's offset from UTC, in
+seconds. Entries are sorted in case-insensitive lexical order by
+ID. If a script reports that it has found a Windows ID not listed
+here, research the relevant zone's offset and add a new entry to the
+list of twoples, preserving the ordering. Internet search engines and
+timeanddate.com can help with researching the offset. Note that some
+UTC offset zones (giving only the hour) are present in windowsIdList.
+
+The utcIdList is again a list of tuples (name, offset), associating
+various UTC-offset names with their offsets in seconds. Aside from
+'UTC' itself, shared with windowsIdList, these include minutes in
+their offsets even when they are whole hour offsets. It is not clear
+where this particular list of offsets came from, but entries should
+not be removed as they make up the available zones of the UTC
+back-end. (That recognizes other offset zones, and its is-available
+check will accept them, but it leaves them out of its list. There are,
+after all, thousands of possible offset zones, but relatively few are
+widely used.)
+
+Note: -00:00 (without the UTC prefix) was introduced in RFC3339 as a
+way to indicate that a date-time has been converted to UTC but its use
+should not be understood to say anything about the local time of the
+origin of the message using it. However, ISO 8601 has, since 2000,
+forbidden this as an offset suffix. The more recent compromise is to
+use Z to convey the meaning RFC3339 gave to -00:00. So the use of
+-00:00 as offset suffix should be avoided (and, by extension, likewise
+for UTC-00:00 as a zone ID), but this suffix (and ID) should be
+recognized when consuming data generated by other sources, for
+backwards compatibility.
+
+"""
+
+# Do not remove IDs, as each entry is part of the API/behavior guarantee.
+# IDs for the same offset shall be space-joined; list the preferred ID first.
+# ( UTC Id, Offset Seconds )
+utcIdList = (
+ ('UTC-14:00', -50400),
+ ('UTC-13:00', -46800),
+ ('UTC-12:00', -43200),
+ ('UTC-11:00', -39600),
+ ('UTC-10:00', -36000),
+ ('UTC-09:00', -32400),
+ ('UTC-08:00', -28800),
+ ('UTC-07:00', -25200),
+ ('UTC-06:00', -21600),
+ ('UTC-05:00', -18000),
+ ('UTC-04:30', -16200),
+ ('UTC-04:00', -14400),
+ ('UTC-03:30', -12600),
+ ('UTC-03:00', -10800),
+ ('UTC-02:00', -7200),
+ ('UTC-01:00', -3600),
+ ('UTC', 0), # Goes first (among zero-offset) to be default
+ ('UTC+00:00', 0),
+ ('UTC-00:00', 0), # Should recognize, but avoid using (see Note above).
+ ('UTC+01:00', 3600),
+ ('UTC+02:00', 7200),
+ ('UTC+03:00', 10800),
+ ('UTC+03:30', 12600),
+ ('UTC+04:00', 14400),
+ ('UTC+04:30', 16200),
+ ('UTC+05:00', 18000),
+ ('UTC+05:30', 19800),
+ ('UTC+05:45', 20700),
+ ('UTC+06:00', 21600),
+ ('UTC+06:30', 23400),
+ ('UTC+07:00', 25200),
+ ('UTC+08:00', 28800),
+ ('UTC+08:30', 30600),
+ ('UTC+09:00', 32400),
+ ('UTC+09:30', 34200),
+ ('UTC+10:00', 36000),
+ ('UTC+11:00', 39600),
+ ('UTC+12:00', 43200),
+ ('UTC+13:00', 46800),
+ ('UTC+14:00', 50400),
+)
+
+# ( Windows Id, Offset Seconds )
+windowsIdList = (
+ ('Afghanistan Standard Time', 16200),
+ ('Alaskan Standard Time', -32400),
+ ('Aleutian Standard Time', -36000),
+ ('Altai Standard Time', 25200),
+ ('Arab Standard Time', 10800),
+ ('Arabian Standard Time', 14400),
+ ('Arabic Standard Time', 10800),
+ ('Argentina Standard Time', -10800),
+ ('Astrakhan Standard Time', 14400),
+ ('Atlantic Standard Time', -14400),
+ ('AUS Central Standard Time', 34200),
+ ('Aus Central W. Standard Time', 31500),
+ ('AUS Eastern Standard Time', 36000),
+ ('Azerbaijan Standard Time', 14400),
+ ('Azores Standard Time', -3600),
+ ('Bahia Standard Time', -10800),
+ ('Bangladesh Standard Time', 21600),
+ ('Belarus Standard Time', 10800),
+ ('Bougainville Standard Time', 39600),
+ ('Canada Central Standard Time', -21600),
+ ('Cape Verde Standard Time', -3600),
+ ('Caucasus Standard Time', 14400),
+ ('Cen. Australia Standard Time', 34200),
+ ('Central America Standard Time', -21600),
+ ('Central Asia Standard Time', 21600),
+ ('Central Brazilian Standard Time', -14400),
+ ('Central Europe Standard Time', 3600),
+ ('Central European Standard Time', 3600),
+ ('Central Pacific Standard Time', 39600),
+ ('Central Standard Time', -21600),
+ ('Central Standard Time (Mexico)', -21600),
+ ('Chatham Islands Standard Time', 45900),
+ ('China Standard Time', 28800),
+ ('Cuba Standard Time', -18000),
+ ('Dateline Standard Time', -43200),
+ ('E. Africa Standard Time', 10800),
+ ('E. Australia Standard Time', 36000),
+ ('E. Europe Standard Time', 7200),
+ ('E. South America Standard Time', -10800),
+ ('Easter Island Standard Time', -21600),
+ ('Eastern Standard Time', -18000),
+ ('Eastern Standard Time (Mexico)', -18000),
+ ('Egypt Standard Time', 7200),
+ ('Ekaterinburg Standard Time', 18000),
+ ('Fiji Standard Time', 43200),
+ ('FLE Standard Time', 7200),
+ ('Georgian Standard Time', 14400),
+ ('GMT Standard Time', 0),
+ ('Greenland Standard Time', -10800),
+ ('Greenwich Standard Time', 0),
+ ('GTB Standard Time', 7200),
+ ('Haiti Standard Time', -18000),
+ ('Hawaiian Standard Time', -36000),
+ ('India Standard Time', 19800),
+ ('Iran Standard Time', 12600),
+ ('Israel Standard Time', 7200),
+ ('Jordan Standard Time', 7200),
+ ('Kaliningrad Standard Time', 7200),
+ ('Korea Standard Time', 32400),
+ ('Libya Standard Time', 7200),
+ ('Line Islands Standard Time', 50400),
+ ('Lord Howe Standard Time', 37800),
+ ('Magadan Standard Time', 36000),
+ ('Magallanes Standard Time', -10800), # permanent DST
+ ('Marquesas Standard Time', -34200),
+ ('Mauritius Standard Time', 14400),
+ ('Middle East Standard Time', 7200),
+ ('Montevideo Standard Time', -10800),
+ ('Morocco Standard Time', 0),
+ ('Mountain Standard Time', -25200),
+ ('Mountain Standard Time (Mexico)', -25200),
+ ('Myanmar Standard Time', 23400),
+ ('N. Central Asia Standard Time', 21600),
+ ('Namibia Standard Time', 3600),
+ ('Nepal Standard Time', 20700),
+ ('New Zealand Standard Time', 43200),
+ ('Newfoundland Standard Time', -12600),
+ ('Norfolk Standard Time', 39600),
+ ('North Asia East Standard Time', 28800),
+ ('North Asia Standard Time', 25200),
+ ('North Korea Standard Time', 30600),
+ ('Omsk Standard Time', 21600),
+ ('Pacific SA Standard Time', -10800),
+ ('Pacific Standard Time', -28800),
+ ('Pacific Standard Time (Mexico)', -28800),
+ ('Pakistan Standard Time', 18000),
+ ('Paraguay Standard Time', -14400),
+ ('Qyzylorda Standard Time', 18000), # a.k.a. Kyzylorda, in Kazakhstan
+ ('Romance Standard Time', 3600),
+ ('Russia Time Zone 10', 39600),
+ ('Russia Time Zone 11', 43200),
+ ('Russia Time Zone 3', 14400),
+ ('Russian Standard Time', 10800),
+ ('SA Eastern Standard Time', -10800),
+ ('SA Pacific Standard Time', -18000),
+ ('SA Western Standard Time', -14400),
+ ('Saint Pierre Standard Time', -10800), # New France
+ ('Sakhalin Standard Time', 39600),
+ ('Samoa Standard Time', 46800),
+ ('Sao Tome Standard Time', 0),
+ ('Saratov Standard Time', 14400),
+ ('SE Asia Standard Time', 25200),
+ ('Singapore Standard Time', 28800),
+ ('South Africa Standard Time', 7200),
+ ('South Sudan Standard Time', 7200),
+ ('Sri Lanka Standard Time', 19800),
+ ('Sudan Standard Time', 7200), # unless they mean South Sudan, +03:00
+ ('Syria Standard Time', 7200),
+ ('Taipei Standard Time', 28800),
+ ('Tasmania Standard Time', 36000),
+ ('Tocantins Standard Time', -10800),
+ ('Tokyo Standard Time', 32400),
+ ('Tomsk Standard Time', 25200),
+ ('Tonga Standard Time', 46800),
+ ('Transbaikal Standard Time', 32400), # Yakutsk
+ ('Turkey Standard Time', 7200),
+ ('Turks And Caicos Standard Time', -14400),
+ ('Ulaanbaatar Standard Time', 28800),
+ ('US Eastern Standard Time', -18000),
+ ('US Mountain Standard Time', -25200),
+ ('UTC', 0),
+ # Lexical order: '+' < '-'
+ ('UTC+12', 43200),
+ ('UTC+13', 46800),
+ ('UTC-02', -7200),
+ ('UTC-08', -28800),
+ ('UTC-09', -32400),
+ ('UTC-11', -39600),
+ ('Venezuela Standard Time', -16200),
+ ('Vladivostok Standard Time', 36000),
+ ('Volgograd Standard Time', 14400),
+ ('W. Australia Standard Time', 28800),
+ ('W. Central Africa Standard Time', 3600),
+ ('W. Europe Standard Time', 3600),
+ ('W. Mongolia Standard Time', 25200), # Hovd
+ ('West Asia Standard Time', 18000),
+ ('West Bank Standard Time', 7200),
+ ('West Pacific Standard Time', 36000),
+ ('Yakutsk Standard Time', 32400),
+ ('Yukon Standard Time', -25200), # Non-DST Mountain Standard Time since 2020-11-01
+)
diff --git a/util/unicode/main.cpp b/util/unicode/main.cpp
index 0195c5b970..fb308b7dc0 100644
--- a/util/unicode/main.cpp
+++ b/util/unicode/main.cpp
@@ -3616,7 +3616,7 @@ int main(int, char **)
QByteArray header =
"// Copyright (C) 2020 The Qt Company Ltd.\n"
- "// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only\n"
+ "// SPDX-License-Identifier: Unicode-3.0\n"
"\n";
QByteArray note =