diff options
765 files changed, 23845 insertions, 13948 deletions
diff --git a/.gitignore b/.gitignore index 5f9854a674..14aa3a77a2 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,8 @@ Makefile* *.pro.user* *.qmlproject.user* *.gcov +*.gcda +*.gcno bin/Qt*.dll bin/assistant* bin/designer* @@ -118,6 +120,8 @@ qmake/qmake_pch.pch src/corelib/global/qconfig.cpp src/corelib/global/qconfig.h src/corelib/global/qconfig.h.qmake +src/platformsupport/*_interface.* +src/platformsupport/*_adaptor.* ui_*.h tests/auto/qprocess/test*/*.exe tests/auto/qtcpsocket/stressTest/*.exe @@ -310,6 +314,7 @@ tests/auto/corelib/plugin/quuid/testProcessUniqueness/testProcessUniqueness tests/auto/corelib/io/qlockfile/qlockfiletesthelper/qlockfile_test_helper tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger +tests/auto/dbus/qdbusabstractinterface/test/pinger_interface.* tests/auto/dbus/qdbusinterface/qmyserver/qmyserver tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal tests/auto/network/bearer/qnetworksession/lackey/lackey diff --git a/config.tests/arch/arch.pro b/config.tests/arch/arch.pro index fda4acc601..d89d70b1ee 100644 --- a/config.tests/arch/arch.pro +++ b/config.tests/arch/arch.pro @@ -2,4 +2,3 @@ TARGET = arch SOURCES = arch.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle diff --git a/config.tests/common/avx/avx.pro b/config.tests/common/avx/avx.pro index ba7fd96e43..8d1b9702bc 100644 --- a/config.tests/common/avx/avx.pro +++ b/config.tests/common/avx/avx.pro @@ -1,6 +1,5 @@ SOURCES = avx.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle isEmpty(QMAKE_CFLAGS_AVX):error("This compiler does not support AVX") else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_AVX diff --git a/config.tests/common/avx2/avx2.pro b/config.tests/common/avx2/avx2.pro index 5aa9429d68..927f64efc8 100644 --- a/config.tests/common/avx2/avx2.pro +++ b/config.tests/common/avx2/avx2.pro @@ -1,6 +1,5 @@ SOURCES = avx2.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle isEmpty(QMAKE_CFLAGS_AVX2):error("This compiler does not support AVX2") else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_AVX2 diff --git a/config.tests/common/c++11/c++11.pro b/config.tests/common/c++11/c++11.pro index dd4042b8d6..dbe764ba84 100644 --- a/config.tests/common/c++11/c++11.pro +++ b/config.tests/common/c++11/c++11.pro @@ -1,3 +1,3 @@ SOURCES = c++11.cpp CONFIG += c++11 -CONFIG -= qt app_bundle +CONFIG -= qt diff --git a/config.tests/common/sse2/sse2.pro b/config.tests/common/sse2/sse2.pro index c8d0861170..b4031f13fa 100644 --- a/config.tests/common/sse2/sse2.pro +++ b/config.tests/common/sse2/sse2.pro @@ -1,6 +1,5 @@ SOURCES = sse2.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle isEmpty(QMAKE_CFLAGS_SSE2):error("This compiler does not support SSE2") else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE2 diff --git a/config.tests/common/sse3/sse3.pro b/config.tests/common/sse3/sse3.pro index 90f61d2065..f704c40c75 100644 --- a/config.tests/common/sse3/sse3.pro +++ b/config.tests/common/sse3/sse3.pro @@ -1,6 +1,5 @@ SOURCES = sse3.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle isEmpty(QMAKE_CFLAGS_SSE3):error("This compiler does not support SSE3") else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE3 diff --git a/config.tests/common/sse4_1/sse4_1.pro b/config.tests/common/sse4_1/sse4_1.pro index d92be9dc43..5cc04e7c5c 100644 --- a/config.tests/common/sse4_1/sse4_1.pro +++ b/config.tests/common/sse4_1/sse4_1.pro @@ -1,6 +1,5 @@ SOURCES = sse4_1.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle isEmpty(QMAKE_CFLAGS_SSE4_1):error("This compiler does not support SSE4.1") else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE4_1 diff --git a/config.tests/common/sse4_2/sse4_2.pro b/config.tests/common/sse4_2/sse4_2.pro index 744098dce8..6a04b1f9a5 100644 --- a/config.tests/common/sse4_2/sse4_2.pro +++ b/config.tests/common/sse4_2/sse4_2.pro @@ -1,6 +1,5 @@ SOURCES = sse4_2.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle isEmpty(QMAKE_CFLAGS_SSE4_2):error("This compiler does not support SSE4.2") else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE4_2 diff --git a/config.tests/common/ssse3/ssse3.pro b/config.tests/common/ssse3/ssse3.pro index e3984bd1cd..5b207e78ce 100644 --- a/config.tests/common/ssse3/ssse3.pro +++ b/config.tests/common/ssse3/ssse3.pro @@ -1,6 +1,5 @@ SOURCES = ssse3.cpp CONFIG -= qt dylib release debug_and_release CONFIG += debug console -mac:CONFIG -= app_bundle isEmpty(QMAKE_CFLAGS_SSSE3):error("This compiler does not support SSSE3") else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSSE3 diff --git a/config.tests/mac/coreservices/coreservices.pro b/config.tests/mac/coreservices/coreservices.pro index 6f7c07a487..64936eb974 100644 --- a/config.tests/mac/coreservices/coreservices.pro +++ b/config.tests/mac/coreservices/coreservices.pro @@ -1,3 +1,3 @@ OBJECTIVE_SOURCES = coreservices.mm LIBS += -framework CoreServices -CONFIG -= app_bundle qt +CONFIG -= qt diff --git a/config.tests/mac/corewlan/corewlan.pro b/config.tests/mac/corewlan/corewlan.pro index a9c256043c..8db0c8c1e7 100644 --- a/config.tests/mac/corewlan/corewlan.pro +++ b/config.tests/mac/corewlan/corewlan.pro @@ -1,3 +1,3 @@ OBJECTIVE_SOURCES = corewlantest.mm LIBS += -framework CoreWLAN -framework Foundation -CONFIG -= app_bundle qt +CONFIG -= qt diff --git a/config.tests/qpa/directfb/directfb.pro b/config.tests/qpa/directfb/directfb.pro index 958ced7bea..b138fd0109 100644 --- a/config.tests/qpa/directfb/directfb.pro +++ b/config.tests/qpa/directfb/directfb.pro @@ -1,3 +1,2 @@ SOURCES = directfb.cpp CONFIG -= qt -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/alsa/alsa.pro b/config.tests/unix/alsa/alsa.pro index 4931d38ea8..6d5d55bcfd 100644 --- a/config.tests/unix/alsa/alsa.pro +++ b/config.tests/unix/alsa/alsa.pro @@ -1,4 +1,3 @@ SOURCES = alsatest.cpp LIBS+=-lasound CONFIG -= qt dylib -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/arch.test b/config.tests/unix/arch.test index 3efd6f4f25..529ed5e547 100755 --- a/config.tests/unix/arch.test +++ b/config.tests/unix/arch.test @@ -26,7 +26,7 @@ CXXFLAGS="$SYSROOT_FLAG" test -d "$OUTDIR/config.tests/arch" || mkdir -p "$OUTDIR/config.tests/arch" cd "$OUTDIR/config.tests/arch" [ -f Makefile ] && $MAKE distclean >/dev/null 2>&1 -OUTDIR=$OUTDIR "$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "QT_BUILD_TREE=$OUTDIR" "LIBS+=$LFLAGS" "QMAKE_CXXFLAGS+=$CXXFLAGS" "$SRCDIR/config.tests/arch/arch$PROSUFFIX.pro" >/dev/null 2>&1 || echo "qmake is broken" >&2 +OUTDIR=$OUTDIR "$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "QT_BUILD_TREE=$OUTDIR" "LIBS+=$LFLAGS" "QMAKE_CXXFLAGS+=$CXXFLAGS" "CONFIG-=app_bundle" "$SRCDIR/config.tests/arch/arch$PROSUFFIX.pro" >/dev/null 2>&1 || echo "qmake is broken" >&2 ARCH="" diff --git a/config.tests/unix/clock-gettime/clock-gettime.pro b/config.tests/unix/clock-gettime/clock-gettime.pro index c527535183..bdbb1c2a82 100644 --- a/config.tests/unix/clock-gettime/clock-gettime.pro +++ b/config.tests/unix/clock-gettime/clock-gettime.pro @@ -1,4 +1,3 @@ SOURCES = clock-gettime.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle include(clock-gettime.pri) diff --git a/config.tests/unix/clock-monotonic/clock-monotonic.pro b/config.tests/unix/clock-monotonic/clock-monotonic.pro index 961e3a848d..253a9f7346 100644 --- a/config.tests/unix/clock-monotonic/clock-monotonic.pro +++ b/config.tests/unix/clock-monotonic/clock-monotonic.pro @@ -1,4 +1,3 @@ SOURCES = clock-monotonic.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle include(../clock-gettime/clock-gettime.pri) diff --git a/config.tests/unix/compile.test b/config.tests/unix/compile.test index 6b90044009..22064b85e9 100755 --- a/config.tests/unix/compile.test +++ b/config.tests/unix/compile.test @@ -67,7 +67,7 @@ test -r Makefile && $MAKE distclean >/dev/null 2>&1 # Make sure output from possible previous tests is gone rm -f "$EXE" "${EXE}.exe" -set -- "$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "CONFIG+=$QMAKE_CONFIG" "CONFIG+=android_app" "CONFIG-=debug_and_release" "LIBS*=$LFLAGS" "LIBS+=$MAC_ARCH_LFLAGS" "INCLUDEPATH*=$INCLUDEPATH" "QMAKE_CXXFLAGS*=$CXXFLAGS" "QMAKE_CXXFLAGS+=$MAC_ARCH_CXXFLAGS" "QT_BUILD_TREE=$OUTDIR" "$SRCDIR/$TEST/$EXE.pro" -o "$OUTDIR/$TEST/Makefile" +set -- "$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "CONFIG+=$QMAKE_CONFIG" "CONFIG+=android_app" "CONFIG-=debug_and_release app_bundle lib_bundle" "LIBS*=$LFLAGS" "LIBS+=$MAC_ARCH_LFLAGS" "INCLUDEPATH*=$INCLUDEPATH" "QMAKE_CXXFLAGS*=$CXXFLAGS" "QMAKE_CXXFLAGS+=$MAC_ARCH_CXXFLAGS" "QT_BUILD_TREE=$OUTDIR" "$SRCDIR/$TEST/$EXE.pro" -o "$OUTDIR/$TEST/Makefile" if [ "$VERBOSE" = "yes" ]; then OUTDIR=$OUTDIR "$@" $MAKE diff --git a/config.tests/unix/cups/cups.pro b/config.tests/unix/cups/cups.pro index d7b78c877f..3f8ca99d0f 100644 --- a/config.tests/unix/cups/cups.pro +++ b/config.tests/unix/cups/cups.pro @@ -1,4 +1,3 @@ SOURCES = cups.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lcups diff --git a/config.tests/unix/db2/db2.pro b/config.tests/unix/db2/db2.pro index 0fa39a8242..b7316051f9 100644 --- a/config.tests/unix/db2/db2.pro +++ b/config.tests/unix/db2/db2.pro @@ -1,4 +1,3 @@ SOURCES = db2.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -ldb2 diff --git a/config.tests/unix/dbus/dbus.pro b/config.tests/unix/dbus/dbus.pro index 1e4aea73e4..c2a01ea269 100644 --- a/config.tests/unix/dbus/dbus.pro +++ b/config.tests/unix/dbus/dbus.pro @@ -1,3 +1,2 @@ SOURCES = dbus.cpp CONFIG -= qt -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/eventfd/eventfd.pro b/config.tests/unix/eventfd/eventfd.pro index c41204f49f..de99717750 100644 --- a/config.tests/unix/eventfd/eventfd.pro +++ b/config.tests/unix/eventfd/eventfd.pro @@ -1,3 +1,2 @@ SOURCES = main.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/fontconfig/fontconfig.pro b/config.tests/unix/fontconfig/fontconfig.pro index 5989586751..8360774035 100644 --- a/config.tests/unix/fontconfig/fontconfig.pro +++ b/config.tests/unix/fontconfig/fontconfig.pro @@ -1,4 +1,4 @@ SOURCES = fontconfig.cpp -CONFIG -= qt app_bundle +CONFIG -= qt LIBS += -lfreetype -lfontconfig include(../../unix/freetype/freetype.pri) diff --git a/config.tests/unix/getaddrinfo/getaddrinfo.pro b/config.tests/unix/getaddrinfo/getaddrinfo.pro index c9121db9b4..cc739118fa 100644 --- a/config.tests/unix/getaddrinfo/getaddrinfo.pro +++ b/config.tests/unix/getaddrinfo/getaddrinfo.pro @@ -1,4 +1,3 @@ SOURCES = getaddrinfotest.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += $$QMAKE_LIBS_NETWORK diff --git a/config.tests/unix/getifaddrs/getifaddrs.pro b/config.tests/unix/getifaddrs/getifaddrs.pro index c3fead6354..14a89f87b8 100644 --- a/config.tests/unix/getifaddrs/getifaddrs.pro +++ b/config.tests/unix/getifaddrs/getifaddrs.pro @@ -1,5 +1,4 @@ SOURCES = getifaddrs.cpp CONFIG -= qt -mac:CONFIG -= app_bundle QT = LIBS += $$QMAKE_LIBS_NETWORK diff --git a/config.tests/unix/glib/glib.pro b/config.tests/unix/glib/glib.pro index c7cd53d116..15d059df77 100644 --- a/config.tests/unix/glib/glib.pro +++ b/config.tests/unix/glib/glib.pro @@ -1,2 +1,2 @@ SOURCES = glib.cpp -CONFIG -= qt app_bundle +CONFIG -= qt diff --git a/config.tests/unix/gnu-libiconv/gnu-libiconv.pro b/config.tests/unix/gnu-libiconv/gnu-libiconv.pro index d879b205f1..1ecf94390a 100644 --- a/config.tests/unix/gnu-libiconv/gnu-libiconv.pro +++ b/config.tests/unix/gnu-libiconv/gnu-libiconv.pro @@ -1,4 +1,3 @@ SOURCES = gnu-libiconv.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -liconv diff --git a/config.tests/unix/ibase/ibase.pro b/config.tests/unix/ibase/ibase.pro index 01e7429733..58787851e1 100644 --- a/config.tests/unix/ibase/ibase.pro +++ b/config.tests/unix/ibase/ibase.pro @@ -1,4 +1,3 @@ SOURCES = ibase.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lgds diff --git a/config.tests/unix/iconv/iconv.pro b/config.tests/unix/iconv/iconv.pro index 39375a5714..1ef6aa7207 100644 --- a/config.tests/unix/iconv/iconv.pro +++ b/config.tests/unix/iconv/iconv.pro @@ -1,3 +1,3 @@ SOURCES = iconv.cpp -CONFIG -= qt dylib app_bundle +CONFIG -= qt dylib mac|win32-g++*|qnx:LIBS += -liconv diff --git a/config.tests/unix/icu/icu.pro b/config.tests/unix/icu/icu.pro index 8e583348bb..002c4840d5 100644 --- a/config.tests/unix/icu/icu.pro +++ b/config.tests/unix/icu/icu.pro @@ -1,4 +1,4 @@ SOURCES = icu.cpp -CONFIG -= qt dylib app_bundle +CONFIG -= qt dylib unix:LIBS += -licuuc -licui18n win32:LIBS += -licuin diff --git a/config.tests/unix/inotify/inotify.pro b/config.tests/unix/inotify/inotify.pro index e2e1560a47..35880de3c0 100644 --- a/config.tests/unix/inotify/inotify.pro +++ b/config.tests/unix/inotify/inotify.pro @@ -1,3 +1,2 @@ SOURCES = inotifytest.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/iodbc/iodbc.pro b/config.tests/unix/iodbc/iodbc.pro index 465a9a7a1b..68a0bd0ef4 100644 --- a/config.tests/unix/iodbc/iodbc.pro +++ b/config.tests/unix/iodbc/iodbc.pro @@ -1,4 +1,3 @@ SOURCES = iodbc.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -liodbc diff --git a/config.tests/unix/ipv6ifname/ipv6ifname.pro b/config.tests/unix/ipv6ifname/ipv6ifname.pro index ed62869cb9..88203a782c 100644 --- a/config.tests/unix/ipv6ifname/ipv6ifname.pro +++ b/config.tests/unix/ipv6ifname/ipv6ifname.pro @@ -1,5 +1,4 @@ SOURCES = ipv6ifname.cpp CONFIG -= qt -mac:CONFIG -= app_bundle QT = LIBS += $$QMAKE_LIBS_NETWORK diff --git a/config.tests/unix/libjpeg/libjpeg.pro b/config.tests/unix/libjpeg/libjpeg.pro index d06888c57d..01329a11fe 100644 --- a/config.tests/unix/libjpeg/libjpeg.pro +++ b/config.tests/unix/libjpeg/libjpeg.pro @@ -1,4 +1,3 @@ SOURCES = libjpeg.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -ljpeg diff --git a/config.tests/unix/libpng/libpng.pro b/config.tests/unix/libpng/libpng.pro index f03838663e..4e50fe26e5 100644 --- a/config.tests/unix/libpng/libpng.pro +++ b/config.tests/unix/libpng/libpng.pro @@ -1,4 +1,3 @@ SOURCES = libpng.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lpng diff --git a/config.tests/unix/mremap/mremap.pro b/config.tests/unix/mremap/mremap.pro index a36d756db3..1dbd3b7a7e 100644 --- a/config.tests/unix/mremap/mremap.pro +++ b/config.tests/unix/mremap/mremap.pro @@ -1,3 +1,2 @@ SOURCES = mremap.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/mysql/mysql.pro b/config.tests/unix/mysql/mysql.pro index a22579e1bd..06d1880f08 100644 --- a/config.tests/unix/mysql/mysql.pro +++ b/config.tests/unix/mysql/mysql.pro @@ -1,4 +1,3 @@ SOURCES = mysql.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lmysqlclient diff --git a/config.tests/unix/mysql_r/mysql_r.pro b/config.tests/unix/mysql_r/mysql_r.pro index 8c06067305..096da69487 100644 --- a/config.tests/unix/mysql_r/mysql_r.pro +++ b/config.tests/unix/mysql_r/mysql_r.pro @@ -1,4 +1,3 @@ SOURCES = ../mysql/mysql.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lmysqlclient_r diff --git a/config.tests/unix/nis/nis.pro b/config.tests/unix/nis/nis.pro index 1f985b2049..b7f5693b60 100644 --- a/config.tests/unix/nis/nis.pro +++ b/config.tests/unix/nis/nis.pro @@ -1,5 +1,4 @@ SOURCES = nis.cpp CONFIG -= qt dylib -mac: CONFIG -= app_bundle solaris-*:LIBS += -lnsl else:LIBS += $$QMAKE_LIBS_NIS diff --git a/config.tests/unix/oci/oci.pro b/config.tests/unix/oci/oci.pro index 4add225f5d..3ffda1ddd7 100644 --- a/config.tests/unix/oci/oci.pro +++ b/config.tests/unix/oci/oci.pro @@ -1,4 +1,3 @@ SOURCES = oci.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lclntsh diff --git a/config.tests/unix/odbc/odbc.pro b/config.tests/unix/odbc/odbc.pro index 06a548fd71..418a0e0d54 100644 --- a/config.tests/unix/odbc/odbc.pro +++ b/config.tests/unix/odbc/odbc.pro @@ -1,5 +1,4 @@ SOURCES = odbc.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle win32-g++*:LIBS += -lodbc32 else:LIBS += -lodbc diff --git a/config.tests/unix/opengldesktop/opengldesktop.pro b/config.tests/unix/opengldesktop/opengldesktop.pro index fbf36a0c67..c3e700c50a 100644 --- a/config.tests/unix/opengldesktop/opengldesktop.pro +++ b/config.tests/unix/opengldesktop/opengldesktop.pro @@ -9,4 +9,3 @@ CONFIG -= qt LIBS += $$QMAKE_LIBS_OPENGL mac:DEFINES += Q_OS_MAC -CONFIG -= app_bundle diff --git a/config.tests/unix/opengles1/opengles1.pro b/config.tests/unix/opengles1/opengles1.pro index 9e6012474d..58817e6a6e 100644 --- a/config.tests/unix/opengles1/opengles1.pro +++ b/config.tests/unix/opengles1/opengles1.pro @@ -9,5 +9,4 @@ CONFIG -= qt LIBS += $$QMAKE_LIBS_OPENGL_ES1 mac { DEFINES += BUILD_ON_MAC - CONFIG -= app_bundle } diff --git a/config.tests/unix/opengles2/opengles2.pro b/config.tests/unix/opengles2/opengles2.pro index 34d77371b4..c4d76895a8 100644 --- a/config.tests/unix/opengles2/opengles2.pro +++ b/config.tests/unix/opengles2/opengles2.pro @@ -9,5 +9,4 @@ CONFIG -= qt LIBS += $$QMAKE_LIBS_OPENGL_ES2 mac { DEFINES += BUILD_ON_MAC - CONFIG -= app_bundle } diff --git a/config.tests/unix/openssl/openssl.pro b/config.tests/unix/openssl/openssl.pro index 1c537cb2b1..a023aee4aa 100644 --- a/config.tests/unix/openssl/openssl.pro +++ b/config.tests/unix/openssl/openssl.pro @@ -1,3 +1,2 @@ SOURCES = openssl.cpp CONFIG -= x11 qt -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/pcre/pcre.pro b/config.tests/unix/pcre/pcre.pro index b29c55da47..7b8bfc6545 100644 --- a/config.tests/unix/pcre/pcre.pro +++ b/config.tests/unix/pcre/pcre.pro @@ -1,3 +1,3 @@ SOURCES = pcre.cpp -CONFIG -= qt dylib app_bundle +CONFIG -= qt dylib LIBS += -lpcre16 diff --git a/config.tests/unix/psql/psql.pro b/config.tests/unix/psql/psql.pro index 38bfb3ed70..d0f3761bfb 100644 --- a/config.tests/unix/psql/psql.pro +++ b/config.tests/unix/psql/psql.pro @@ -1,4 +1,3 @@ SOURCES = psql.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS *= -lpq diff --git a/config.tests/unix/ptrsize.test b/config.tests/unix/ptrsize.test index c78c73f7a2..3ad15dbd2b 100755 --- a/config.tests/unix/ptrsize.test +++ b/config.tests/unix/ptrsize.test @@ -10,7 +10,7 @@ OUTDIR=$4 # build and run a test program test -d "$OUTDIR/config.tests/unix/ptrsize" || mkdir -p "$OUTDIR/config.tests/unix/ptrsize" -"$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "QT_BUILD_TREE=$OUTDIR" "$SRCDIR/config.tests/unix/ptrsize/ptrsizetest.pro" -o "$OUTDIR/config.tests/unix/ptrsize/Makefile" >/dev/null 2>&1 +"$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "QT_BUILD_TREE=$OUTDIR" "CONFIG-=app_bundle" "$SRCDIR/config.tests/unix/ptrsize/ptrsizetest.pro" -o "$OUTDIR/config.tests/unix/ptrsize/Makefile" >/dev/null 2>&1 cd "$OUTDIR/config.tests/unix/ptrsize" if [ "$VERBOSE" = "yes" ]; then diff --git a/config.tests/unix/ptrsize/ptrsizetest.pro b/config.tests/unix/ptrsize/ptrsizetest.pro index 41aba86dd9..045a759ec9 100644 --- a/config.tests/unix/ptrsize/ptrsizetest.pro +++ b/config.tests/unix/ptrsize/ptrsizetest.pro @@ -1,3 +1,2 @@ SOURCES = ptrsizetest.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/slog2/slog2.pro b/config.tests/unix/slog2/slog2.pro index 9f5b34d664..e65460bb94 100644 --- a/config.tests/unix/slog2/slog2.pro +++ b/config.tests/unix/slog2/slog2.pro @@ -1,4 +1,3 @@ SOURCES = slog2.cpp CONFIG -= qt -mac:CONFIG -= app_bundle LIBS += -lslog2 diff --git a/config.tests/unix/sqlite/sqlite.pro b/config.tests/unix/sqlite/sqlite.pro index ba2cac1465..4b24e014ba 100644 --- a/config.tests/unix/sqlite/sqlite.pro +++ b/config.tests/unix/sqlite/sqlite.pro @@ -1,3 +1,2 @@ SOURCES = sqlite.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/sqlite2/sqlite2.pro b/config.tests/unix/sqlite2/sqlite2.pro index 14a64d5db9..7e69fdf2f3 100644 --- a/config.tests/unix/sqlite2/sqlite2.pro +++ b/config.tests/unix/sqlite2/sqlite2.pro @@ -1,4 +1,3 @@ SOURCES = sqlite2.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lsqlite diff --git a/config.tests/unix/stdint/stdint.pro b/config.tests/unix/stdint/stdint.pro index 79a0d9cd3a..9975484889 100644 --- a/config.tests/unix/stdint/stdint.pro +++ b/config.tests/unix/stdint/stdint.pro @@ -1,4 +1,3 @@ SOURCES = main.cpp CONFIG -= x11 qt -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/stl/stl.pro b/config.tests/unix/stl/stl.pro index a2feab431c..7303e8d31c 100644 --- a/config.tests/unix/stl/stl.pro +++ b/config.tests/unix/stl/stl.pro @@ -1,3 +1,2 @@ SOURCES = stltest.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle diff --git a/config.tests/unix/sun-libiconv/sun-libiconv.pro b/config.tests/unix/sun-libiconv/sun-libiconv.pro index 00df8653c8..923afc7dd2 100644 --- a/config.tests/unix/sun-libiconv/sun-libiconv.pro +++ b/config.tests/unix/sun-libiconv/sun-libiconv.pro @@ -1,2 +1,2 @@ SOURCES = ../gnu-libiconv/gnu-libiconv.cpp -CONFIG -= qt dylib app_bundle +CONFIG -= qt dylib diff --git a/config.tests/unix/tds/tds.pro b/config.tests/unix/tds/tds.pro index 5516a14c8f..6712779d58 100644 --- a/config.tests/unix/tds/tds.pro +++ b/config.tests/unix/tds/tds.pro @@ -1,4 +1,3 @@ SOURCES = tds.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lsybdb diff --git a/config.tests/unix/zlib/zlib.pro b/config.tests/unix/zlib/zlib.pro index 67cc870516..d9bd03e5df 100644 --- a/config.tests/unix/zlib/zlib.pro +++ b/config.tests/unix/zlib/zlib.pro @@ -1,4 +1,3 @@ SOURCES = zlib.cpp CONFIG -= qt dylib -mac:CONFIG -= app_bundle LIBS += -lz @@ -1518,6 +1518,11 @@ while [ "$#" -gt 0 ]; do QTCONFIG_CONFIG="$QTCONFIG_CONFIG testcocoon" fi ;; + gcov) + if [ "$VAL" = "yes" ]; then + QTCONFIG_CONFIG="$QTCONFIG_CONFIG gcov" + fi + ;; platform) PLATFORM="$VAL" # keep compatibility with old platform names @@ -2457,47 +2462,7 @@ if [ "$OPT_SHADOW" = "yes" ]; then [ -d "$outpath/bin" ] || mkdir -p "$outpath/bin" - # save a pre-existing mkspecs/modules dir - test -d "$outpath/mkspecs/modules" && \ - mv "$outpath/mkspecs/modules" "$outpath/mkspecs-modules" - # ditto for mkspecs/modules-inst - test -d "$outpath/mkspecs/modules-inst" && \ - mv "$outpath/mkspecs/modules-inst" "$outpath/mkspecs-modules-inst" - - # symlink the mkspecs directory mkdir -p "$outpath/mkspecs" - rm -rf "$outpath"/mkspecs/* - ln -s "$relpath"/mkspecs/* "$outpath/mkspecs" - - ShadowMkspecs() - { - rm -rf "$outpath/mkspecs/$1" - find "$relpath/mkspecs/$1" -type d | sed "s,^$relpath,$outpath," | xargs mkdir -p - find "$relpath/mkspecs/$1" -type f | sed "s,^$relpath/,," | while read f; do ln -s "$relpath/$f" "$outpath/$f"; done - } - - # Special case for mkspecs/features directory. - # To be able to place .prf files into a shadow build directory, - # we're creating links for files only. The directory structure is reproduced. - ShadowMkspecs features - - # The modules dir is special, too. - if test -d "$outpath/mkspecs-modules"; then - rm -rf "$outpath/mkspecs/modules" - mv "$outpath/mkspecs-modules" "$outpath/mkspecs/modules" - else - ShadowMkspecs modules - fi - - # The modules-inst dir is not quite as special, but still. - if test -d "$outpath/mkspecs-modules-inst"; then - rm -rf "$outpath/mkspecs/modules-inst" - mv "$outpath/mkspecs-modules-inst" "$outpath/mkspecs/modules-inst" - fi - - # Prepare doc directory - mkdir -p "$outpath/doc" - ln -f -s "$relpath"/doc/global "$outpath/doc" fi # symlink fonts to be able to run application from build directory @@ -2801,9 +2766,9 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then if [ `basename $QMAKESPEC` = "macx-xcode" ] || [ `basename $XQMAKESPEC` = "macx-xcode" ]; then echo >&2 echo " Platform 'macx-xcode' should not be used when building Qt/Mac." >&2 - echo " Please build Qt/Mac with 'macx-g++', then if you would like to" >&2 - echo " use mac-xcode on your application code it can link to a Qt/Mac" >&2 - echo " built with 'macx-g++'" >&2 + echo " Please build Qt/Mac with 'macx-clang' or 'macx-g++', then use" >&2 + echo " the 'macx-xcode' spec for your application, and it will link to" >&2 + echo " the Qt/Mac build using the settings of the original mkspec." >&2 echo >&2 exit 2 fi @@ -2894,7 +2859,7 @@ if [ "$XPLATFORM_IOS" = "yes" ]; then CFG_NOBUILD_PARTS="$CFG_NOBUILD_PARTS examples tests" CFG_SHARED="no" # iOS builds should be static to be able to submit to the App Store CFG_CXX11="no" # C++11 support disabled for now - CFG_SKIP_MODULES="$CFG_SKIP_MODULES qtdeclarative qtquickcontrols qtwebkit qtgraphicaleffects qtdoc qtmultimedia qtwebkit-examples qttools" + CFG_SKIP_MODULES="$CFG_SKIP_MODULES qtquickcontrols qtwebkit qtgraphicaleffects qtdoc qtmultimedia qtwebkit-examples qttools" fi # disable GTK style support auto-detection on Mac @@ -3039,21 +3004,44 @@ else fi # auto-detect default include and library search paths -gccout=`LC_ALL=C $TEST_COMPILER $SYSROOT_FLAG $TEST_COMPILER_CXXFLAGS -xc++ -E -v - < /dev/null 2>&1 > /dev/null` -# extract from one line like 'LIBRARY_PATH=/one/path:/another/path:...' -libdirs=`echo "$gccout" | sed -n -e 's/^LIBRARY_PATH=\(.*\)/\1/p'` -DEFAULT_LIBDIRS=`IFS=${HOST_DIRLIST_SEP}; for i in $libdirs; do test -d "$i" && cd "$i" && pwd; done` -# extract from indented lines between '#include <...> search starts here:' and 'End of search list.' -DEFAULT_INCDIRS=`echo "$gccout" | $AWK ' -/^End of search/ { yup=0 } +unset tty +[ "$OPT_VERBOSE" = "yes" ] && tty=/dev/stderr + +eval `LC_ALL=C $TEST_COMPILER $SYSROOT_FLAG $TEST_COMPILER_CXXFLAGS -xc++ -E -v - < /dev/null 2>&1 > /dev/null | $AWK ' +BEGIN { ORS = ""; FS = "="; incs = 0; libs = 0; } +function quote(s) +{ + # We only handle spaces + if (match(s, " ") != 0) + return "\\\\\"" s "\\\\\""; + return s; +} + +# extract include paths from indented lines between +# #include <...> search starts here: +# and +# End of search list. +/^\#include </ { yup=1; print "DEFAULT_INCDIRS=\""; next } +/^End of search/ { yup=0; print "\"\n" } / \(framework directory\)$/ { next } -yup { print substr($0, 2) } -/^\#include </ { yup=1 } -'` -test -z "$DEFAULT_LIBDIRS" && DEFAULT_LIBDIRS="/lib -/usr/lib" -test -z "$DEFAULT_INCDIRS" && DEFAULT_INCDIRS="/usr/include -/usr/local/include" +yup { print quote(substr($0, 2)) " "; ++incs } + +# extract from one line like LIBRARY_PATH=/one/path:/another/path:... +$1 == "LIBRARY_PATH" { + libs = split($2, library_paths, ":"); + print "DEFAULT_LIBDIRS=\""; + for (lib in library_paths) + print quote(library_paths[lib]) " "; + print "\"\n" +} + +END { + if (incs == 0) + print "DEFAULT_INCDIRS=\"/usr/include /usr/local/include\"\n"; + if (libs == 0) + print "DEFAULT_LIBDIRS=\"/lib /usr/lib\"\n"; +}' | tee $tty` +unset tty #setup the build parts if [ -z "$CFG_BUILD_PARTS" ]; then @@ -3463,6 +3451,7 @@ Configure options: -qtlibinfix <infix> Renames all libQt*.so to libQt*<infix>.so. -testcocoon ........ Instrument Qt with the TestCocoon code coverage tool. + -gcov .............. Instrument Qt with the GCov code coverage tool. -D <string> ........ Add an explicit define to the preprocessor. -I <string> ........ Add an explicit include path. @@ -4124,6 +4113,12 @@ cat > "$QTCONFFILE" <<EOF [EffectivePaths] Prefix=.. EOF +if [ x"$relpath" != x"$outpath" ]; then + cat >> "$QTCONFFILE" <<EOF +[EffectiveSourcePaths] +Prefix=$relpath +EOF +fi #------------------------------------------------------------------------------- # write out device config before we run the test. @@ -4398,8 +4393,7 @@ fi # detect neon support if [ "$CFG_ARCH" = "arm" ] && [ "${CFG_NEON}" = "auto" ]; then - # The iOS toolchain has trouble building the pixman NEON draw-helpers - if [ "$XPLATFORM_IOS" != "yes" ] && compileTest unix/neon "neon"; then + if compileTest unix/neon "neon"; then CFG_NEON=yes else CFG_NEON=no @@ -6534,12 +6528,14 @@ fi cat >>"$QTCONFIG.tmp" <<EOF #configuration CONFIG += $QTCONFIG_CONFIG -QT_ARCH = $CFG_ARCH -QT_HOST_ARCH = $CFG_HOST_ARCH -QT_CPU_FEATURES = $CFG_CPUFEATURES -QT_HOST_CPU_FEATURES = $CFG_HOST_CPUFEATURES -QMAKE_DEFAULT_LIBDIRS = `echo "$DEFAULT_LIBDIRS" | sed 's,^,",;s,$,",' | tr '\n' ' '` -QMAKE_DEFAULT_INCDIRS = `echo "$DEFAULT_INCDIRS" | sed 's,^,",;s,$,",' | tr '\n' ' '` +host_build { + QT_ARCH = $CFG_HOST_ARCH + QT_TARGET_ARCH = $CFG_ARCH +} else { + QT_ARCH = $CFG_ARCH + QMAKE_DEFAULT_LIBDIRS = $DEFAULT_LIBDIRS + QMAKE_DEFAULT_INCDIRS = $DEFAULT_INCDIRS +} QT_EDITION = $Edition QT_CONFIG += $QT_CONFIG @@ -6621,6 +6617,14 @@ if [ -n "$CFG_SKIP_MODULES" ]; then echo "QT_SKIP_MODULES += $CFG_SKIP_MODULES" >> "$QTMODULE.tmp" fi +cat >>"$QTMODULE.tmp" <<EOF +host_build { + QT_CPU_FEATURES.$CFG_HOST_ARCH = $CFG_HOST_CPUFEATURES +} else { + QT_CPU_FEATURES.$CFG_ARCH = $CFG_CPUFEATURES +} +EOF + if [ -n "$QT_CFLAGS_PSQL" ]; then echo "QT_CFLAGS_PSQL = $QT_CFLAGS_PSQL" >> "$QTMODULE.tmp" fi diff --git a/dist/changes-5.2.0 b/dist/changes-5.2.0 new file mode 100644 index 0000000000..89d1a2d8c7 --- /dev/null +++ b/dist/changes-5.2.0 @@ -0,0 +1,45 @@ +Qt 5.2 introduces many new features and improvements as well as bugfixes +over the 5.1.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + + http://qt-project.org/doc/qt-5.2 + +The Qt version 5.2 series is binary compatible with the 5.1.x series. +Applications compiled for 5.1 will continue to run with 5.2. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt-project.org/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + +QtWidgets +--------- + +- QAbstractScrollArea now has a SizeAdjustPolicy. If it is set to AdjustToContents + it will make use of the new protected viewportSizeHint() (binary compatible since it + was reserved in Qt5). This function returns a suggested size based on contents. + +- QTreeView now has setTreePosition to allow the treestructure to show data from other + columns than logicalindex zero. + +- [QTBUG-4206] QTableView resizeToContents will now adjust to actual contents + and not just visible area. QHeaderView::setAutoResizePrecision() has been + introduced to control how precise the autoResize should be. + +- QFileDialog::setDefaultSuffix() removes leading dot characters. + +- QSizePolicy got a retainSizeWhenHidden attribute. + +QtCore +------ +- [QTBUG-30250] QTime, QDateTime: + When calling QTime::toString(Qt::TextDate) and QTime::toString(Qt::ISODate), + milliseconds are now included in the returned string. This also applies to + QDateTime::toString(Qt::TextDate) and QDateTime::toString(ISODate). diff --git a/doc/global/config.qdocconf b/doc/global/config.qdocconf new file mode 100644 index 0000000000..2b3ca1d6ba --- /dev/null +++ b/doc/global/config.qdocconf @@ -0,0 +1,12 @@ +#Include this file to inherit configuration related to Qt Project based modules. + +dita.metadata.default.author = Qt Project +dita.metadata.default.permissions = all +dita.metadata.default.publisher = Qt Project +dita.metadata.default.copyryear = 2013 +dita.metadata.default.copyrholder = Digia Plc +dita.metadata.default.audience = programmer + +#Set the main Qt index.html +navigation.homepage = "Qt $QT_VER" +buildversion = "Qt $QT_VERSION Reference Documentation" diff --git a/doc/global/externalsites/rfc.qdoc b/doc/global/externalsites/rfc.qdoc index bc6a1d66a2..37c71ab73e 100644 --- a/doc/global/externalsites/rfc.qdoc +++ b/doc/global/externalsites/rfc.qdoc @@ -77,3 +77,18 @@ \externalpage http://www.rfc-editor.org/rfc/rfc3986.txt \title RFC 3986 */ + +/*! + \externalpage http://www.rfc-editor.org/rfc/rfc2822.txt + \title RFC 2822 +*/ + +/*! + \externalpage http://www.rfc-editor.org/rfc/rfc1036.txt + \title RFC 1036 +*/ + +/*! + \externalpage http://www.rfc-editor.org/rfc/rfc850.txt + \title RFC 850 +*/ diff --git a/doc/global/fileextensions.qdocconf b/doc/global/fileextensions.qdocconf new file mode 100644 index 0000000000..ec47dc9c7f --- /dev/null +++ b/doc/global/fileextensions.qdocconf @@ -0,0 +1,12 @@ +naturallanguage = en_US +outputencoding = UTF-8 +sourceencoding = UTF-8 + +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml *.css" +examples.imageextensions = "*.png *.jpg *.gif" + +headers.fileextensions = "*.ch *.h *.h++ *.hh *.hpp *.hxx" +sources.fileextensions = "*.c++ *.cc *.cpp *.cxx *.mm *.qml *.qdoc" + +#include the external websites +sourcedirs += externalsites diff --git a/doc/global/html-config.qdocconf b/doc/global/html-config.qdocconf new file mode 100644 index 0000000000..1560db8d98 --- /dev/null +++ b/doc/global/html-config.qdocconf @@ -0,0 +1,29 @@ +#Additional HTML settings + +HTML.nonavigationbar = "false" + +HTML.extraimages += template/images/arrow_bc.png \ + template/images/home.png \ + template/images/ico_out.png \ + template/images/ico_note.png \ + template/images/ico_note_attention.png \ + template/images/btn_prev.png \ + template/images/btn_next.png \ + template/images/bullet_dn.png \ + template/images/bullet_sq.png \ + template/images/bgrContent.png \ + template/images/logo.png + +#specify which files in the output directory should be packed into the qch file. +#these files are assumed to be in each module's output directory."qtquick/images/ico_out.png" for example. +qhp.extraFiles += images/arrow_bc.png \ + images/home.png \ + images/ico_out.png \ + images/ico_note.png \ + images/ico_note_attention.png \ + images/btn_prev.png \ + images/btn_next.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bgrContent.png \ + images/logo.png diff --git a/doc/global/html-footer.qdocconf b/doc/global/html-footer.qdocconf new file mode 100644 index 0000000000..6c26dc7c29 --- /dev/null +++ b/doc/global/html-footer.qdocconf @@ -0,0 +1,30 @@ +#Default HTML footer for QDoc builds. + +HTML.footer = \ + " </div>\n" \ + " </div>\n" \ + " </div>\n" \ + " </div>\n" \ + "</div>\n" \ + "<div class=\"footer\">\n" \ + " <div class=\"qt13a-copyright\" id=\"copyright\">\n" \ + " <div class=\"qt13a-container\">\n" \ + " <p>\n" \ + " <acronym title=\"Copyright\">©</acronym> 2013 Digia Plc and/or its\n" \ + " subsidiaries. Documentation contributions included herein are the copyrights of\n" \ + " their respective owners.</p>\n" \ + " <p>\n" \ + " The documentation provided herein is licensed under the terms of the\n" \ + " <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU Free Documentation\n" \ + " License version 1.3</a> as published by the Free Software Foundation.</p>\n" \ + " <p>\n" \ + " Documentation sources may be obtained from <a href=\"http://www.qt-project.org\">\n" \ + " www.qt-project.org</a>.</p>\n" \ + " <p>\n" \ + " Digia, Qt and their respective logos are trademarks of Digia Plc \n" \ + " in Finland and/or other countries worldwide. All other trademarks are property\n" \ + " of their respective owners. <a title=\"Privacy Policy\"\n" \ + " href=\"http://en.gitorious.org/privacy_policy/\">Privacy Policy</a></p>\n" \ + " </div>\n" \ + " </div>\n" \ + "</div>\n" \ diff --git a/doc/global/html-header-offline.qdocconf b/doc/global/html-header-offline.qdocconf new file mode 100644 index 0000000000..d84f38fef8 --- /dev/null +++ b/doc/global/html-header-offline.qdocconf @@ -0,0 +1,31 @@ +#Default HTML header for QDoc builds. + +#specify the CSS file used by this template +HTML.stylesheets = template/style/offline.css + +#for including files into the qch file +qhp.extraFiles += style/offline.css + +HTML.headerstyles = \ + " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n" + +HTML.endheader = \ + "</head>\n" + +HTML.postheader = \ + "<body>\n" \ + "<div class=\"header\" id=\"qtdocheader\">\n"\ + " <div class=\"main\">\n" \ + " <div class=\"main-rounded\">\n" \ + " <div class=\"navigationbar\">\n"\ + " <ul>\n"\ + + + +HTML.postpostheader = \ + " </ul>\n"\ + " </div>\n" \ + "</div>\n" \ + "<div class=\"content\">\n" \ + "<div class=\"line\">\n" \ + "<div class=\"content mainContent\">\n" \ diff --git a/doc/global/html-header-online.qdocconf b/doc/global/html-header-online.qdocconf new file mode 100644 index 0000000000..5c21644a39 --- /dev/null +++ b/doc/global/html-header-online.qdocconf @@ -0,0 +1,64 @@ +#HTML Header with Qt Project branding and online links + +HTML.stylesheets = template/style/online.css + +#for including files into the qch file. Relative to the outputdir of a QDoc build. +# $QT_INSTALL_DOCS/qtquick/style/online.css for example +qhp.extraFiles += style/online.css + +HTML.headerstyles = \ + " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/online.css\" />\n" + +HTML.endheader = \ + "</head>\n" + +HTML.postheader = \ + "<body>\n" \ + "<div class=\"header\" id=\"qtdocheader\"></div>\n" \ + " <div class=\"nav\" id=\"qt13a-header\">\n" \ + " <div class=\"qt13a-gradient\">\n" \ + " <div class=\"qt13a-container qt13a-dynamicREMOVE\" >\n" \ + " <div id=\"qt13a-register\">\n" \ + " <a href=\"http://qt-project.org/\">Qt Home</a>\n" \ + " <a href=\"https://bugreports.qt-project.org/\">Bug Tracker</a>\n" \ + " <a href=\"https://codereview.qt-project.org/\">Code Review</a>\n" \ + " </div>\n" \ + " <div class=\"qt13a-sixCol\">\n" \ + " <div id=\"qt13a-logo\">\n" \ + " <a href=\"http://qt-project.org/\" class=\"qt13a-site-logo\">\n" \ + " <img src=\"images/Qt-logo.png\" alt=\"Qt\"></img>\n" \ + " </a>\n" \ + " </div>\n" \ + " <div id=\"qt13a-title_nav\">\n" \ + " <div id=\"qt13a-title\">\n" \ + " <p class=\"qt13a-title\">Qt Documentation Snapshots</p>\n" \ + " </div>\n" \ + " <div class=\"qt13a-nav\">\n" \ + " <ul>\n" \ + " <li>\n" \ + " <a href=\"http://doc-snapshot.qt-project.org\">Snapshots</a>\n" \ + " </li>\n" \ + " <li>\n" \ + " <a href=\"http://qt-project.org/doc\">Released</a>\n" \ + " </li>\n" \ + " <li>\n" \ + " <a href=\"http://doc.qt.digia.com\">Archives</a>\n" \ + " </li>\n" \ + " </ul>\n" \ + " </div>\n" \ + " </div>\n" \ + " </div>\n" \ + " </div>\n" \ + " </div>\n" \ + " </div>\n" \ + " <div class=\"main\">\n" \ + " <div class=\"main-rounded\">\n" \ + " <div class=\"navigationbar\">\n" \ + " <ul>\n" \ + +HTML.postpostheader = \ + " </ul>\n" \ + " </div>\n" \ + "<div class=\"content\">\n" \ + " <div class=\"line\">\n" \ + " <div class=\"content mainContent\">\n" \ diff --git a/doc/global/qt-cpp-ignore.qdocconf b/doc/global/qt-cpp-defines.qdocconf index 1f34f366cb..2e795e1439 100644 --- a/doc/global/qt-cpp-ignore.qdocconf +++ b/doc/global/qt-cpp-defines.qdocconf @@ -1,3 +1,21 @@ +versionsym = QT_VERSION_STR + +defines += Q_QDOC \ + QT_.*_SUPPORT \ + QT_.*_LIB \ + QT_COMPAT \ + QT_KEYPAD_NAVIGATION \ + QT_NO_EGL \ + QT3_SUPPORT \ + Q_WS_.* \ + Q_OS_.* \ + Q_BYTE_ORDER \ + QT_DEPRECATED \ + QT_DEPRECATED_* \ + Q_NO_USING_KEYWORD \ + __cplusplus \ + Q_COMPILER_INITIALIZER_LISTS + Cpp.ignoretokens += \ PHONON_EXPORT \ Q_AUTOTEST_EXPORT \ @@ -37,11 +55,13 @@ Cpp.ignoretokens += \ Q_LOCATION_EXPORT \ Q_MULTIMEDIA_EXPORT \ Q_NETWORK_EXPORT \ + Q_NORETURN \ Q_OPENGL_EXPORT \ Q_OPENVG_EXPORT \ Q_OUTOFLINE_TEMPLATE \ Q_PRINTSUPPORT_EXPORT \ Q_QML_EXPORT \ + Q_REQUIRED_RESULT \ Q_SCRIPT_EXPORT \ Q_SCRIPTTOOLS_EXPORT \ Q_SQL_EXPORT \ @@ -84,13 +104,15 @@ Cpp.ignoretokens += \ QT_END_NAMESPACE \ QT_FASTCALL \ QT_WIDGET_PLUGIN_EXPORT \ - QTBLUETOOTH_BEGIN_NAMESPACE \ - QTBLUETOOTH_END_NAMESAPCE \ - QTNFC_BEGIN_NAMESPACE \ - QTNFC_END_NAMESPACE \ + QT_BEGIN_NAMESPACE_NFC \ + QT_END_NAMESPACE_NFC \ + QT_USE_NAMESPACE_NFC \ + QT_BEGIN_NAMESPACE_BLUETOOTH \ + QT_END_NAMESPACE_BLUETOOTH \ + QT_USE_NAMESPACE_BLUETOOTH \ QWEBKIT_EXPORT -Cpp.ignoredirectives = \ +Cpp.ignoredirectives += \ __attribute__ \ K_DECLARE_PRIVATE \ PHONON_HEIR \ diff --git a/doc/global/qt-defines.qdocconf b/doc/global/qt-defines.qdocconf deleted file mode 100644 index 79b13eee92..0000000000 --- a/doc/global/qt-defines.qdocconf +++ /dev/null @@ -1,17 +0,0 @@ -versionsym = QT_VERSION_STR - -defines += Q_QDOC \ - QT_.*_SUPPORT \ - QT_.*_LIB \ - QT_COMPAT \ - QT_KEYPAD_NAVIGATION \ - QT_NO_EGL \ - QT3_SUPPORT \ - Q_WS_.* \ - Q_OS_.* \ - Q_BYTE_ORDER \ - QT_DEPRECATED \ - QT_DEPRECATED_* \ - Q_NO_USING_KEYWORD \ - __cplusplus \ - Q_COMPILER_INITIALIZER_LISTS diff --git a/doc/global/qt-html-templates-offline.qdocconf b/doc/global/qt-html-templates-offline.qdocconf index e9b2c6a7a8..cd8315aa9a 100644 --- a/doc/global/qt-html-templates-offline.qdocconf +++ b/doc/global/qt-html-templates-offline.qdocconf @@ -1,4 +1,10 @@ -HTML.nobreadcrumbs = "true" +#include standard set of HTML header and footer. +include(html-config.qdocconf) +include(html-header-offline.qdocconf) +include(html-footer.qdocconf) + +#uncomment if navigation bar is not wanted +#HTML.nonavigationbar = "true" HTML.stylesheets = template/style/offline.css HTML.extraimages += template/images/ico_out.png \ @@ -20,40 +26,3 @@ qhp.extraFiles += style/offline.css \ images/bullet_dn.png \ images/bullet_sq.png \ images/bgrContent.png - - -HTML.headerstyles = \ - " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n" - -HTML.endheader = \ - "</head>\n" \ - "<body>\n" \ - "<div class=\"header\" id=\"qtdocheader\"></div>\n"\ - "<div class=\"content\">\n" \ - "<div class=\"line\">\n" \ - "<div class=\"content mainContent\">\n" \ - -HTML.footer = \ - "</div>\n" \ - "</div>\n" \ - "</div>\n" \ - "<div class=\"footer\">\n" \ - " <p>\n" \ - " <acronym title=\"Copyright\">©</acronym> 2013 Digia Plc and/or its\n" \ - " subsidiaries. Documentation contributions included herein are the copyrights of\n" \ - " their respective owners.</p>\n" \ - " <br />\n" \ - " <p>\n" \ - " The documentation provided herein is licensed under the terms of the\n" \ - " <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU Free Documentation\n" \ - " License version 1.3</a> as published by the Free Software Foundation.</p>\n" \ - " <p>\n" \ - " Documentation sources may be obtained from <a href=\"http://www.qt-project.org\">\n" \ - " www.qt-project.org</a>.</p>\n" \ - " <br />\n" \ - " <p>\n" \ - " Digia, Qt and their respective logos are trademarks of Digia Plc \n" \ - " in Finland and/or other countries worldwide. All other trademarks are property\n" \ - " of their respective owners. <a title=\"Privacy Policy\"\n" \ - " href=\"http://en.gitorious.org/privacy_policy/\">Privacy Policy</a></p>\n" \ - "</div>\n" \ diff --git a/doc/global/qt-html-templates-online.qdocconf b/doc/global/qt-html-templates-online.qdocconf index c794c47679..88abc3429b 100644 --- a/doc/global/qt-html-templates-online.qdocconf +++ b/doc/global/qt-html-templates-online.qdocconf @@ -1,4 +1,10 @@ -HTML.nobreadcrumbs = "true" +#include standard set of HTML header and footer. +include(html-config.qdocconf) +include(html-header-online.qdocconf) +include(html-footer.qdocconf) + +#uncomment if navigation bar is not wanted +#HTML.nonavigationbar = "true" HTML.stylesheets = template/style/online.css HTML.extraimages += template/images/ico_out.png \ @@ -8,67 +14,10 @@ HTML.extraimages += template/images/ico_out.png \ template/images/btn_next.png \ template/images/bullet_dn.png \ template/images/bullet_sq.png \ - template/images/bgrContent.png - -HTML.headerstyles = \ - " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/online.css\" />\n" - -HTML.endheader = \ - "</head>\n" \ - "<body>\n" \ - "<div class=\"header\" id=\"qtdocheader\"></div>\n" \ - " <header>\n" \ - " <div class=\"nav\">\n" \ - " <a href=\"http://qt-project.org/\">Qt Home</a>\n" \ - " <a href=\"https://bugreports.qt-project.org/\">Bug Tracker</a>\n" \ - " <a href=\"https://codereview.qt-project.org/\">Code Review</a>\n" \ - " </div>\n" \ - " <a href=\"http://qt-project.org/\">\n" \ - " <img src=\"http://doc-snapshot.qt-project.org/images/logo.png\" alt=\"Qt\"></img>\n" \ - " </a>\n" \ - " <div class=\"nav-title\">\n" \ - " <h1 >Qt Documentation Snapshots</h1>\n" \ - " <div class=\"nav-subtitle\">\n" \ - " --snapshots of unreleased Qt documentation\n" \ - " </div>\n" \ - " </div>\n" \ - " <div class=\"nav-main\">\n" \ - " <div class=\"nav-main-content\">\n" \ - " <a href=\"http://doc-snapshot.qt-project.org\">All Modules</a>\n" \ - " </div>\n" \ - " <div class=\"nav-main-content\">\n" \ - " <a href=\"http://qt-project.org/doc\">Qt Releases</a>\n" \ - " </div>\n" \ - " <div class=\"nav-main-content\">\n" \ - " <a href=\"http://doc.qt.digia.com\">Archives</a>\n" \ - " </div>\n" \ - " </div>\n" \ - "</header>\n" \ - "<div class=\"content\">\n" \ - " <div class=\"line\">\n" \ - " <div class=\"content mainContent\">\n" \ - -HTML.footer = \ - " </div>\n" \ - " </div>\n" \ - "</div>\n" \ - "<div class=\"footer\">\n" \ - " <p>\n" \ - " <acronym title=\"Copyright\">©</acronym> 2013 Digia Plc and/or its\n" \ - " subsidiaries. Documentation contributions included herein are the copyrights of\n" \ - " their respective owners.</p>\n" \ - " <br />\n" \ - " <p>\n" \ - " The documentation provided herein is licensed under the terms of the\n" \ - " <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU Free Documentation\n" \ - " License version 1.3</a> as published by the Free Software Foundation.</p>\n" \ - " <p>\n" \ - " Documentation sources may be obtained from <a href=\"http://www.qt-project.org\">\n" \ - " www.qt-project.org</a>.</p>\n" \ - " <br />\n" \ - " <p>\n" \ - " Digia, Qt and their respective logos are trademarks of Digia Plc \n" \ - " in Finland and/or other countries worldwide. All other trademarks are property\n" \ - " of their respective owners. <a title=\"Privacy Policy\"\n" \ - " href=\"http://en.gitorious.org/privacy_policy/\">Privacy Policy</a></p>\n" \ - "</div>\n" \ + template/images/bgrContent.png \ + template/images/Qt-logo.png \ + template/images/Qt-dark_gradient.png \ + template/images/Qt-footer-bg.jpg \ + template/images/Qt-footer_shadow.png \ + template/images/Qt-gradient.png \ + template/images/Qt-header-bg.jpg diff --git a/doc/global/qt-module-defaults-offline.qdocconf b/doc/global/qt-module-defaults-offline.qdocconf new file mode 100644 index 0000000000..bdca212960 --- /dev/null +++ b/doc/global/qt-module-defaults-offline.qdocconf @@ -0,0 +1,13 @@ +#The default configuration for a Qt 5 module, including Add-Ons and Tools. +#Include this file for a standard Qt 5 module; builds with the offline style. + +#include standard set of macros and C++ defines and ignores +include(macros.qdocconf) +include(qt-cpp-defines.qdocconf) +include(compat.qdocconf) +include(manifest-meta.qdocconf) +include(fileextensions.qdocconf) +include(qt-html-templates-offline.qdocconf) + +#extra configuration data such as file extensions +include(config.qdocconf) diff --git a/doc/global/qt-module-defaults-online.qdocconf b/doc/global/qt-module-defaults-online.qdocconf index 93ecae16fa..258295b4f9 100644 --- a/doc/global/qt-module-defaults-online.qdocconf +++ b/doc/global/qt-module-defaults-online.qdocconf @@ -1,32 +1,14 @@ +#The online onfiguration for a Qt 5 module, including Add-Ons and Tools. +#Online version contains a different header. +#Include this file for a standard Qt 5 module; builds with the online style. + +#include standard set of macros and C++ defines and ignores include(macros.qdocconf) -include(qt-cpp-ignore.qdocconf) -include(qt-defines.qdocconf) -include(qt-html-templates-online.qdocconf) +include(qt-cpp-defines.qdocconf) include(compat.qdocconf) +include(manifest-meta.qdocconf) +include(fileextensions.qdocconf) +include(qt-html-templates-online.qdocconf) -dita.metadata.default.author = Qt Project -dita.metadata.default.permissions = all -dita.metadata.default.publisher = Qt Project -dita.metadata.default.copyryear = 2013 -dita.metadata.default.copyrholder = Digia Plc -dita.metadata.default.audience = programmer - -naturallanguage = en_US -outputencoding = UTF-8 -sourceencoding = UTF-8 - -examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml *.css" -examples.imageextensions = "*.png *.jpg *.gif" - -headers.fileextensions = "*.ch *.h *.h++ *.hh *.hpp *.hxx" -sources.fileextensions = "*.c++ *.cc *.cpp *.cxx *.mm *.qml *.qdoc" - -versionsym = QT_VERSION_STR - -macro.raisedaster.HTML = "<sup>*</sup>" - -#for including files into the qch file -qhp.extraFiles += template/style/online.css - -#include the external websites -sourcedirs += externalsites +#extra configuration data DITA information +include(config.qdocconf) diff --git a/doc/global/qt-module-defaults.qdocconf b/doc/global/qt-module-defaults.qdocconf index 0365d5a6cd..8d0665ef41 100644 --- a/doc/global/qt-module-defaults.qdocconf +++ b/doc/global/qt-module-defaults.qdocconf @@ -1,30 +1,7 @@ -include(macros.qdocconf) -include(qt-cpp-ignore.qdocconf) -include(qt-defines.qdocconf) -include(qt-html-templates-offline.qdocconf) -include(compat.qdocconf) -include(manifest-meta.qdocconf) +#The default configuration for a Qt 5 module, including Add-Ons and Tools. +#Include this file for a standard Qt 5 module. This file is provided for +#compatibility reasons. -dita.metadata.default.author = Qt Project -dita.metadata.default.permissions = all -dita.metadata.default.publisher = Qt Project -dita.metadata.default.copyryear = 2013 -dita.metadata.default.copyrholder = Digia Plc -dita.metadata.default.audience = programmer - -naturallanguage = en_US -outputencoding = UTF-8 -sourceencoding = UTF-8 - -examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml *.css" -examples.imageextensions = "*.png *.jpg *.gif" - -headers.fileextensions = "*.ch *.h *.h++ *.hh *.hpp *.hxx" -sources.fileextensions = "*.c++ *.cc *.cpp *.cxx *.mm *.qml *.qdoc" - -versionsym = QT_VERSION_STR - -macro.raisedaster.HTML = "<sup>*</sup>" - -#include the external websites -sourcedirs += externalsites +#The default is the offline style. The alternate style is in +#qt-module-defaults-online.qdocconf +include(qt-module-defaults-offline.qdocconf) diff --git a/doc/global/template/images/Qt-dark_gradient.png b/doc/global/template/images/Qt-dark_gradient.png Binary files differnew file mode 100644 index 0000000000..6ae10f37bf --- /dev/null +++ b/doc/global/template/images/Qt-dark_gradient.png diff --git a/doc/global/template/images/Qt-footer-bg.jpg b/doc/global/template/images/Qt-footer-bg.jpg Binary files differnew file mode 100644 index 0000000000..c0ff209b7e --- /dev/null +++ b/doc/global/template/images/Qt-footer-bg.jpg diff --git a/doc/global/template/images/Qt-footer_shadow.png b/doc/global/template/images/Qt-footer_shadow.png Binary files differnew file mode 100644 index 0000000000..5a7063dfee --- /dev/null +++ b/doc/global/template/images/Qt-footer_shadow.png diff --git a/doc/global/template/images/Qt-gradient.png b/doc/global/template/images/Qt-gradient.png Binary files differnew file mode 100644 index 0000000000..aa38227cbb --- /dev/null +++ b/doc/global/template/images/Qt-gradient.png diff --git a/doc/global/template/images/Qt-header-bg.jpg b/doc/global/template/images/Qt-header-bg.jpg Binary files differnew file mode 100644 index 0000000000..c9a6d96db4 --- /dev/null +++ b/doc/global/template/images/Qt-header-bg.jpg diff --git a/doc/global/template/images/Qt-logo.png b/doc/global/template/images/Qt-logo.png Binary files differnew file mode 100644 index 0000000000..64c1c4aaa3 --- /dev/null +++ b/doc/global/template/images/Qt-logo.png diff --git a/doc/global/template/images/arrow_bc.png b/doc/global/template/images/arrow_bc.png Binary files differnew file mode 100644 index 0000000000..f2a83a5740 --- /dev/null +++ b/doc/global/template/images/arrow_bc.png diff --git a/doc/global/template/images/logo.png b/doc/global/template/images/logo.png Binary files differnew file mode 100644 index 0000000000..1e7ed4cf21 --- /dev/null +++ b/doc/global/template/images/logo.png diff --git a/doc/global/template/style/offline.css b/doc/global/template/style/offline.css index 0e4dd5e9a4..f573633331 100644 --- a/doc/global/template/style/offline.css +++ b/doc/global/template/style/offline.css @@ -1,43 +1,55 @@ -body{ -font: normal 400 14px/1.2 Arial; -margin-top:85px; -font-family: Arial, Helvetica; -color:#313131; -text-align:justify; -margin-left:5px; -margin-right:5px; +body { + font: normal 400 14px/1.2 Arial; + margin-top: 85px; + font-family: Arial, Helvetica; + color: #313131; + text-align: justify; + margin-left: 5px; + margin-right: 5px; } p { -line-height: 20px; + line-height: 20px } -img{ --moz-box-shadow: 3px 3px 3px #ccc; --webkit-box-shadow: 3px 3px 3px #ccc; -box-shadow: 3px 3px 3px #ccc; -border:#8E8D8D 2px solid; -margin-left:0px; -max-width: 800px; -height: auto + +img { + -moz-box-shadow: 3px 3px 3px #ccc; + -webkit-box-shadow: 3px 3px 3px #ccc; + box-shadow: 3px 3px 3px #ccc; + border: #8E8D8D 2px solid; + margin-left: 0px; + max-width: 800px; + height: auto; } -.content{} +.content { -.descr{ -margin-top:35px; -/*max-width: 75%;*/ -margin-left:5px; -text-align:justify; -vertical-align:top; } -.name{ -max-width: 75%; -font-weight:100; +.content .indexboxcont li { + font: normal bold 13px/1 Verdana + } + +.content .normallist li { + font: normal 13px/1 Verdana + } + +.descr { + margin-top: 35px; + /*max-width: 75%;*/ + margin-left: 5px; + text-align: justify; + vertical-align: top; } -tt{ -text-align:left;} +.name { + max-width: 75%; + font-weight: 100; +} + +tt { + text-align: left +} /* ----------- @@ -45,25 +57,25 @@ links ----------- */ -a:link{ -color: #007330; -text-decoration: none; -text-align:left; +a:link { + color: #007330; + text-decoration: none; + text-align: left; } -a:hover{ -color: #44a51c; -text-align:left; +a:hover { + color: #44a51c; + text-align: left; } -a:visited{ -color: #007330; -text-align:left; +a:visited { + color: #007330; + text-align: left; } -a:visited:hover{ -color: #44a51c; -text-align:left; +a:visited:hover { + color: #44a51c; + text-align: left; } /* @@ -71,19 +83,19 @@ text-align:left; offline viewing: HTML links display an icon ----------- */ -a[href*="http://"], a[href*="ftp://"],a[href*="https://"] -{ -text-decoration: none; -background-image:url(../images/ico_out.png); -background-repeat:no-repeat; -background-position:left; -padding-left:20px; -text-align:left; + +a[href*="http://"], a[href*="ftp://"], a[href*="https://"] { + text-decoration: none; + background-image: url(../images/ico_out.png); + background-repeat: no-repeat; + background-position: left; + padding-left: 20px; + text-align: left; } -.flags{ -text-decoration:none; -text-height:24px; +.flags { + text-decoration: none; + text-height: 24px; } /* @@ -91,36 +103,37 @@ text-height:24px; NOTE styles ------------------------------- */ -.notetitle, .tiptitle, .fastpathtitle{ -font-weight:bold; + +.notetitle, .tiptitle, .fastpathtitle { + font-weight: bold } -.attentiontitle,.cautiontitle,.dangertitle,.importanttitle,.remembertitle,.restrictiontitle{ -font-weight:bold; +.attentiontitle, .cautiontitle, .dangertitle, .importanttitle, .remembertitle, .restrictiontitle { + font-weight: bold } -.note,.tip,.fastpath{ -background: #F2F2F2 url(../images/ico_note.png); -background-repeat: no-repeat; -background-position: top left; -padding:5px; -padding-left:40px; -padding-bottom:10px; -border:#999 1px dotted; -color:#666666; -margin:5px; +.note, .tip, .fastpath { + background: #F2F2F2 url(../images/ico_note.png); + background-repeat: no-repeat; + background-position: top left; + padding: 5px; + padding-left: 40px; + padding-bottom: 10px; + border: #999 1px dotted; + color: #666666; + margin: 5px; } -.attention,.caution,.danger,.important,.remember,.restriction{ -background: #F2F2F2 url(../images/ico_note_attention.png); -background-repeat:no-repeat; -background-position:top left; -padding:5px; -padding-left:40px; -padding-bottom:10px; -border:#999 1px dotted; -color:#666666; -margin:5px; +.attention, .caution, .danger, .important, .remember, .restriction { + background: #F2F2F2 url(../images/ico_note_attention.png); + background-repeat: no-repeat; + background-position: top left; + padding: 5px; + padding-left: 40px; + padding-bottom: 10px; + border: #999 1px dotted; + color: #666666; + margin: 5px; } /* @@ -129,58 +142,127 @@ Top navigation ------------------------------- */ -.qtref{ -display: block; -position: relative; -height:15px; -z-index: 1; -font-size:11px; -padding-right:10px; -float:right; -} - -.naviNextPrevious{ -clear: both; -display: block; -position: relative; -text-align: right; -top: -47px; -float:right; -height:20px; -z-index:1; -padding-right:10px; -padding-top:2px; -vertical-align:top; -margin:0px; -} - - -.naviNextPrevious > a:first-child{ -background-image:url(../images/btn_prev.png); -background-repeat:no-repeat; -background-position:left; -padding-left:20px; -height:20px; -padding-left:20px; -} - -.naviNextPrevious > a:last-child{ -background-image:url(../images/btn_next.png); -background-repeat:no-repeat; -background-position:right; -padding-right:20px; -height:20px; -margin-left:30px; -} +.qtref { + display: block; + position: relative; + height: 15px; + z-index: 1; + font-size: 11px; + padding-right: 10px; + float: right; +} + +.naviNextPrevious { + clear: both; + display: block; + position: relative; + text-align: right; + top: -47px; + float: right; + height: 20px; + z-index: 1; + padding-right: 10px; + padding-top: 2px; + vertical-align: top; + margin: 0px; +} + +.naviNextPrevious > a:first-child { + background-image: url(../images/btn_prev.png); + background-repeat: no-repeat; + background-position: left; + padding-left: 20px; + height: 20px; + padding-left: 20px; + } + +.naviNextPrevious > a:last-child { + background-image: url(../images/btn_next.png); + background-repeat: no-repeat; + background-position: right; + padding-right: 20px; + height: 20px; + margin-left: 30px; + } + /* ----------- footer and license ----------- */ -.footer{ -text-align:center + +.footer { + text-align: center +} + +.navigationbar { + display: block; + position: relative; + top: -20px; + /*border-top: 2px solid #ffffff;*/ + border-bottom: 1px solid #cecece; + background-color: #F2F2F2; + z-index: 1; + height: 20px; + padding-left: 7px; + margin: 0px; + padding-top: 2px; + margin-left: -5px; + margin-right: -5px; +} + +.navigationbar .first { + background: url(../images/home.png); + background-position: left; + background-repeat: no-repeat; + padding-left: 20px; + } + +.navigationbar ul { + margin: 0px; + padding: 0px; + } + + .navigationbar ul li { + list-style-type: none; + padding-top: 2px; + padding-left: 4px; + margin: 0; + height: 20px; + } + +.navigationbar li { + float: left + } + + .navigationbar li a { + display: block; + text-decoration: none; + background: url(../images/arrow_bc.png); + background-repeat: no-repeat; + background-position: right; + padding-right: 17px; + } + +/* +----------- +footer and license +----------- +*/ + +.footer { + text-align: center +} + +#buildversion { + font-style: italic; + font-size: small; + float: right; + margin-right: 5px; } +/* + /* table of content no display */ @@ -191,181 +273,177 @@ headers ----------- */ - -@media screen{ -.title{ -color:#313131; -font-size: 18px; -font-weight: normal; -left: 0; -padding-bottom: 20px; -padding-left: 10px; -padding-top: 20px; -position: absolute; -right: 0; -top: 0; -background-color:#E6E6E6; -border-bottom: 1px #CCC solid; -border-top: 2px #CCC solid; -font-weight:bold; -margin-left:0px; -margin-right:0px; -} +@media screen { + .title { + color: #313131; + font-size: 18px; + font-weight: normal; + left: 0; + padding-bottom: 20px; + padding-left: 10px; + padding-top: 20px; + position: absolute; + right: 0; + top: 0; + background-color: #E6E6E6; + border-bottom: 1px #CCC solid; + border-top: 2px #CCC solid; + font-weight: bold; + margin-left: 0px; + margin-right: 0px; + } } h1 { -margin: 0; + margin: 0 } h2, p.h2 { -font: 500 16px/1.2 Arial; -font-weight:100; -background-color:#F2F3F4; -padding:4px; -margin-bottom:30px; -margin-top:30px; -border-top:#E0E0DE 1px solid; -border-bottom: #E0E0DE 1px solid; -max-width: 99%; -overflow: hidden; -} - -h3{ - -font: 500 14px/1.2 Arial; -font-weight:100; -text-decoration:underline; -margin-bottom:30px; -margin-top:30px; -} - -h3.fn,span.fn{ -border-width: 1px; -border-style: solid; -border-color: #E6E6E6; --moz-border-radius: 7px 7px 7px 7px; --webkit-border-radius: 7px 7px 7px 7px; -border-radius: 7px 7px 7px 7px; -background-color: #F6F6F6; -word-spacing: 3px; -padding: 5px 5px; -text-decoration:none; -font-weight:bold; -max-width:75%; -font-size:14px; -margin:0px; -margin-top:45px; - -} - -.name{ -color:#1A1A1A; -} -.type{ -color:#808080; + font: 500 16px/1.2 Arial; + font-weight: 100; + background-color: #F2F3F4; + padding: 4px; + margin-bottom: 30px; + margin-top: 30px; + border-top: #E0E0DE 1px solid; + border-bottom: #E0E0DE 1px solid; + max-width: 99%; + overflow: hidden; +} + +h3 { + font: 500 14px/1.2 Arial; + font-weight: 100; + text-decoration: underline; + margin-bottom: 30px; + margin-top: 30px; +} + +h3.fn, span.fn { + border-width: 1px; + border-style: solid; + border-color: #E6E6E6; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + word-spacing: 3px; + padding: 5px 5px; + text-decoration: none; + font-weight: bold; + max-width: 75%; + font-size: 14px; + margin: 0px; + margin-top: 45px; +} + +.name { + color: #1A1A1A +} + +.type { + color: #808080 } - - @media print { -.title { -color:#0066CB; -font-family:Arial, Helvetica; -font-size: 32px; -font-weight: normal; -left: 0; -position: absolute; -right: 0; -top: 0; -} + .title { + color: #0066CB; + font-family: Arial, Helvetica; + font-size: 32px; + font-weight: normal; + left: 0; + position: absolute; + right: 0; + top: 0; + } } - /* ----------------- table styles ----------------- */ + .table img { -border:none; -margin-left:0px; --moz-box-shadow:0px 0px 0px #fff; --webkit-box-shadow: 0px 0px 0px #fff; -box-shadow: 0px 0px 0px #fff; + border: none; + margin-left: 0px; + -moz-box-shadow: 0px 0px 0px #fff; + -webkit-box-shadow: 0px 0px 0px #fff; + box-shadow: 0px 0px 0px #fff; } /* table with border alternative colours*/ - table,pre{ --moz-border-radius: 7px 7px 7px 7px; --webkit-border-radius: 7px 7px 7px 7px; - border-radius: 7px 7px 7px 7px; -background-color: #F6F6F6; -border: 1px solid #E6E6E6; -border-collapse: separate; -margin-bottom: 25px; -margin-left: 15px; -font-size: 12px; -line-height: 1.2; -} - - -table th{ -text-align:left; -padding-left:20px; -} - -table td { -padding: 3px 15px 3px 20px; -border-bottom:#CCC dotted 1px; -} -table p { margin:0px;} - -table tr.even { -background-color: white; -color: #66666E; -} - -table tr.odd { -background-color: #F6F6F6; -color: #66666E; -} - - -table thead { -text-align:left; -padding-left:20px; -background-color:#e1e0e0; -border-left:none; -border-right:none; -} - -table thead th { -padding-top:5px; -padding-left:10px; -padding-bottom:5px; -border-bottom: 2px solid #D1D1D1; -padding-right:10px; -} - +table, pre { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #E6E6E6; + border-collapse: separate; + margin-bottom: 25px; + margin-left: 15px; + font-size: 12px; + line-height: 1.2; +} + + table tr.even { + background-color: white; + color: #66666E; + } + + table tr.odd { + background-color: #F6F6F6; + color: #66666E; + } + + table thead { + text-align: left; + padding-left: 20px; + background-color: #e1e0e0; + border-left: none; + border-right: none; + } + + table thead th { + padding-top: 5px; + padding-left: 10px; + padding-bottom: 5px; + border-bottom: 2px solid #D1D1D1; + padding-right: 10px; + } + + table th { + text-align: left; + padding-left: 20px; + } + + table td { + padding: 3px 15px 3px 20px; + border-bottom: #CCC dotted 1px; + } + + table p { + margin: 0px + } /* table bodless & white*/ .borderless { -border-radius: 0px 0px 0px 0px; -background-color: #fff; -border: 1px solid #fff; + border-radius: 0px 0px 0px 0px; + background-color: #fff; + border: 1px solid #fff; } .borderless tr { -background-color: #FFF; -color: #66666E; -} + background-color: #FFF; + color: #66666E; + } .borderless td { -border:none; -border-bottom:#fff dotted 1px; -} + border: none; + border-bottom: #fff dotted 1px; + } /* ----------- @@ -373,264 +451,249 @@ List ----------- */ -ul{ -padding-bottom:2px; +ul { + padding-bottom: 2px } li { -margin-bottom: 10px; -padding-left: 8px; -list-style:outside; -list-style-type:square; -text-align:left; + margin-bottom: 10px; + padding-left: 8px; + list-style: outside; + list-style-type: square; + text-align: left; } - -ol{ -margin:10px; -padding:0; +ol { + margin: 10px; + padding: 0; } -ol > li{ -margin-left: 30px; -padding-left:8px; -list-style:decimal; -} + ol > li { + margin-left: 30px; + padding-left: 8px; + list-style: decimal; + } -.centerAlign{ -text-align: left; +.centerAlign { + text-align: left } -.cpp{ -display: block; -margin: 10px; -overflow: auto; -padding: 20px 20px 20px 20px; +.cpp { + display: block; + margin: 10px; + overflow: auto; + padding: 20px 20px 20px 20px; } -.js{ -display: block; -margin: 10px; -overflow: auto; -padding: 20px 20px 20px 20px; +.js { + display: block; + margin: 10px; + overflow: auto; + padding: 20px 20px 20px 20px; } -.footer{ -margin-top: 50px; -padding-left:5px; -margin-bottom: 10px; -font-size:10px; -border-top: 1px solid #999; -padding-top:11px; +.footer { + margin-top: 50px; + padding-left: 5px; + margin-bottom: 10px; + font-size: 10px; + border-top: 1px solid #999; + padding-top: 11px; } -.footerNavi{ -width:auto; -text-align:right; -margin-top:50px; -z-index:1; +.footerNavi { + width: auto; + text-align: right; + margin-top: 50px; + z-index: 1; } -.memItemLeft{ -padding-right: 3px; +.memItemLeft { + padding-right: 3px } -.memItemRight{ -padding: 3px 15px 3px 0; +.memItemRight { + padding: 3px 15px 3px 0 } -.qml{ -display: block; -margin: 10; -overflow: auto; -padding: 20px 20px 20px 20px; +.qml { + display: block; + margin: 10px; + overflow: auto; + padding: 20px 20px 20px 20px; } -.qmldefault{ -padding-left: 5px; -float: right; -color: red; +.qmldefault { + padding-left: 5px; + float: right; + color: red; } -.qmlreadonly{ -padding-left: 5px; -float: right; -color: #254117; +.qmlreadonly { + padding-left: 5px; + float: right; + color: #254117; } -.rightAlign{ -padding: 3px 5px 3px 10px; -text-align: right; +.rightAlign { + padding: 3px 5px 3px 10px; + text-align: right; } .qmldoc { -margin-left: 15px; + margin-left: 15px } + /* ----------- Content table ----------- */ -@media print{ -.toc { -float: right; -clear: right; -padding-bottom: 10px; -padding-top: 50px; -width: 100%; -background-image:url(../images/bgrContent.png); -background-position:top; -background-repeat:no-repeat; -} +@media print { + .toc { + float: right; + clear: right; + padding-bottom: 10px; + padding-top: 50px; + width: 100%; + background-image: url(../images/bgrContent.png); + background-position: top; + background-repeat: no-repeat; + } } -@media screen{ -.toc{ -float:right; -clear: right; -vertical-align:top; --moz-border-radius: 7px 7px 7px 7px; --webkit-border-radius: 7px 7px 7px 7px; -border-radius: 7px 7px 7px 7px; - background:#FFF url(../images/bgrContent.png); -background-position:top; -background-repeat:repeat-x; -border: 1px solid #E6E6E6; -padding-left:5px; -padding-bottom:10px; -height: auto; -width: 200px; -text-align:left; -margin-left:20px; -} +@media screen { + .toc { + float: right; + clear: right; + vertical-align: top; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background: #FFF url('../images/bgrContent.png'); + background-position: top; + background-repeat: repeat-x; + border: 1px solid #E6E6E6; + padding-left: 5px; + padding-bottom: 10px; + height: auto; + width: 200px; + text-align: left; + margin-left: 20px; + } } -.toc h3{ -text-decoration:none; -} -.toc h3{font: 500 14px/1.2 Arial; -font-weight:100; -padding:0px; -margin:0px; -padding-top:5px; -padding-left:5px; +.toc h3 { + text-decoration: none } - -.toc ul{ -padding-left:10px; -padding-right:5px; +.toc h3 { + font: 500 14px/1.2 Arial; + font-weight: 100; + padding: 0px; + margin: 0px; + padding-top: 5px; + padding-left: 5px; } -.toc ul li{ -margin-left:15px; -list-style-image:url(../images/bullet_dn.png); -marker-offset: 0px; -margin-bottom:8px; -padding-left:0px; +.toc ul { + padding-left: 10px; + padding-right: 5px; } -.toc .level1{ -border:none;} +.toc ul li { + margin-left: 15px; + list-style-image: url(../images/bullet_dn.png); + marker-offset: 0px; + margin-bottom: 8px; + padding-left: 0px; + } -.toc .level2{ -border:none; -margin-left: 25px; +.toc .level1 { + border: none } -.level3{ -border:none; -margin-left: 30px; +.toc .level2 { + border: none; + margin-left: 25px; } -.clearfix{ -clear:both;} +.level3 { + border: none; + margin-left: 30px; +} -/* start index box */ -.indexbox -{ -width: 100%; -display:inline-block; +.clearfix { + clear: both } -.indexboxcont -{ -display: block; +/* start index box */ +.indexbox { + width: 100%; + display: inline-block; } -.indexboxcont .section -{ -display: inline-block; -width: 49%; -*width:42%; -_width:42%; -padding:0 2% 0 1%; -vertical-align:top; -} +.indexbox .indexIcon { + width: 11% + } -.indexboxcont .indexIcon -{ -width: 11%; -*width:18%; -_width:18%; -overflow:hidden; -} + .indexbox .indexIcon span { + display: block + } -.indexboxcont .section { - float: left; +.indexboxcont { + display: block } -.indexboxcont .section p -{ -padding-top: 20px; -padding-bottom: 20px; -} -.indexboxcont .sectionlist -{ -display: inline-block; -vertical-align:top; -width: 32.5%; -padding: 0; -} -.indexboxcont .sectionlist ul -{ -margin-bottom: 20px; -} +.indexboxcont .sectionlist { + display: inline-block; + vertical-align: top; + width: 32.5%; + padding: 0; + } -.indexboxcont .sectionlist ul li -{ -line-height: 1.5; -} + .indexboxcont .sectionlist ul { + margin-bottom: 20px + } -.content .indexboxcont li -{ -font: normal bold 13px/1 Verdana; -} + .indexboxcont .sectionlist ul li { + line-height: 1.5 + } -.content .normallist li -{ -font: normal 13px/1 Verdana; -} +.indexboxcont .indexIcon { + width: 11%; + *width: 18%; + _width: 18%; + overflow: hidden; + } -.indexbox .indexIcon { -width: 11%; -} +.indexboxcont .section { + display: inline-block; + width: 49%; + *width: 42%; + _width: 42%; + padding: 0 2% 0 1%; + vertical-align: top; + } + + .indexboxcont .section p { + padding-top: 20px; + padding-bottom: 20px; + } -.indexbox .indexIcon span -{ -display: block; -} +.indexboxcont .section { + float: left + } -.indexboxcont:after -{ -content: "."; -display: block; -height: 0; -clear: both; -visibility: hidden; +.indexboxcont:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; } /* @@ -638,6 +701,7 @@ visibility: hidden; Landing page ----------- */ + .col-group { white-space: nowrap; vertical-align: top; @@ -652,8 +716,8 @@ Landing page } .col-1 h1 { - margin: 20px 0 0 0; -} + margin: 20px 0 0 0 + } .col-2 { display: inline-block; @@ -663,5 +727,5 @@ Landing page } .sectionlist { - width: 100% !important; + width: 100% !important } diff --git a/doc/global/template/style/online.css b/doc/global/template/style/online.css index 7809783fa7..cf73455877 100644 --- a/doc/global/template/style/online.css +++ b/doc/global/template/style/online.css @@ -1,43 +1,41 @@ -body{ -font: normal 400 14px/1.2 Arial; -font-family: Arial, Helvetica; -color:#313131; -text-align:justify; -margin-left:5px; -margin-right:5px; -background: none repeat scroll 0% 0% rgb(230,231,232); +img { + -moz-box-shadow: 3px 3px 3px #ccc; + -webkit-box-shadow: 3px 3px 3px #ccc; + box-shadow: 3px 3px 3px #ccc; + border: #8E8D8D 2px solid; + margin-left: 0px; + max-width: 800px; + height: auto; } -p { -line-height: 20px; -} -img{ --moz-box-shadow: 3px 3px 3px #ccc; --webkit-box-shadow: 3px 3px 3px #ccc; -box-shadow: 3px 3px 3px #ccc; -border:#8E8D8D 2px solid; -margin-left:0px; -max-width: 800px; -height: auto +.content { + margin: 15px } -.content{} +.content .indexboxcont li { + font: normal bold 13px/1 Verdana + } + +.content .normallist li { + font: normal 13px/1 Verdana + } -.descr{ -margin-top:35px; -/*max-width: 75%;*/ -margin-left:5px; -text-align:justify; -vertical-align:top; +.descr { + margin-top: 35px; + /*max-width: 75%;*/ + margin-left: 5px; + text-align: justify; + vertical-align: top; } -.name{ -max-width: 75%; -font-weight:100; +.name { + max-width: 75%; + font-weight: 100; } -tt{ -text-align:left;} +tt { + text-align: left +} /* ----------- @@ -45,30 +43,9 @@ links ----------- */ -a:link{ -color: #007330; -text-decoration: none; -text-align:left; -} - -a:hover{ -color: #44a51c; -text-align:left; -} - -a:visited{ -color: #007330; -text-align:left; -} - -a:visited:hover{ -color: #44a51c; -text-align:left; -} - -.flags{ -text-decoration:none; -text-height:24px; +.flags { + text-decoration: none; + text-height: 24px; } /* @@ -76,692 +53,1005 @@ text-height:24px; NOTE styles ------------------------------- */ -.notetitle, .tiptitle, .fastpathtitle{ -font-weight:bold; -} - -.attentiontitle,.cautiontitle,.dangertitle,.importanttitle,.remembertitle,.restrictiontitle{ -font-weight:bold; -} -.note,.tip,.fastpath{ -background: #F2F2F2 url(../images/ico_note.png); -background-repeat: no-repeat; -background-position: top left; -padding:5px; -padding-left:40px; -padding-bottom:10px; -border:#999 1px dotted; -color:#666666; -margin:5px; +.notetitle, .tiptitle, .fastpathtitle { + font-weight: bold } -.attention,.caution,.danger,.important,.remember,.restriction{ -background: #F2F2F2 url(../images/ico_note_attention.png); -background-repeat:no-repeat; -background-position:top left; -padding:5px; -padding-left:40px; -padding-bottom:10px; -border:#999 1px dotted; -color:#666666; -margin:5px; -} - -/* -------------------------------- -Top navigation -------------------------------- -*/ - -.nav{ -text-align:right; -margin-right:9px; -} -.nav img{ - box-shadow: none; -} -.nav-main{ -margin-top:22px; -margin-left: 20px; -text-align:left -} -.nav-main-content{ -margin-right: 20px; -display:inline-block; -} -.nav-subtitle{ -margin-left: 220px; +.attentiontitle, .cautiontitle, .dangertitle, .importanttitle, .remembertitle, .restrictiontitle { + font-weight: bold } -header{ -background: none repeat scroll 0% 0% rgb(255,255,255); -border-radius: 10px 10px 10px 10px; -padding: 10px; -box-shadow: 0px 0px 10px rgba(0,0,0,0.1); +.note, .tip, .fastpath { + background: #F2F2F2 url('../images/ico_note.png'); + background-repeat: no-repeat; + background-position: top left; + padding: 5px; + padding-left: 40px; + padding-bottom: 10px; + border: #999 1px dotted; + color: #666666; + margin: 5px; } -header h1{ -display:block; -line-height: 70px; -font-size: 30px; -margin-left: 223px; -} -header img{ -box-shadow: none; -border: 0; -position: absolute; -left: 30px; -} -.qtref{ -display: block; -top: -76px; -z-index: 1; -font-size:11px; -padding-right:10px; -float:right; +.attention, .caution, .danger, .important, .remember, .restriction { + background: #F2F2F2 url('../images/ico_note_attention.png'); + background-repeat: no-repeat; + background-position: top left; + padding: 5px; + padding-left: 40px; + padding-bottom: 10px; + border: #999 1px dotted; + color: #666666; + margin: 5px; } -.naviNextPrevious{ -display: block; -text-align: right; -float:right; -z-index:1; -padding-right:10px; -padding-top:4px; +.qtref { + display: block; + top: -76px; + z-index: 1; + font-size: 11px; + padding-right: 10px; + float: right; } - -.naviNextPrevious > a.prevPage { -background-image:url(../images/btn_prev.png); -background-repeat:no-repeat; -background-position:left; -padding-left:20px; -height:20px; -padding-left:20px; +.naviNextPrevious { + display: block; + text-align: right; + float: right; + z-index: 1; + padding-right: 10px; + padding-top: 4px; } .naviNextPrevious > a.nextPage { -background-image:url(../images/btn_next.png); -background-repeat:no-repeat; -background-position:right; -padding-right:20px; -height:20px; -margin-left:30px; -} - -.breadcrumb{ -display: block; -position: relative; -z-index:1; -height:20px; -padding:0px; -margin:0px; -padding-left:10px; -padding-top:12px; -margin-left:-5px; -margin-right:-5px; -} - -.breadcrumb ul{ - margin:0px; - padding:0px; -} - -.breadcrumb ul li{ -list-style-type:none; -padding:0; -margin:0; -height:20px; -} - -.breadcrumb li{ -float:left; -} - -.breadcrumb .first { -background:url(../images/home.png); -background-position:left; -background-repeat:no-repeat; -padding-left:20px; -} - - -.breadcrumb li a{ -display:block; -text-decoration:none; -background:url(../images/arrow.png); -background-repeat:no-repeat; -background-position:right; -padding-right:25px; -padding-left:10px; -} - -.breadcrumb li a:hover{ -color:#909090; -display:block; -text-decoration:none; -background:url(../images/arrow.png); -background-repeat:no-repeat; -background-position:right; -padding-right:20px; -padding-left:10px; -} + background-image: url('../images/btn_next.png'); + background-repeat: no-repeat; + background-position: right; + padding-right: 20px; + height: 20px; + margin-left: 30px; + } -/* ------------ -footer and license ------------ -*/ -.footer{ -text-align:center -} -/* ------------ -main content ------------ -*/ -.line{ -text-align: left; -background: none repeat scroll 0% 0% rgb(255,255,255); -border-radius: 10px 10px 10px 10px; -padding-left: 14px; -padding-right: 14px; -box-shadow: 0px 0px 10px rgba(0,0,0,0.1); -margin-top: 10px; -padding-bottom: 35px; +.naviNextPrevious > a.prevPage { + background-image: url('../images/btn_prev.png'); + background-repeat: no-repeat; + background-position: left; + padding-left: 20px; + height: 20px; + padding-left: 20px; + } + +.navigationbar { + background-repeat: no-repeat; + height: 33px; + margin: 0px !important; + padding: 0px !important; + border-bottom: 1px solid rgb(209, 209, 209); + background-image: -moz-linear-gradient(center top , rgb(246, 245, 245), rgb(239, 239, 239)); + background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0.0, #efefef), color-stop(0.5, #f6f5f5) ); + border-radius: 10px 10px 0px 0px; +} + +.navigationbar ul { + margin: 0px; + padding: 8px 0px 15px 15px; + height: 20px; + } + +.navigationbar li { + list-style-type: none; + float: left; + font-size: 15px; + } + + .navigationbar li a { + display: block; + text-decoration: none; + background: url('../images/arrow_bc.png'); + background-repeat: no-repeat; + background-position: right; + padding-right: 25px; + font-size: inherit; + } + +#buildversion { + font-style: italic; + font-size: small; + float: right; + margin-right: 5px; } - -/* table of content -no display -*/ - /* ----------- headers ----------- */ - -@media screen{ -.title{ -color:#313131; -font-size: 18px; -font-weight: normal; -left: 0; -padding-bottom: 20px; -padding-left: 10px; -padding-top: 20px; -border-bottom: 1px #CCC solid ; -font-weight:bold; -margin-left:0px; -margin-right:0px; -} +@media screen { + .title { + color: #313131; + font-size: 18px; + font-weight: normal; + left: 0; + padding-bottom: 20px; + padding-left: 10px; + padding-top: 20px; + border-bottom: 1px #CCC solid; + font-weight: bold; + margin-left: 0px; + margin-right: 0px; + } } h1 { -margin: 0; + margin: 0 } h2, p.h2 { -font: 500 16px/1.2 Arial; -font-weight:100; -background-color:#F2F3F4; -padding:4px; -padding-left:14px; -margin-bottom:30px; -margin-top:30px; -margin-left:-10px; -margin-right:-5px; -border-top:#E0E0DE 1px solid; -border-bottom: #E0E0DE 1px solid; -max-width: 99%; -overflow: hidden; + font: 500 16px/1.2 Arial; + font-weight: 100; + background-color: #F2F3F4; + padding: 4px; + padding-left: 14px; + margin-bottom: 30px; + margin-top: 30px; + margin-left: -10px; + margin-right: -5px; + border-top: #E0E0DE 1px solid; + border-bottom: #E0E0DE 1px solid; + max-width: 99%; + overflow: hidden; +} + +h3 { + font: 500 14px/1.2 Arial; + font-weight: 100; + text-decoration: underline; + margin-bottom: 30px; + margin-top: 30px; +} + +h3.fn, span.fn { + border-width: 1px; + border-style: solid; + border-color: #E6E6E6; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + word-spacing: 3px; + padding: 5px 5px; + text-decoration: none; + font-weight: bold; + max-width: 75%; + font-size: 14px; + margin: 0px; + margin-top: 45px; +} + +.name { + color: #1A1A1A +} + +.type { + color: #808080 } -h3{ - -font: 500 14px/1.2 Arial; -font-weight:100; -text-decoration:underline; -margin-bottom:30px; -margin-top:30px; +@media print { + .title { + color: #0066CB; + font-size: 32px; + font-weight: normal; + left: 0; + position: absolute; + right: 0; + top: 0; + } } -h3.fn,span.fn{ -border-width: 1px; -border-style: solid; -border-color: #E6E6E6; --moz-border-radius: 7px 7px 7px 7px; --webkit-border-radius: 7px 7px 7px 7px; -border-radius: 7px 7px 7px 7px; -background-color: #F6F6F6; -word-spacing: 3px; -padding: 5px 5px; -text-decoration:none; -font-weight:bold; -max-width:75%; -font-size:14px; -margin:0px; -margin-top:45px; +/* +----------------- +table styles +----------------- +*/ +.table img { + border: none; + margin-left: 0px; + -moz-box-shadow: 0px 0px 0px #fff; + -webkit-box-shadow: 0px 0px 0px #fff; + box-shadow: 0px 0px 0px #fff; } -.name{ -color:#1A1A1A; -} -.type{ -color:#808080; -} +/* table with border alternative colours*/ +table, pre { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #E6E6E6; + border-collapse: separate; + font-size: 12px; + line-height: 1.2; + margin-bottom: 25px; + margin-left: 15px; + font-size: 12px; + line-height: 1.2; + margin-bottom: 25px; + margin-left: 15px; +} + + table tr.even { + background-color: white; + color: #66666E; + } + + table tr.odd { + background-color: #F6F6F6; + color: #66666E; + } + + table thead { + text-align: left; + padding-left: 20px; + background-color: #e1e0e0; + border-left: none; + border-right: none; + } + + table thead th { + padding-top: 5px; + padding-left: 10px; + padding-bottom: 5px; + border-bottom: 2px solid #D1D1D1; + padding-right: 10px; + } + + table td { + padding: 3px 15px 3px 20px; + border-bottom: #CCC dotted 1px; + } + + table th { + text-align: left; + padding-left: 20px; + } + + table p { + margin: 0px + } +/* table bodless & white*/ -@media print { -.title { -color:#0066CB; -font-family:Arial, Helvetica; -font-size: 32px; -font-weight: normal; -left: 0; -position: absolute; -right: 0; -top: 0; -} +.borderless { + border-radius: 0px 0px 0px 0px; + background-color: #fff; + border: 1px solid #fff; } +.borderless td { + border: none; + border-bottom: #fff dotted 1px; + } + +.borderless tr { + background-color: #FFF; + color: #66666E; + } /* ------------------ -table styles ------------------ +----------- +List +----------- */ -.table img { -border:none; -margin-left:0px; --moz-box-shadow:0px 0px 0px #fff; --webkit-box-shadow: 0px 0px 0px #fff; -box-shadow: 0px 0px 0px #fff; + +ul { + padding-bottom: 2px } -/* table with border alternative colours*/ +li { + margin-bottom: 10px; + padding-left: 8px; + list-style: outside; + list-style-type: square; + text-align: left; +} - table,pre{ --moz-border-radius: 7px 7px 7px 7px; --webkit-border-radius: 7px 7px 7px 7px; - border-radius: 7px 7px 7px 7px; -background-color: #F6F6F6; -border: 1px solid #E6E6E6; -border-collapse: separate; -font-size: 12px; -line-height: 1.2; -margin-bottom: 25px; -margin-left: 15px; -font-size: 12px; -line-height: 1.2; -margin-bottom: 25px; -margin-left: 15px; +ol { + margin: 10px; + padding: 0; } + ol > li { + margin-left: 30px; + padding-left: 8px; + list-style: decimal; + } -table th{ -text-align:left; -padding-left:20px; +.centerAlign { + text-align: left } -table td { -padding: 3px 15px 3px 20px; -border-bottom:#CCC dotted 1px; +.cpp { + display: block; + margin: 10px; + overflow: auto; + padding: 20px 20px 20px 20px; } -table p { margin:0px;} -table tr.even { -background-color: white; -color: #66666E; +.js { + display: block; + margin: 10px; + overflow: auto; + padding: 20px 20px 20px 20px; } -table tr.odd { -background-color: #F6F6F6; -color: #66666E; +.footerNavi { + width: auto; + text-align: right; + margin-top: 50px; + z-index: 1; } - -table thead { -text-align:left; -padding-left:20px; -background-color:#e1e0e0; -border-left:none; -border-right:none; +.memItemLeft { + padding-right: 3px } -table thead th { -padding-top:5px; -padding-left:10px; -padding-bottom:5px; -border-bottom: 2px solid #D1D1D1; -padding-right:10px; +.memItemRight { + padding: 3px 15px 3px 0 } +.qml { + display: block; + margin: 10px; + overflow: auto; + padding: 20px 20px 20px 20px; +} -/* table bodless & white*/ +.qmldefault { + padding-left: 5px; + float: right; + color: red; +} -.borderless { -border-radius: 0px 0px 0px 0px; -background-color: #fff; -border: 1px solid #fff; +.qmlreadonly { + padding-left: 5px; + float: right; + color: #254117; } -.borderless tr { -background-color: #FFF; -color: #66666E; +.rightAlign { + padding: 3px 5px 3px 10px; + text-align: right; } -.borderless td { -border:none; -border-bottom:#fff dotted 1px; +.qmldoc { + margin-left: 15px } /* ----------- -List +Content table ----------- */ -ul{ -padding-bottom:2px; +@media print { + .toc { + float: right; + clear: right; + padding-bottom: 10px; + padding-top: 50px; + width: 100%; + background-image: url('../images/bgrContent.png'); + background-position: top; + background-repeat: no-repeat; + } +} + +@media screen { + .toc { + clear: both; + clear: right; + position: relative; + top: 83px; + float: right; + vertical-align: top; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background: #FFF url('../images/bgrContent.png'); + background-position: top; + background-repeat: repeat-x; + border: 1px solid #E6E6E6; + padding-left: 5px; + padding-bottom: 10px; + height: auto; + width: 200px; + text-align: left; + margin-left: 20px; + } +} + +.toc h3 { + text-decoration: none +} + +.toc h3 { + font: 500 14px/1.2 Arial; + font-weight: 100; + padding: 0px; + margin: 0px; + padding-top: 5px; + padding-left: 5px; +} + +.toc ul { + padding-left: 10px; + padding-right: 5px; + padding-top: 10px; +} + +.toc ul li { + margin-left: 15px; + list-style-image: url('../images/blu_dot.png'); + list-style: outside; + marker-offset: 0px; + margin-bottom: 8px; + padding-left: 0px; + } + +.toc .level1 { + border: none +} + +.toc .level2 { + border: none; + margin-left: 25px; +} + +.level3 { + border: none; + margin-left: 30px; +} + +.clearfix { + clear: both } -li { -margin-bottom: 10px; -padding-left: 8px; -list-style:outside; -list-style-type:square; -text-align:left; +/* start index box */ + +.indexbox { + width: 100%; + display: inline-block; } +.indexbox .indexIcon { + width: 11% + } -ol{ -margin:10px; -padding:0; -} + .indexbox .indexIcon span { + display: block + } -ol > li{ -margin-left: 30px; -padding-left:8px; -list-style:decimal; +.indexboxcont { + display: block } -.centerAlign{ -text-align: left; -} +.indexboxcont .sectionlist { + display: inline-block; + vertical-align: top; + width: 32.5%; + padding: 0; + } -.cpp{ -display: block; -margin: 10px; -overflow: auto; -padding: 20px 20px 20px 20px; -} + .indexboxcont .sectionlist ul { + margin-bottom: 20px + } -.js{ -display: block; -margin: 10px; -overflow: auto; -padding: 20px 20px 20px 20px; -} + .indexboxcont .sectionlist ul li { + line-height: 1.5 + } -.footer{ -margin-top: 50px; -padding-left:5px; -margin-bottom: 10px; -font-size:10px; -border-top: 1px solid #999; -padding-top:11px; -} +.indexboxcont .indexIcon { + width: 11%; + *width: 18%; + _width: 18%; + overflow: hidden; + } -.footerNavi{ -width:auto; -text-align:right; -margin-top:50px; -z-index:1; -} +.indexboxcont .section { + float: left + } -.memItemLeft{ -padding-right: 3px; +.indexboxcont .section { + display: inline-block; + width: 49%; + *width: 42%; + _width: 42%; + padding: 0 2% 0 1%; + vertical-align: top; + } + + .indexboxcont .section p { + padding-top: 20px; + padding-bottom: 20px; + } + +.indexboxcont:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; } -.memItemRight{ -padding: 3px 15px 3px 0; -} +/* +----------- +Landing page +----------- +*/ -.qml{ -display: block; -margin: 10px; -overflow: auto; -padding: 20px 20px 20px 20px; +.col-group { + white-space: nowrap; + vertical-align: top; } -.qmldefault{ -padding-left: 5px; -float: right; -color: red; +.col-1 { + display: inline-block; + white-space: normal; + width: 70%; + height: 100%; + float: left; } -.qmlreadonly{ -padding-left: 5px; -float: right; -color: #254117; -} +.col-1 h1 { + margin: 20px 0 0 0 + } -.rightAlign{ -padding: 3px 5px 3px 10px; -text-align: right; +.col-2 { + display: inline-block; + white-space: normal; + width: 25%; + margin: 0 0 0 50px; } -.qmldoc { -margin-left: 15px; +.sectionlist { + width: 100% !important } /* ------------ -Content table ------------ +Additions from Qt Project */ -@media print{ -.toc { -float: right; -clear: right; -padding-bottom: 10px; -padding-top: 50px; -width: 100%; -background-image:url(../images/bgrContent.png); -background-position:top; -background-repeat:no-repeat; -} +body { + background: #E8E8E8; + margin: 0px; + font-family: "Open Sans",sans-serif !important; } -@media screen{ -.toc{ -clear: both; -clear: right; -position: relative; -top: 83px; -float:right; -vertical-align:top; --moz-border-radius: 7px 7px 7px 7px; --webkit-border-radius: 7px 7px 7px 7px; -border-radius: 7px 7px 7px 7px; - background:#FFF url(../images/bgrContent.png); -background-position:top; -background-repeat:repeat-x; -border: 1px solid #E6E6E6; -padding-left:5px; -padding-bottom:10px; -height: auto; -width: 200px; -text-align:left; -margin-left:20px; +.qt13a-twoCol { + width: 23.46939%; + float: left; + margin-right: 2.04082%; + display: inline; } + +.qt13a-fourCol { + width: 48.97959%; + float: left; + margin-right: 2.04082%; + display: inline; } -.toc h3{ -text-decoration:none; +.qt13a-sixCol { + width: 70.4898%; + float: left; + margin-right: 2.04082%; + display: inline; } -.toc h3{font: 500 14px/1.2 Arial; -font-weight:100; -padding:0px; -margin:0px; -padding-top:5px; -padding-left:5px; +.qt13a-eightCol { + width: 100%; + float: left; + margin-right: 2.04082%; + display: inline; } +.qt13a-fiveCol { + width: 17.35537%; + float: left; + margin-right: 3.30579%; + display: inline; +} -.toc ul{ -padding-left:10px; -padding-right:5px; -padding-top:10px; +.qt13a-fiveCol:nth-child(2n) { + float: left; + margin-right: 3.30579%; } -.toc ul li{ -margin-left:15px; -list-style-image:url(../images/blu_dot.png); -list-style:outside; -marker-offset: 0px; -margin-bottom:8px; -padding-left:0px; +.qt13a-omega { + float: right; + margin-right: 0; + *margin-left: -20px; + display: inline; } -.toc .level1{ -border:none;} +.qt13a-last { + float: right; + margin-right: 0; + *margin-left: -20px; + display: inline; +} + +.qt13a-container { + *zoom: 1; + padding-left: 20px; + padding-right: 20px; + margin-left: auto; + margin-right: auto; + max-width: 1045px; +} + +.qt13a-container:after { + content: ""; + display: table; + clear: both; +} + +.qt13a-container.qt13a-dynamic { + max-width: 1295px +} + +.qt13a-no-bg-img { + background-image: none !important +} + +.qt13a-wrapper { + overflow: hidden +} + +.content-view { + position: relative; + overflow: hidden; +} + +#qt13a-header { + background: url('../images/Qt-header-bg.jpg') repeat; + min-height: 126px; + padding: 0; + margin: 0; + min-width: 1045px; + margin-bottom: 18px; +} + + #qt13a-header .qt13a-nav-divider-left { + border-left: 1px solid #35322f; + padding-left: 10px; + margin-left: 5px; + font-size: 13px; + } + + #qt13a-header #qt13a-title_nav { + padding-top: 34px; + width: 87.37374%; + float: left; + margin-right: 1.0101%; + display: inline; + float: right; + margin-right: 0; + *margin-left: -20px; + display: inline; + } + + #qt13a-header .qt13a-gradient { + background: url('../images/Qt-gradient.png') repeat-x; + background-position: bottom; + margin: 0; + min-height: 126px; + padding: 0; + } + + #qt13a-header p.qt13a-title { + font-size: 24px; + margin: 0 0 0 0px; + letter-spacing: -1px; + color: #35322f; + font-weight: 600; + } + + #qt13a-header p.qt13a-title a { + font-weight: 600; + color: #35322f; + } + + #qt13a-header p.qt13a-title a:hover { + color: #35322f; + text-decoration: none; + } + + #qt13a-header #qt13a-title { + padding: 0px 0 0 0px; + padding-bottom: 0px; + } + + #qt13a-header #qt13a-logo { + float: left; + width: 11.61616%; + float: left; + margin-right: 1.0101%; + display: inline; + margin: 20px 0px 10px 0; + min-width: 50px; + } + + #qt13a-header #qt13a-logo .qt13a-site-logo { + background: url('../images/Qt-logo.png') no-repeat; + text-indent: -100em; + overflow: hidden; + display: block; + height: 90px; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; + } + + #qt13a-header #qt13a-logo img { + float: left; + border: 0; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; + } + + #qt13a-header .qt13a-nav { + background: none + } + + #qt13a-header .qt13a-nav .qt13a-nav-divider-left { + border-left: 1px solid #35322f; + padding-left: 20px; + } + + #qt13a-header .qt13a-nav .qt13a-nav-small a { + font-size: 13px + } + + #qt13a-header .qt13a-nav ul { + margin: 0 0 0 0px; + padding: 11px 0 0; + background: none; + } + + #qt13a-header .qt13a-nav ul li.devnet-active a { + color: #fff + } + + #qt13a-header .qt13a-nav ul li { + display: inline-block; + width: auto; + padding: 0 2.88% 0 0; + margin: 0; + border: 0; + *display: inline; + zoom: 1; + } + + #qt13a-header .qt13a-nav ul li a { + color: #35322f; + margin: 0; + padding: 0; + line-height: 18px; + font-size: 18px; + } + + #qt13a-header .qt13a-nav ul li a:hover, #qt13a-header .qt13a-nav ul li a:active, #qt13a-header .qt13a-nav ul li a.active { + color: #fff; + text-decoration: none; + } + +#qt13a-register_search { + display: block; + font-variant: 400; + float: right; +} + +#qt13a-register { + padding: 34px 0px 0; + float: right; + text-align: right; + color: #1e1b18; +} + + #qt13a-register .qt13a-link-divider { + padding: 0 5px + } + + #qt13a-register a { + color: #1e1b18; + font-weight: 400; + font-size: 13px; + padding-left: 13px; + } + + #qt13a-register a:visited { + color: #1e1b18 + } + + #qt13a-register a:hover { + color: #fff; + text-decoration: none; + } + +#search { + margin-top: 23px +} + +#qt13a-footer { + background: url('../images/Qt-header-bg.jpg') repeat; + margin: 0; +} + + #qt13a-footer .qt13a-container { + padding: 36px 0 + } + + #qt13a-footer .qt13a-gradient { + background: url('../images/Qt-dark_gradient.png') repeat-x; + background-position: bottom; + margin: 0; + min-height: 126px; + padding: 0; + } + + #qt13a-footer .qt13a-shadow { + background: transparent url('../images/Qt-footer_shadow.png') repeat-x top center + } + + #qt13a-footer .qt13a-last { + float: right; + margin-right: 0; + *margin-left: -20px; + display: inline; + } + + #qt13a-footer ul { + width: 17.35537%; + float: left; + margin-right: 3.30579%; + display: inline; + padding-left: 0; + list-style-type: none; + } + + #qt13a-footer ul li a.qt13a-some-icon { + width: 32px; + height: 32px; + background-repeat: none; + text-indent: -300em; + overflow: hidden; + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + *vertical-align: auto; + zoom: 1; + *display: inline; + } -.toc .level2{ -border:none; -margin-left: 25px; -} + #qt13a-footer ul li a { + font-family: "Open Sans",sans-serif; + font-size: 13px; + color: #35322f; + padding: 0; + font-weight: 400; + } -.level3{ -border:none; -margin-left: 30px; -} + #qt13a-footer ul li a:hover, #qt13a-footer ul li a:active { + color: #35322f; + text-decoration: underline; + } -.clearfix{ -clear:both;} + #qt13a-footer .qt13a-title a, #qt13a-footer .qt13a-title { + padding: 18px 0 18px; + font-weight: 400; + letter-spacing: -0.5pt; + color: #35322f; + font-size: 18px; + margin: 0; + } -/* start index box */ -.indexbox -{ -width: 100%; -display:inline-block; +.qt13a-copyright { + border-top: 1px solid #000; + background: url('../images/Qt-footer-bg.jpg') repeat; + margin: 0; + padding: 36px 0; + font-weight: 400; + font-size: 0.84615em; + line-height: 1.63636em; } -.indexboxcont -{ -display: block; +.qt13a-copyright p { + padding: 0; + color: #aeadac; + font-size: 11px; + } -} +.qt13a-copyright a { + color: #328930 + } -.indexboxcont .section -{ -display: inline-block; -width: 49%; -*width:42%; -_width:42%; -padding:0 2% 0 1%; -vertical-align:top; -} +.qt13a-copyright a:visited { + color: #328930 + } -.indexboxcont .indexIcon -{ -width: 11%; -*width:18%; -_width:18%; -overflow:hidden; +.searchbox { + display: block; + overflow: hidden; + padding: 0px 35px 0 5px; } -.indexboxcont .section { - float: left; +.content-view { + position: relative; + overflow: hidden; } -.indexboxcont .section p -{ -padding-top: 20px; -padding-bottom: 20px; -} -.indexboxcont .sectionlist -{ -display: inline-block; -vertical-align:top; -width: 32.5%; -padding: 0; -} -.indexboxcont .sectionlist ul -{ -margin-bottom: 20px; +p, li, p.forum-overview-title, p.forum-description, p.desc, p.forum-lastpost, div.navigationbars li, div.block-profile div { + font-size: 13px } -.indexboxcont .sectionlist ul li -{ -line-height: 1.5; +p.forum-description.desc { + font-size: 13px !important } -.content .indexboxcont li -{ -font: normal bold 13px/1 Verdana; +.steps li { + font-size: 16px } -.content .normallist li -{ -font: normal 13px/1 Verdana; +div.license p, div.notes p { + font-size: 12px !important } -.indexbox .indexIcon { -width: 11%; +a { + color: #44a51c; + text-decoration: none; } -.indexbox .indexIcon span -{ -display: block; +.wrap { + padding-left: 30px } -.indexboxcont:after -{ -content: "."; -display: block; -height: 0; -clear: both; -visibility: hidden; +a:visited { + color: #007330; + text-align: left; } -/* ------------ -Landing page ------------ -*/ -.col-group { - white-space: nowrap; - vertical-align: top; +a:hover { + color: #44a51c; + text-align: left; } -.col-1 { - display: inline-block; - white-space: normal; - width: 70%; - height: 100%; - float: left; +a:visited:hover { + color: #44a51c; + text-align: left; } -.col-1 h1 { - margin: 20px 0 0 0; +a:link { + color: #007330; + text-decoration: none; + text-align: left; } -.col-2 { - display: inline-block; - white-space: normal; - width: 25%; - margin: 0 0 0 50px; +.main { + padding: 0px 30px 30px 30px } -.sectionlist { - width: 100% !important; +.main-rounded { + display: inline-block; + background: none repeat scroll 0% 0% rgb(255,255,255); + width: 100%; + border: 1px solid #DADADA; + border-radius: 10px 10px 10px 10px; + box-shadow: 0 0 3px #C4C4C4; + padding-bottom: 30px; } diff --git a/examples/widgets/dialogs/standarddialogs/dialog.cpp b/examples/widgets/dialogs/standarddialogs/dialog.cpp index c626b63b7d..fdd3633950 100644 --- a/examples/widgets/dialogs/standarddialogs/dialog.cpp +++ b/examples/widgets/dialogs/standarddialogs/dialog.cpp @@ -121,6 +121,10 @@ Dialog::Dialog(QWidget *parent) textLabel->setFrameStyle(frameStyle); QPushButton *textButton = new QPushButton(tr("QInputDialog::get&Text()")); + multiLineTextLabel = new QLabel; + multiLineTextLabel->setFrameStyle(frameStyle); + QPushButton *multiLineTextButton = new QPushButton(tr("QInputDialog::get&MultiLineText()")); + colorLabel = new QLabel; colorLabel->setFrameStyle(frameStyle); QPushButton *colorButton = new QPushButton(tr("QColorDialog::get&Color()")); @@ -177,6 +181,7 @@ Dialog::Dialog(QWidget *parent) connect(doubleButton, SIGNAL(clicked()), this, SLOT(setDouble())); connect(itemButton, SIGNAL(clicked()), this, SLOT(setItem())); connect(textButton, SIGNAL(clicked()), this, SLOT(setText())); + connect(multiLineTextButton, SIGNAL(clicked()), this, SLOT(setMultiLineText())); connect(colorButton, SIGNAL(clicked()), this, SLOT(setColor())); connect(fontButton, SIGNAL(clicked()), this, SLOT(setFont())); connect(directoryButton, SIGNAL(clicked()), @@ -206,7 +211,9 @@ Dialog::Dialog(QWidget *parent) layout->addWidget(itemLabel, 2, 1); layout->addWidget(textButton, 3, 0); layout->addWidget(textLabel, 3, 1); - layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding), 4, 0); + layout->addWidget(multiLineTextButton, 4, 0); + layout->addWidget(multiLineTextLabel, 4, 1); + layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding), 5, 0); toolbox->addItem(page, tr("Input Dialogs")); const QString doNotUseNativeDialog = tr("Do not use native dialog"); @@ -327,6 +334,17 @@ void Dialog::setText() //! [3] } +void Dialog::setMultiLineText() +{ +//! [4] + bool ok; + QString text = QInputDialog::getMultiLineText(this, tr("QInputDialog::getMultiLineText()"), + tr("Address:"), "John Doe\nFreedom Street", &ok); + if (ok && !text.isEmpty()) + multiLineTextLabel->setText(text); +//! [4] +} + void Dialog::setColor() { const QColorDialog::ColorDialogOptions options = QFlag(colorDialogOptionsWidget->value()); diff --git a/examples/widgets/dialogs/standarddialogs/dialog.h b/examples/widgets/dialogs/standarddialogs/dialog.h index 27b1de98cb..d6272c440e 100644 --- a/examples/widgets/dialogs/standarddialogs/dialog.h +++ b/examples/widgets/dialogs/standarddialogs/dialog.h @@ -63,6 +63,7 @@ private slots: void setDouble(); void setItem(); void setText(); + void setMultiLineText(); void setColor(); void setFont(); void setExistingDirectory(); @@ -80,6 +81,7 @@ private: QLabel *doubleLabel; QLabel *itemLabel; QLabel *textLabel; + QLabel *multiLineTextLabel; QLabel *colorLabel; QLabel *fontLabel; QLabel *directoryLabel; diff --git a/examples/widgets/doc/src/addressbook-fr.qdoc b/examples/widgets/doc/src/addressbook-fr.qdoc index 9a7bc3a6b7..7d15d99597 100644 --- a/examples/widgets/doc/src/addressbook-fr.qdoc +++ b/examples/widgets/doc/src/addressbook-fr.qdoc @@ -71,8 +71,6 @@ */ /*! - \page tutorials-addressbook-fr-part1.html - \example tutorials/addressbook-fr/part1 \title Carnet d'adresses 1 - Conception de l'interface utilisateur @@ -229,8 +227,6 @@ */ /*! - \page tutorials-addressbook-fr-part2.html - \example tutorials/addressbook-fr/part2 \title Carnet d'adresses 2 - Ajouter des adresses @@ -389,8 +385,6 @@ */ /*! - \page tutorials-addressbook-fr-part3.html - \example tutorials/addressbook-fr/part3 \title Carnet d'adresses 3 - Navigation entre les éléments @@ -509,8 +503,6 @@ /*! - \page tutorials-addressbook-fr-part4.html - \example tutorials/addressbook-fr/part4 \title Carnet d'Adresses 4 - éditer et supprimer des adresses @@ -659,8 +651,6 @@ */ /*! - \page tutorials-addressbook-fr-part5.html - \example tutorials/addressbook-fr/part5 \title Carnet d'adresse 5 - Ajout d'une fonction de recherche @@ -808,8 +798,6 @@ */ /*! - \page tutorials-addressbook-part6.html - \example tutorials/addressbook-fr/part6 \title Carnet d'Adresses 6 - Sauvegarde et chargement @@ -945,8 +933,6 @@ */ /*! - \page tutorials-addressbook-fr-part7.html - \example tutorials/addressbook-fr/part7 \title Carnet d'adresse 7 - Fonctionnalités avancées diff --git a/examples/widgets/doc/src/addressbook-tutorial.qdoc b/examples/widgets/doc/src/addressbook-tutorial.qdoc index 089ab2319d..78517f80d7 100644 --- a/examples/widgets/doc/src/addressbook-tutorial.qdoc +++ b/examples/widgets/doc/src/addressbook-tutorial.qdoc @@ -77,8 +77,6 @@ */ /*! - \page tutorials-addressbook-part1.html - \example tutorials/addressbook/part1 \title Part 1 - Designing the User Interface @@ -231,8 +229,6 @@ */ /*! - \page tutorials-addressbook-part2.html - \example tutorials/addressbook/part2 \title Part 2 - Adding Addresses @@ -382,8 +378,6 @@ */ /*! - \page tutorials-addressbook-part3.html - \example tutorials/addressbook/part3 \title Part 3 - Navigating between Entries @@ -499,8 +493,6 @@ */ /*! - \page tutorials-addressbook-part4.html - \example tutorials/addressbook/part4 \title Part 4 - Editing and Removing Addresses @@ -633,8 +625,6 @@ */ /*! - \page tutorials-addressbook-part5.html - \example tutorials/addressbook/part5 \title Part 5 - Adding a Find Function @@ -777,8 +767,6 @@ */ /*! - \page tutorials-addressbook-part6.html - \example tutorials/addressbook/part6 \title Part 6 - Loading and Saving @@ -899,8 +887,6 @@ */ /*! - \page tutorials-addressbook-part7.html - \example tutorials/addressbook/part7 \title Part 7 - Additional Features diff --git a/examples/widgets/itemviews/spreadsheet/main.cpp b/examples/widgets/itemviews/spreadsheet/main.cpp index 1cc9205d7e..f518986bc5 100644 --- a/examples/widgets/itemviews/spreadsheet/main.cpp +++ b/examples/widgets/itemviews/spreadsheet/main.cpp @@ -42,14 +42,15 @@ #include "spreadsheet.h" #include <QApplication> +#include <QLayout> int main(int argc, char** argv) { Q_INIT_RESOURCE(spreadsheet); QApplication app(argc, argv); SpreadSheet sheet(10, 6); sheet.setWindowIcon(QPixmap(":/images/interview.png")); - sheet.resize(640, 420); sheet.show(); + sheet.layout()->setSizeConstraint(QLayout::SetFixedSize); return app.exec(); } diff --git a/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp b/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp index 59d29f0e61..6fab0c2aae 100644 --- a/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp +++ b/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp @@ -64,6 +64,7 @@ SpreadSheet::SpreadSheet(int rows, int cols, QWidget *parent) toolBar->addWidget(formulaInput); table = new QTableWidget(rows, cols, this); + table->setSizeAdjustPolicy(QTableWidget::AdjustToContents); for (int c = 0; c < cols; ++c) { QString character(QChar('A' + c)); table->setHorizontalHeaderItem(c, new QTableWidgetItem(character)); diff --git a/examples/widgets/widgets/spinboxes/window.cpp b/examples/widgets/widgets/spinboxes/window.cpp index 8c35f93c56..acce642ec6 100644 --- a/examples/widgets/widgets/spinboxes/window.cpp +++ b/examples/widgets/widgets/spinboxes/window.cpp @@ -94,6 +94,14 @@ void Window::createSpinBoxes() priceSpinBox->setValue(99); //! [4] //! [5] + QLabel *hexLabel = new QLabel(tr("Enter a value between " + "%1 and %2:").arg('-' + QString::number(31, 16)).arg(QString::number(31, 16))); + QSpinBox *hexSpinBox = new QSpinBox; + hexSpinBox->setRange(-31, 31); + hexSpinBox->setSingleStep(1); + hexSpinBox->setValue(0); + hexSpinBox->setDisplayIntegerBase(16); + QVBoxLayout *spinBoxLayout = new QVBoxLayout; spinBoxLayout->addWidget(integerLabel); spinBoxLayout->addWidget(integerSpinBox); @@ -101,6 +109,8 @@ void Window::createSpinBoxes() spinBoxLayout->addWidget(zoomSpinBox); spinBoxLayout->addWidget(priceLabel); spinBoxLayout->addWidget(priceSpinBox); + spinBoxLayout->addWidget(hexLabel); + spinBoxLayout->addWidget(hexSpinBox); spinBoxesGroup->setLayout(spinBoxLayout); } //! [5] diff --git a/mkspecs/blackberry-armv7le-qcc/qmake.conf b/mkspecs/blackberry-armv7le-qcc/qmake.conf index 2e24e4e0d3..cfcd2aecf0 100644 --- a/mkspecs/blackberry-armv7le-qcc/qmake.conf +++ b/mkspecs/blackberry-armv7le-qcc/qmake.conf @@ -16,6 +16,7 @@ contains(QT_CONFIG, stack-protector-strong) { } QMAKE_CFLAGS += -mcpu=cortex-a9 -mtune=cortex-a9 -mthumb -D_FORTIFY_SOURCE=2 +QMAKE_CXXFLAGS += -mcpu=cortex-a9 -mtune=cortex-a9 -mthumb -D_FORTIFY_SOURCE=2 QMAKE_LFLAGS_SHLIB += -Wl,-z,relro -Wl,-z,now diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf index 4f141351c1..ace2496f10 100644 --- a/mkspecs/common/clang.conf +++ b/mkspecs/common/clang.conf @@ -20,13 +20,3 @@ QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE QMAKE_CXXFLAGS_CXX11 = -std=c++11 QMAKE_LFLAGS_CXX11 = - -QMAKE_CFLAGS_SSE2 += -msse2 -QMAKE_CFLAGS_SSE3 += -msse3 -QMAKE_CFLAGS_SSSE3 += -mssse3 -QMAKE_CFLAGS_SSE4_1 += -msse4.1 -QMAKE_CFLAGS_SSE4_2 += -msse4.2 -QMAKE_CFLAGS_AVX += -mavx -QMAKE_CFLAGS_AVX2 += -mavx2 -QMAKE_CFLAGS_IWMMXT += -mcpu=iwmmxt -QMAKE_CFLAGS_NEON += -mfpu=neon diff --git a/mkspecs/common/ios/qmake.conf b/mkspecs/common/ios/qmake.conf index 39465aa765..3c477438a3 100644 --- a/mkspecs/common/ios/qmake.conf +++ b/mkspecs/common/ios/qmake.conf @@ -15,9 +15,6 @@ QMAKE_RANLIB = ranlib -s QMAKE_LINK = $$QMAKE_CXX QMAKE_LINK_SHLIB = $$QMAKE_CXX -# Basic iOS frameworks needed for any GUI app -QMAKE_LFLAGS += -framework Foundation -framework UIKit -framework QuartzCore -lz - # No OpenGL ES1 QMAKE_INCDIR_OPENGL_ES1 = QMAKE_LIBDIR_OPENGL_ES1 = diff --git a/mkspecs/common/mac.conf b/mkspecs/common/mac.conf index 1b480aa267..4421665370 100644 --- a/mkspecs/common/mac.conf +++ b/mkspecs/common/mac.conf @@ -4,7 +4,7 @@ !load(device_config): error(Could not successfully load device configuration) -QMAKE_PLATFORM += mac +QMAKE_PLATFORM += mac darwin QMAKE_RESOURCE = /Developer/Tools/Rez QMAKE_EXTENSION_SHLIB = dylib diff --git a/mkspecs/common/macx.conf b/mkspecs/common/macx.conf index 48efae5d1e..ad54612f22 100644 --- a/mkspecs/common/macx.conf +++ b/mkspecs/common/macx.conf @@ -2,7 +2,7 @@ # qmake configuration for common OS X # -QMAKE_PLATFORM += macx +QMAKE_PLATFORM += osx macx QMAKE_MAC_SDK = macosx include(mac.conf) diff --git a/mkspecs/darwin-g++/qmake.conf b/mkspecs/darwin-g++/qmake.conf index 24a6224b7c..ab333b1684 100644 --- a/mkspecs/darwin-g++/qmake.conf +++ b/mkspecs/darwin-g++/qmake.conf @@ -5,7 +5,7 @@ # MAKEFILE_GENERATOR = UNIX -QMAKE_PLATFORM = mac macx +QMAKE_PLATFORM = osx macx mac darwin CONFIG += native_precompiled_headers DEFINES += __USE_WS_X11__ diff --git a/mkspecs/devices/linux-imx6-g++/qeglfshooks_imx6.cpp b/mkspecs/devices/linux-imx6-g++/qeglfshooks_imx6.cpp index a1fd633c28..6f59b73921 100644 --- a/mkspecs/devices/linux-imx6-g++/qeglfshooks_imx6.cpp +++ b/mkspecs/devices/linux-imx6-g++/qeglfshooks_imx6.cpp @@ -51,6 +51,7 @@ public: virtual QSize screenSize() const; virtual EGLNativeWindowType createNativeWindow(const QSize &size, const QSurfaceFormat &format); virtual void destroyNativeWindow(EGLNativeWindowType window); + virtual EGLNativeDisplayType platformDisplay() const; private: QSize mScreenSize; @@ -72,6 +73,11 @@ QSize QEglFSImx6Hooks::screenSize() const return mScreenSize; } +EGLNativeDisplayType QEglFSImx6Hooks::platformDisplay() const +{ + return mNativeDisplay; +} + EGLNativeWindowType QEglFSImx6Hooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format) { Q_UNUSED(format); diff --git a/mkspecs/features/configure.prf b/mkspecs/features/configure.prf index b4569df6d5..39144e7216 100644 --- a/mkspecs/features/configure.prf +++ b/mkspecs/features/configure.prf @@ -7,9 +7,6 @@ equals(MAKEFILE_GENERATOR, UNIX) { QMAKE_MAKE = mingw32-make } else:if(equals(MAKEFILE_GENERATOR, MSVC.NET)|equals(MAKEFILE_GENERATOR, MSBUILD)) { QMAKE_MAKE = nmake -} else:ios { - # iOS unsets MAKEFILE_GENERATOR in its default_pre.prf - QMAKE_MAKE = make } else { error("Configure tests are not supported with the $$MAKEFILE_GENERATOR Makefile generator.") } diff --git a/mkspecs/features/create_cmake.prf b/mkspecs/features/create_cmake.prf index 58a0620e01..2dcb8da063 100644 --- a/mkspecs/features/create_cmake.prf +++ b/mkspecs/features/create_cmake.prf @@ -66,12 +66,6 @@ contains(CMAKE_BIN_DIR, "^\\.\\./.*") { CMAKE_DLL_DIR_IS_ABSOLUTE = $$CMAKE_LIB_DIR_IS_ABSOLUTE } -CMAKE_HOST_DATA_DIR = $$cmakeRelativePath($$[QT_HOST_DATA], $$[QT_INSTALL_PREFIX]) -contains(CMAKE_HOST_DATA_DIR, "^\\.\\./.*") { - CMAKE_HOST_DATA_DIR = $$[QT_HOST_DATA]/ - CMAKE_HOST_DATA_DIR_IS_ABSOLUTE = True -} - static|staticlib:CMAKE_STATIC_TYPE = true unix:contains(QT_CONFIG, reduce_relocations):CMAKE_ADD_FPIE_FLAGS = "true" diff --git a/mkspecs/features/gcov.prf b/mkspecs/features/gcov.prf new file mode 100644 index 0000000000..330831fc0e --- /dev/null +++ b/mkspecs/features/gcov.prf @@ -0,0 +1,31 @@ +# +# Tested with gcov 4.8.1 +# http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Gcov.html + +# To instrument a Qt application or library with the gcov coverage +# tool, do `CONFIG+=gcov' in the application .pro file. +# +# To instrument Qt itself with gcov, use the `-gcov' configure +# option. + +# The .gcno file is generated when the source file is compiled. +# The .gcda file is generated when a program is executed. + +# Example how to generate the html output after you've run the program or test +# +# lcov --capture --directory . --output-file coverage-gcov.info --no-external +# lcov --output-file coverage-gcov.info --remove coverage-gcov.info '*.moc*' '.*rcc*' '*3rdparty*' +# genhtml coverage-gcov.info --output-directory doc/coverage + +# If you want to use gcov directly, you most likely need to manually move the .gcda and .gcno files +# along with the program. +# +# mv .obj/debug-shared/tst_example.gc* . +# gcov -b -c tst_example.cpp + +QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage +QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage +QMAKE_OBJECTIVE_CFLAGS += -fprofile-arcs -ftest-coverage +QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage + +QMAKE_CLEAN += $(OBJECTS_DIR)*.gcno and $(OBJECTS_DIR)*.gcda diff --git a/mkspecs/features/ios/default_post.prf b/mkspecs/features/ios/default_post.prf index e9d2149351..654255eb1f 100644 --- a/mkspecs/features/ios/default_post.prf +++ b/mkspecs/features/ios/default_post.prf @@ -1,40 +1,44 @@ -CONFIG(qt):contains(QT, gui):equals(TEMPLATE, app): CONFIG += gui_app +equals(TEMPLATE, app) { + qt:app_bundle:!macx-xcode { + # For Qt applications we want Xcode project files as the generated output, + # but since qmake doesn't handle the transition between makefiles and Xcode + # project files (which happens when using subdirs), we create a wrapper + # makefile that takes care of generating the Xcode project, and allows + # building by calling out to xcodebuild. + TEMPLATE = aux -isEmpty(MAKEFILE_GENERATOR) { - gui_app:app_bundle: \ - # For applications we want Xcode project files - MAKEFILE_GENERATOR = XCODE - else: \ - # For libs, etc we still want regular Makefiles - MAKEFILE_GENERATOR = UNIX -} + CONFIG -= have_target qt staticlib dll + SOURCES = + RESOURCES = + INSTALLS = + + TARGET_XCODE_PROJECT_DIR = $${TARGET}.xcodeproj + + system("cd $$system_quote($$OUT_PWD) && $${QMAKE_QMAKE} $$system_quote($$_PRO_FILE_) -spec macx-xcode") -gui_app { - # We have to do the link and dependency resolution for the platform plugin - # manually, since QTPLUGIN and the prl lookup logic does not support - # the -force_load link style. The -force_load option ensures that all - # symbols from the static library are included, not just the ones the - # linker have seen a use for so far. We need this because we load the platform - # plugin from the platform plugin itself, using Q_IMPORT_PLUGIN. - lib_path_and_base = $$[QT_INSTALL_PLUGINS/get]/platforms/libqios$$qtPlatformTargetSuffix() - LIBS += "-force_load $${lib_path_and_base}.$${QMAKE_EXTENSION_STATICLIB}" - LIBS += $$fromfile($${lib_path_and_base}.prl, QMAKE_PRL_LIBS) + # We use xcodebuild to do the actual build, but filter out the verbose + # output that shows all environment variables for each build step. + xcodebuild_build.commands = "@xcodebuild build | grep -v setenv" + QMAKE_EXTRA_TARGETS += xcodebuild_build + all.depends = xcodebuild_build + QMAKE_EXTRA_TARGETS += all - # Which means we don't want the auto-generated import for the platform plugin - CONFIG -= import_qpa_plugin + # We do the same for the clean action + xcodebuild_clean.commands = "@xcodebuild clean" + QMAKE_EXTRA_TARGETS += xcodebuild_clean + clean.depends = xcodebuild_clean + QMAKE_EXTRA_TARGETS += clean - !no_main_wrapper { - # We link the iosmain library manually as well, since it's not really a plugin - lib_name = qiosmain - lib_path_and_base = $$[QT_INSTALL_PLUGINS/get]/platforms/lib$${lib_name}$$qtPlatformTargetSuffix() - LIBS += -L$$[QT_INSTALL_PLUGINS/get]/platforms -l$${lib_name}$$qtPlatformTargetSuffix() - LIBS += $$fromfile($${lib_path_and_base}.prl, QMAKE_PRL_LIBS) - DEFINES += main=qt_main + # And distclean + xcodebuild_distclean.commands = "$(DEL_FILE) -R $$TARGET_XCODE_PROJECT_DIR" + QMAKE_EXTRA_TARGETS += xcodebuild_distclean + distclean.depends = xcodebuild_distclean + QMAKE_EXTRA_TARGETS += distclean } } -contains(MAKEFILE_GENERATOR, XCODE) { +macx-xcode { ios_device_family.name = TARGETED_DEVICE_FAMILY ios_device_family.value = $$QMAKE_IOS_TARGETED_DEVICE_FAMILY QMAKE_MAC_XCODE_SETTINGS += ios_device_family @@ -46,24 +50,27 @@ isEmpty(QT_ARCH) { # but we fail to pick up the architecture since we're not passing -arch # yet. Xcode does not seem to have a way to run the shared toolchain # in a way that will automatically do this (for example xcrun -sdk). - contains(QMAKE_MAC_SDK, iphoneos.*): QT_ARCH = armv7 + contains(QMAKE_MAC_SDK, iphoneos.*): QT_ARCH = arm else: QT_ARCH = i386 # Simulator -} else { - # Fix up the QT_ARCH to be more specific - equals(QT_ARCH, arm) { - # Samsung S5PC100, Apple A4, A5, A5X - QT_ARCH = armv7 - - # FIXME: How do we support armv7s when Qt can't do universal builds? - } } -!equals(MAKEFILE_GENERATOR, XCODE) { - arch_flag = -arch $$QT_ARCH - QMAKE_CFLAGS += $$arch_flag - QMAKE_CXXFLAGS += $$arch_flag - QMAKE_OBJECTIVE_CFLAGS += $$arch_flag - QMAKE_LFLAGS += $$arch_flag +# Be more specific about which architecture we're targeting +equals(QT_ARCH, arm): \ + actual_archs = armv7 +else: \ + actual_archs = $$QT_ARCH + +macx-xcode { + QMAKE_XCODE_ARCHS = $$actual_archs +} else { + for(arch, actual_archs): \ + arch_flags += -arch $$arch + + QMAKE_CFLAGS += $$arch_flags + QMAKE_CXXFLAGS += $$arch_flags + QMAKE_OBJECTIVE_CFLAGS += $$arch_flags + QMAKE_LFLAGS += $$arch_flags } +unset(actual_archs) load(default_post) diff --git a/mkspecs/features/ios/default_pre.prf b/mkspecs/features/ios/default_pre.prf index 7cfbc03eb5..5db8d98d6c 100644 --- a/mkspecs/features/ios/default_pre.prf +++ b/mkspecs/features/ios/default_pre.prf @@ -1,5 +1,3 @@ -# Unset makefile generator, so we can auto-detect value in default_post -!macx-xcode: unset(MAKEFILE_GENERATOR) load(default_pre) diff --git a/mkspecs/features/ios/qt.prf b/mkspecs/features/ios/qt.prf new file mode 100644 index 0000000000..80d4907acd --- /dev/null +++ b/mkspecs/features/ios/qt.prf @@ -0,0 +1,24 @@ + +equals(TEMPLATE, app):contains(QT, gui(-private)?) { + LIBS *= -L$$[QT_INSTALL_PLUGINS/get]/platforms + + lib_name = qios + lib_path_and_base = $$[QT_INSTALL_PLUGINS/get]/platforms/lib$${lib_name}$$qtPlatformTargetSuffix() + LIBS += -l$${lib_name}$$qtPlatformTargetSuffix() $$fromfile($${lib_path_and_base}.prl, QMAKE_PRL_LIBS) + + # By marking qt_registerPlatformPlugin as undefined, we ensure that + # the plugin.o translation unit is considered for inclusion in + # the final binary, which in turn ensures that the plugin's + # static initializer is included and run. + QMAKE_LFLAGS += -u _qt_registerPlatformPlugin + + # We do link and dependency resolution for the platform plugin + # manually, since we know we always need the plugin, so we don't + # need to generate an import for it. + CONFIG -= import_qpa_plugin + + # FIXME: Solve using 'ld -r -alias -unexported_symbol' instead + !no_main_wrapper: DEFINES += main=qt_user_main +} + +load(qt) diff --git a/mkspecs/features/qt_docs.prf b/mkspecs/features/qt_docs.prf index 85e2db25bc..be3cd5273c 100644 --- a/mkspecs/features/qt_docs.prf +++ b/mkspecs/features/qt_docs.prf @@ -34,7 +34,7 @@ qtmver.value = $$replace(qtver.value, ^(\\d+\\.\\d+).*$, \\1) qtvertag.name = QT_VERSION_TAG qtvertag.value = $$replace(qtver.value, \.,) qtdocs.name = QT_INSTALL_DOCS -qtdocs.value = $$[QT_INSTALL_DOCS/get] +qtdocs.value = $$[QT_INSTALL_DOCS/src] qtAddToolEnv(QDOC, qtver qtmver qtvertag qtdocs) doc_command = $$QDOC $$QMAKE_DOCS prepare_docs { diff --git a/mkspecs/features/simd.prf b/mkspecs/features/simd.prf index 14da926dc3..e0cd5a3a58 100644 --- a/mkspecs/features/simd.prf +++ b/mkspecs/features/simd.prf @@ -12,6 +12,9 @@ # Get the SIMD flags load(qt_build_config) +# Set QT_CPU_FEATURES for convenience +QT_CPU_FEATURES = $$eval(QT_CPU_FEATURES.$$QT_ARCH) + # # Set up compilers for SIMD (SSE/AVX, NEON etc) # diff --git a/mkspecs/features/spec_post.prf b/mkspecs/features/spec_post.prf index c9e9f8b2f6..ad03c9c428 100644 --- a/mkspecs/features/spec_post.prf +++ b/mkspecs/features/spec_post.prf @@ -9,7 +9,7 @@ isEmpty(QMAKE_PLATFORM) { isEmpty(TARGET_PLATFORM) { equals(MAKEFILE_GENERATOR, UNIX) { equals(QMAKE_HOST.os, Darwin): \ - TARGET_PLATFORM = macx + TARGET_PLATFORM = macx # backwards compatibility; cannot change else: \ TARGET_PLATFORM = unix } else:if(equals(MAKEFILE_GENERATOR, MSVC.NET) \ @@ -28,12 +28,18 @@ isEmpty(QMAKE_PLATFORM) { equals(TARGET_PLATFORM, unix): \ QMAKE_PLATFORM = unix else:equals(TARGET_PLATFORM, macx): \ - QMAKE_PLATFORM = mac macx unix + QMAKE_PLATFORM = osx macx mac darwin unix else:equals(TARGET_PLATFORM, win32): \ QMAKE_PLATFORM = win32 else: \ error("Qmake spec sets an invalid TARGET_PLATFORM.") } + +contains(QMAKE_PLATFORM, macx):!contains(QMAKE_PLATFORM, osx) { + warning("qmake spec specifies platform macx, but not osx.") + QMAKE_PLATFORM = osx $$QMAKE_PLATFORM +} + CONFIG += $$QMAKE_PLATFORM isEmpty(QMAKE_COMPILER) { diff --git a/mkspecs/macx-clang-libc++-32/qmake.conf b/mkspecs/macx-clang-libc++-32/qmake.conf deleted file mode 100644 index 3f7342da0b..0000000000 --- a/mkspecs/macx-clang-libc++-32/qmake.conf +++ /dev/null @@ -1,23 +0,0 @@ -# -# qmake configuration for 32-bit Clang on OS X -# - -warning("QMakespec macx-clang-libc++-32 is deprecated. Use macx-clang-32 instead.") - -MAKEFILE_GENERATOR = UNIX -CONFIG += app_bundle incremental global_init_link_order lib_version_first plugin_no_soname -QMAKE_INCREMENTAL_STYLE = sublib - -include(../common/macx.conf) -include(../common/gcc-base-mac.conf) -include(../common/clang.conf) -include(../common/clang-mac.conf) - -QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 - -QMAKE_CFLAGS += -arch i386 -QMAKE_OBJECTIVE_CFLAGS += -arch i386 -stdlib=libc++ -QMAKE_CXXFLAGS += -arch i386 -stdlib=libc++ -QMAKE_LFLAGS += -arch i386 -stdlib=libc++ - -load(qt_config) diff --git a/mkspecs/macx-clang-libc++/qmake.conf b/mkspecs/macx-clang-libc++/qmake.conf deleted file mode 100644 index 7f4151e81b..0000000000 --- a/mkspecs/macx-clang-libc++/qmake.conf +++ /dev/null @@ -1,22 +0,0 @@ -# -# qmake configuration for Clang on OS X -# - -warning("QMakespec macx-clang-libc++ is deprecated. Use macx-clang instead.") - -MAKEFILE_GENERATOR = UNIX -CONFIG += app_bundle incremental global_init_link_order lib_version_first plugin_no_soname -QMAKE_INCREMENTAL_STYLE = sublib - -include(../common/macx.conf) -include(../common/gcc-base-mac.conf) -include(../common/clang.conf) -include(../common/clang-mac.conf) - -QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 - -QMAKE_OBJECTIVE_CFLAGS += -stdlib=libc++ -QMAKE_CXXFLAGS += -stdlib=libc++ -QMAKE_LFLAGS += -stdlib=libc++ - -load(qt_config) diff --git a/mkspecs/macx-xcode/Info.plist.app b/mkspecs/macx-xcode/Info.plist.app deleted file mode 100755 index 187a8e0aa4..0000000000 --- a/mkspecs/macx-xcode/Info.plist.app +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>NSPrincipalClass</key> - <string>NSApplication</string> - <key>CFBundleIconFile</key> - <string>@ICON@</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleGetInfoString</key> - <string>Created by Qt/QMake</string> - <key>CFBundleSignature</key> - <string>@TYPEINFO@</string> - <key>CFBundleExecutable</key> - <string>@EXECUTABLE@</string> - <key>CFBundleIdentifier</key> - <string>com.yourcompany.@EXECUTABLE@</string> - <key>NOTE</key> - <string>This file was generated by Qt/QMake.</string> -</dict> -</plist> diff --git a/mkspecs/macx-xcode/Info.plist.lib b/mkspecs/macx-xcode/Info.plist.lib deleted file mode 100644 index 63f1a945c2..0000000000 --- a/mkspecs/macx-xcode/Info.plist.lib +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundlePackageType</key> - <string>FMWK</string> - <key>CFBundleShortVersionString</key> - <string>@SHORT_VERSION@</string> - <key>CFBundleGetInfoString</key> - <string>Created by Qt/QMake</string> - <key>CFBundleSignature</key> - <string>@TYPEINFO@</string> - <key>CFBundleExecutable</key> - <string>@LIBRARY@</string> - <key>NOTE</key> - <string>Please, do NOT change this file -- It was generated by Qt/QMake.</string> -</dict> -</plist> diff --git a/mkspecs/macx-xcode/features/default_post.prf b/mkspecs/macx-xcode/features/default_post.prf new file mode 100644 index 0000000000..4c4746bb2b --- /dev/null +++ b/mkspecs/macx-xcode/features/default_post.prf @@ -0,0 +1,7 @@ + +isEmpty(QMAKE_INFO_PLIST) { + plist_template = $$absolute_path(../../$$[QMAKE_XSPEC]/Info.plist.$${TEMPLATE}) + exists($$plist_template): QMAKE_INFO_PLIST = $$plist_template +} + +load(default_post) diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index 9b7bfa6f8b..2f8f07eb2d 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -4,7 +4,7 @@ QMKGENSRC = $(QMKSRC)/generators #qmake code OBJS=project.o option.o property.o main.o ioutils.o proitems.o \ - qmakeglobals.o qmakeparser.o qmakeevaluator.o qmakebuiltins.o \ + qmakevfs.o qmakeglobals.o qmakeparser.o qmakeevaluator.o qmakebuiltins.o \ makefile.o unixmake2.o unixmake.o \ mingw_make.o winmakefile.o projectgenerator.o \ meta.o makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \ @@ -90,7 +90,7 @@ CPPFLAGS = -g $(EXTRA_CPPFLAGS) \ -I$(BUILD_PATH)/src/corelib/global -DHAVE_QCONFIG_CPP \ -I$(QMAKESPEC) \ -I$(SOURCE_PATH)/tools/shared \ - -DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL -DPROEVALUATOR_DEBUG \ + -DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL \ -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_NO_COMPONENT -DQT_NO_COMPRESS \ -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM @@ -125,6 +125,9 @@ proitems.o: $(QMKLIBSRC)/proitems.cpp qmakeglobals.o: $(QMKLIBSRC)/qmakeglobals.cpp $(CXX) -c -o $@ $(CXXFLAGS) $< +qmakevfs.o: $(QMKLIBSRC)/qmakevfs.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + qmakeparser.o: $(QMKLIBSRC)/qmakeparser.cpp $(CXX) -c -o $@ $(CXXFLAGS) $< diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index 85b5405b41..979155678e 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -38,7 +38,7 @@ CFLAGS_BARE = -c -Fo./ \ -I$(BUILD_PATH)\src\corelib\global -DHAVE_QCONFIG_CPP \ -I$(SOURCE_PATH)\mkspecs\$(QMAKESPEC) \ -I$(SOURCE_PATH)\tools\shared \ - -DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL -DPROEVALUATOR_DEBUG \ + -DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL \ -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_NO_COMPONENT -DQT_NO_COMPRESS \ -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM \ -DUNICODE @@ -57,7 +57,7 @@ ADDCLEAN = vc60.pdb vc70.pdb qmake.pdb qmake.ilk !ENDIF #qmake code -OBJS = project.obj main.obj ioutils.obj proitems.obj \ +OBJS = project.obj main.obj ioutils.obj proitems.obj qmakevfs.obj \ qmakeglobals.obj qmakeparser.obj qmakeevaluator.obj qmakebuiltins.obj \ makefile.obj unixmake.obj unixmake2.obj mingw_make.obj \ option.obj winmakefile.obj projectgenerator.obj property.obj meta.obj \ diff --git a/qmake/doc/src/images/qmake-precompile-ui.png b/qmake/doc/images/qmake-precompile-ui.png Binary files differindex 8c7b936fee..8c7b936fee 100644 --- a/qmake/doc/src/images/qmake-precompile-ui.png +++ b/qmake/doc/images/qmake-precompile-ui.png diff --git a/qmake/doc/qmake.qdocconf b/qmake/doc/qmake.qdocconf index cd8ac4d0ab..6b52ccc585 100644 --- a/qmake/doc/qmake.qdocconf +++ b/qmake/doc/qmake.qdocconf @@ -22,6 +22,9 @@ language = Cpp sources = src/qmake-manual.qdoc +imagedirs = images +exampledirs = snippets + depends += \ activeqt \ qt3d \ @@ -67,9 +70,8 @@ depends += \ qtwebkit \ qtwebkitexamples \ qtwidgets \ + qtwinextras \ qtx11extras \ qtxml \ qtxmlpatterns -imagedirs = src/images -exampledirs = src diff --git a/qmake/doc/src/snippets/code/doc_src_qmake-manual.cpp b/qmake/doc/snippets/code/doc_src_qmake-manual.cpp index bd63e600cd..bd63e600cd 100644 --- a/qmake/doc/src/snippets/code/doc_src_qmake-manual.cpp +++ b/qmake/doc/snippets/code/doc_src_qmake-manual.cpp diff --git a/qmake/doc/src/snippets/code/doc_src_qmake-manual.pro b/qmake/doc/snippets/code/doc_src_qmake-manual.pro index 0ee4785887..0ee4785887 100644 --- a/qmake/doc/src/snippets/code/doc_src_qmake-manual.pro +++ b/qmake/doc/snippets/code/doc_src_qmake-manual.pro diff --git a/qmake/doc/src/snippets/qmake/comments.pro b/qmake/doc/snippets/qmake/comments.pro index 957052c81d..957052c81d 100644 --- a/qmake/doc/src/snippets/qmake/comments.pro +++ b/qmake/doc/snippets/qmake/comments.pro diff --git a/qmake/doc/src/snippets/qmake/configscopes.pro b/qmake/doc/snippets/qmake/configscopes.pro index 6ab7f7c428..6ab7f7c428 100644 --- a/qmake/doc/src/snippets/qmake/configscopes.pro +++ b/qmake/doc/snippets/qmake/configscopes.pro diff --git a/qmake/doc/src/snippets/qmake/debug_and_release.pro b/qmake/doc/snippets/qmake/debug_and_release.pro index 92e8dbf76a..92e8dbf76a 100644 --- a/qmake/doc/src/snippets/qmake/debug_and_release.pro +++ b/qmake/doc/snippets/qmake/debug_and_release.pro diff --git a/qmake/doc/src/snippets/qmake/delegate.h b/qmake/doc/snippets/qmake/delegate.h index 92c7eb6a48..92c7eb6a48 100644 --- a/qmake/doc/src/snippets/qmake/delegate.h +++ b/qmake/doc/snippets/qmake/delegate.h diff --git a/qmake/doc/src/snippets/qmake/dereferencing.pro b/qmake/doc/snippets/qmake/dereferencing.pro index ff0c97995c..ff0c97995c 100644 --- a/qmake/doc/src/snippets/qmake/dereferencing.pro +++ b/qmake/doc/snippets/qmake/dereferencing.pro diff --git a/qmake/doc/src/snippets/qmake/destdir.pro b/qmake/doc/snippets/qmake/destdir.pro index b2f943904a..b2f943904a 100644 --- a/qmake/doc/src/snippets/qmake/destdir.pro +++ b/qmake/doc/snippets/qmake/destdir.pro diff --git a/qmake/doc/src/snippets/qmake/dirname.pro b/qmake/doc/snippets/qmake/dirname.pro index 59e1f20b3f..59e1f20b3f 100644 --- a/qmake/doc/src/snippets/qmake/dirname.pro +++ b/qmake/doc/snippets/qmake/dirname.pro diff --git a/qmake/doc/src/snippets/qmake/environment.pro b/qmake/doc/snippets/qmake/environment.pro index 808bdeba47..808bdeba47 100644 --- a/qmake/doc/src/snippets/qmake/environment.pro +++ b/qmake/doc/snippets/qmake/environment.pro diff --git a/qmake/doc/src/snippets/qmake/functions.pro b/qmake/doc/snippets/qmake/functions.pro index 2766120719..2766120719 100644 --- a/qmake/doc/src/snippets/qmake/functions.pro +++ b/qmake/doc/snippets/qmake/functions.pro diff --git a/qmake/doc/src/snippets/qmake/include.pro b/qmake/doc/snippets/qmake/include.pro index 37e7156957..37e7156957 100644 --- a/qmake/doc/src/snippets/qmake/include.pro +++ b/qmake/doc/snippets/qmake/include.pro diff --git a/qmake/doc/src/snippets/qmake/main.cpp b/qmake/doc/snippets/qmake/main.cpp index 92c7eb6a48..92c7eb6a48 100644 --- a/qmake/doc/src/snippets/qmake/main.cpp +++ b/qmake/doc/snippets/qmake/main.cpp diff --git a/qmake/doc/src/snippets/qmake/model.cpp b/qmake/doc/snippets/qmake/model.cpp index 92c7eb6a48..92c7eb6a48 100644 --- a/qmake/doc/src/snippets/qmake/model.cpp +++ b/qmake/doc/snippets/qmake/model.cpp diff --git a/qmake/doc/src/snippets/qmake/model.h b/qmake/doc/snippets/qmake/model.h index 92c7eb6a48..92c7eb6a48 100644 --- a/qmake/doc/src/snippets/qmake/model.h +++ b/qmake/doc/snippets/qmake/model.h diff --git a/qmake/doc/src/snippets/qmake/other.pro b/qmake/doc/snippets/qmake/other.pro index e69de29bb2..e69de29bb2 100644 --- a/qmake/doc/src/snippets/qmake/other.pro +++ b/qmake/doc/snippets/qmake/other.pro diff --git a/qmake/doc/src/snippets/qmake/paintwidget_mac.cpp b/qmake/doc/snippets/qmake/paintwidget_mac.cpp index 92c7eb6a48..92c7eb6a48 100644 --- a/qmake/doc/src/snippets/qmake/paintwidget_mac.cpp +++ b/qmake/doc/snippets/qmake/paintwidget_mac.cpp diff --git a/qmake/doc/src/snippets/qmake/paintwidget_unix.cpp b/qmake/doc/snippets/qmake/paintwidget_unix.cpp index c39fc2cbf6..c39fc2cbf6 100644 --- a/qmake/doc/src/snippets/qmake/paintwidget_unix.cpp +++ b/qmake/doc/snippets/qmake/paintwidget_unix.cpp diff --git a/qmake/doc/src/snippets/qmake/paintwidget_win.cpp b/qmake/doc/snippets/qmake/paintwidget_win.cpp index 92c7eb6a48..92c7eb6a48 100644 --- a/qmake/doc/src/snippets/qmake/paintwidget_win.cpp +++ b/qmake/doc/snippets/qmake/paintwidget_win.cpp diff --git a/qmake/doc/src/snippets/qmake/precompile-stable.h b/qmake/doc/snippets/qmake/precompile-stable.h index eef8cef728..eef8cef728 100644 --- a/qmake/doc/src/snippets/qmake/precompile-stable.h +++ b/qmake/doc/snippets/qmake/precompile-stable.h diff --git a/qmake/doc/src/snippets/qmake/project_location.pro b/qmake/doc/snippets/qmake/project_location.pro index 09d9b3d9d0..09d9b3d9d0 100644 --- a/qmake/doc/src/snippets/qmake/project_location.pro +++ b/qmake/doc/snippets/qmake/project_location.pro diff --git a/qmake/doc/src/snippets/qmake/qtconfiguration.pro b/qmake/doc/snippets/qmake/qtconfiguration.pro index 55e13be352..55e13be352 100644 --- a/qmake/doc/src/snippets/qmake/qtconfiguration.pro +++ b/qmake/doc/snippets/qmake/qtconfiguration.pro diff --git a/qmake/doc/src/snippets/qmake/quoting.pro b/qmake/doc/snippets/qmake/quoting.pro index 62efb2042e..62efb2042e 100644 --- a/qmake/doc/src/snippets/qmake/quoting.pro +++ b/qmake/doc/snippets/qmake/quoting.pro diff --git a/qmake/doc/src/snippets/qmake/replace.pro b/qmake/doc/snippets/qmake/replace.pro index 504e01a018..504e01a018 100644 --- a/qmake/doc/src/snippets/qmake/replace.pro +++ b/qmake/doc/snippets/qmake/replace.pro diff --git a/qmake/doc/src/snippets/qmake/replacefunction.pro b/qmake/doc/snippets/qmake/replacefunction.pro index 98013ba42d..98013ba42d 100644 --- a/qmake/doc/src/snippets/qmake/replacefunction.pro +++ b/qmake/doc/snippets/qmake/replacefunction.pro diff --git a/qmake/doc/src/snippets/qmake/scopes.pro b/qmake/doc/snippets/qmake/scopes.pro index 63b9b3aa55..63b9b3aa55 100644 --- a/qmake/doc/src/snippets/qmake/scopes.pro +++ b/qmake/doc/snippets/qmake/scopes.pro diff --git a/qmake/doc/src/snippets/qmake/shared_or_static.pro b/qmake/doc/snippets/qmake/shared_or_static.pro index 31c25ea44b..31c25ea44b 100644 --- a/qmake/doc/src/snippets/qmake/shared_or_static.pro +++ b/qmake/doc/snippets/qmake/shared_or_static.pro diff --git a/qmake/doc/src/snippets/qmake/spaces.pro b/qmake/doc/snippets/qmake/spaces.pro index 614d4c553d..614d4c553d 100644 --- a/qmake/doc/src/snippets/qmake/spaces.pro +++ b/qmake/doc/snippets/qmake/spaces.pro diff --git a/qmake/doc/src/snippets/qmake/specifications.pro b/qmake/doc/snippets/qmake/specifications.pro index f9a0d0a1cb..f9a0d0a1cb 100644 --- a/qmake/doc/src/snippets/qmake/specifications.pro +++ b/qmake/doc/snippets/qmake/specifications.pro diff --git a/qmake/doc/src/snippets/qmake/testfunction.pro b/qmake/doc/snippets/qmake/testfunction.pro index 785ffed6be..785ffed6be 100644 --- a/qmake/doc/src/snippets/qmake/testfunction.pro +++ b/qmake/doc/snippets/qmake/testfunction.pro diff --git a/qmake/doc/src/snippets/qmake/variables.pro b/qmake/doc/snippets/qmake/variables.pro index c1439ba68b..c1439ba68b 100644 --- a/qmake/doc/src/snippets/qmake/variables.pro +++ b/qmake/doc/snippets/qmake/variables.pro diff --git a/qmake/doc/src/snippets/qmake/view.h b/qmake/doc/snippets/qmake/view.h index 92c7eb6a48..92c7eb6a48 100644 --- a/qmake/doc/src/snippets/qmake/view.h +++ b/qmake/doc/snippets/qmake/view.h diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 5f8672c163..a00d00d8c1 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -201,11 +201,11 @@ The following snippet illustrates how lists of values are assigned to variables: - \snippet snippets/qmake/variables.pro 0 + \snippet qmake/variables.pro 0 The list of values in a variable is extended in the following way: - \snippet snippets/qmake/variables.pro 1 + \snippet qmake/variables.pro 1 \note The first assignment only includes values that are specified on the same line as the \c HEADERS variable. The second assignment splits @@ -244,7 +244,7 @@ The contents of a variable can be read by prepending the variable name with \c $$. This can be used to assign the contents of one variable to another: - \snippet snippets/qmake/dereferencing.pro 0 + \snippet qmake/dereferencing.pro 0 The \c $$ operator is used extensively with built-in functions that operate on strings and lists of values. For more information, see @@ -255,21 +255,21 @@ Usually, whitespace separates values in variable assignments. To specify values that contain spaces, you must enclose the values in double quotes: - \snippet snippets/qmake/quoting.pro 0 + \snippet qmake/quoting.pro 0 The quoted text is treated as a single item in the list of values held by the variable. A similar approach is used to deal with paths that contain spaces, particularly when defining the \l{INCLUDEPATH} and \l{LIBS} variables for the Windows platform: - \snippet snippets/qmake/spaces.pro quoting include paths with spaces + \snippet qmake/spaces.pro quoting include paths with spaces \section2 Comments You can add comments to project files. Comments begin with the \c # character and continue to the end of the same line. For example: - \snippet snippets/qmake/comments.pro 0 + \snippet qmake/comments.pro 0 To include the \c # character in variable assignments, it is necessary to use the contents of the built-in \l{LITERAL_HASH} variable. @@ -285,12 +285,12 @@ The \c include function is most commonly used to include other project files: - \snippet snippets/qmake/include.pro 0 + \snippet qmake/include.pro 0 Support for conditional structures is made available via \l{Scopes}{scopes} that behave like \c if statements in programming languages: - \snippet snippets/qmake/scopes.pro 0 + \snippet qmake/scopes.pro 0 The assignments inside the braces are only made if the condition is true. In this case, the \c win32 \l{CONFIG} option must be set. This @@ -353,7 +353,7 @@ versions of a project, the Makefile that qmake generates includes a rule that builds both versions. This can be invoked in the following way: - \snippet snippets/code/doc_src_qmake-manual.pro 0 + \snippet code/doc_src_qmake-manual.pro 0 Adding the \c build_all option to the \c CONFIG variable makes this rule the default when building the project. @@ -365,8 +365,8 @@ For example, the following lines show the function as the condition in a scope to test whether only the \c opengl option is in use: - \snippet snippets/qmake/configscopes.pro 4 - \snippet snippets/qmake/configscopes.pro 5 + \snippet qmake/configscopes.pro 4 + \snippet qmake/configscopes.pro 5 This enables different configurations to be defined for \c release and \c debug builds. For more information, see \l{Scopes}{Using Scopes}. @@ -394,7 +394,7 @@ For example, if your application uses the Qt library and you want to build it in \c debug mode, your project file will contain the following line: - \snippet snippets/code/doc_src_qmake-manual.pro 1 + \snippet code/doc_src_qmake-manual.pro 1 \note You must use "+=", not "=", or qmake will not be able to use Qt's configuration to determine the settings @@ -409,21 +409,21 @@ extension modules. For example, we can enable the XML and network modules in the following way: - \snippet snippets/code/doc_src_qmake-manual.pro 2 + \snippet code/doc_src_qmake-manual.pro 2 \note \c QT includes the \c core and \c gui modules by default, so the above declaration \e adds the network and XML modules to this default list. The following assignment \e omits the default modules, and will lead to errors when the application's source code is being compiled: - \snippet snippets/code/doc_src_qmake-manual.pro 3 + \snippet code/doc_src_qmake-manual.pro 3 If you want to build a project \e without the \c gui module, you need to exclude it with the "-=" operator. By default, \c QT contains both \c core and \c gui, so the following line will result in a minimal Qt project being built: - \snippet snippets/code/doc_src_qmake-manual.pro 4 + \snippet code/doc_src_qmake-manual.pro 4 For a list of Qt modules that you can add to the \c QT variable, see \l{Variables#QT}{QT}. @@ -441,7 +441,7 @@ \l{http://www.freedesktop.org/wiki/Software/pkg-config}{pkg-config}, such as the D-Bus and ogg libraries, with the following lines: - \snippet snippets/code/doc_src_qmake-manual.pro 5 + \snippet code/doc_src_qmake-manual.pro 5 For more information about adding features, see \l{Adding New Configuration Features}. @@ -458,14 +458,14 @@ For example, the following lines show how a library can be specified: - \snippet snippets/code/doc_src_qmake-manual.pro 6 + \snippet code/doc_src_qmake-manual.pro 6 The paths containing header files can also be specified in a similar way using the \l{INCLUDEPATH} variable. For example, to add several paths to be searched for header files: - \snippet snippets/code/doc_src_qmake-manual.pro 7 + \snippet code/doc_src_qmake-manual.pro 7 */ /*! @@ -485,7 +485,7 @@ The syntax used to run qmake takes the following simple form: - \snippet snippets/code/doc_src_qmake-manual.pro 8 + \snippet code/doc_src_qmake-manual.pro 8 \section1 Operating Modes @@ -572,7 +572,7 @@ \target MakefileMode \section1 Makefile Mode Options - \snippet snippets/code/doc_src_qmake-manual.pro 9 + \snippet code/doc_src_qmake-manual.pro 9 In Makefile mode, qmake will generate a Makefile that is used to build the project. Additionally, the following options may @@ -599,12 +599,12 @@ before all of the files specified. For example, the following command generates a Makefile from test.pro: - \snippet snippets/code/doc_src_qmake-manual.pro 10 + \snippet code/doc_src_qmake-manual.pro 10 However, some of the specified options can be omitted as they are default values: - \snippet snippets/code/doc_src_qmake-manual.pro 11 + \snippet code/doc_src_qmake-manual.pro 11 If you are certain you want your variables processed after the files specified, then you may pass the \c -after option. When this @@ -614,7 +614,7 @@ \target ProjectMode \section1 Project Mode Options - \snippet snippets/code/doc_src_qmake-manual.pro 12 + \snippet code/doc_src_qmake-manual.pro 12 In project mode, qmake will generate a project file. Additionally, you may supply the following options in this mode: @@ -669,7 +669,7 @@ For example, to use qmake from a binary package to create a Makefile in a project directory, invoke the following command: - \snippet snippets/code/doc_src_qmake-manual.pro 13 + \snippet code/doc_src_qmake-manual.pro 13 \section2 Using Frameworks @@ -681,12 +681,12 @@ to the build system, and this is achieved by appending linker options to the \l{QMAKE_LFLAGS} variable, as shown in the following example: - \snippet snippets/code/doc_src_qmake-manual.pro 14 + \snippet code/doc_src_qmake-manual.pro 14 The framework itself is linked in by appending the \c{-framework} options and the name of the framework to the \l{LIBS} variable: - \snippet snippets/code/doc_src_qmake-manual.pro 15 + \snippet code/doc_src_qmake-manual.pro 15 \section2 Creating Frameworks @@ -697,7 +697,7 @@ \l{TEMPLATE}{\c lib template} and add the \c lib_bundle option to the \l{CONFIG} variable: - \snippet snippets/code/doc_src_qmake-manual.pro 16 + \snippet code/doc_src_qmake-manual.pro 16 The data associated with the library is specified using the \l{QMAKE_BUNDLE_DATA} @@ -705,7 +705,7 @@ bundle, and is often used to specify a collection of header files, as in the following example: - \snippet snippets/code/doc_src_qmake-manual.pro 17 + \snippet code/doc_src_qmake-manual.pro 17 You use the \c FRAMEWORK_HEADERS variable to specify the headers required by a particular framework. @@ -727,7 +727,7 @@ by running qmake to generate an Xcode project from an existing qmake project file. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 19 + \snippet code/doc_src_qmake-manual.pro 19 \note If a project is later moved on the disk, qmake must be run again to process the project file and create a new Xcode project file. @@ -778,12 +778,12 @@ This can also be set using a command line option, for example: - \snippet snippets/code/doc_src_qmake-manual.pro 20 + \snippet code/doc_src_qmake-manual.pro 20 It is possible to recursively generate \c{.vcproj} files in subdirectories and a \c{.sln} file in the main directory, by typing: - \snippet snippets/code/doc_src_qmake-manual.pro 21 + \snippet code/doc_src_qmake-manual.pro 21 Each time you update the project file, you need to run qmake to generate an updated Visual Studio @@ -802,12 +802,12 @@ Removing manifest embedding for application executables can be done with the following assignment to the \l{CONFIG} variable: - \snippet snippets/code/doc_src_qmake-manual.pro 22 + \snippet code/doc_src_qmake-manual.pro 22 Also, the manifest embedding for DLLs can be removed with the following assignment to the \c CONFIG variable: - \snippet snippets/code/doc_src_qmake-manual.pro 23 + \snippet code/doc_src_qmake-manual.pro 23 This is discussed in more detail in the \l{Deploying an Application on Windows#Manifest files} @@ -917,7 +917,7 @@ qmake generates includes a rule that builds both versions, and this can be invoked in the following way: - \snippet snippets/code/doc_src_qmake-manual.pro 24 + \snippet code/doc_src_qmake-manual.pro 24 When linking a library, qmake relies on the underlying platform to know what other libraries this library links @@ -954,7 +954,7 @@ will be set for each of these modes, and you can test for this to perform build-specific tasks. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 25 + \snippet code/doc_src_qmake-manual.pro 25 As a result, it may be useful to define mode-specific variables, such as \l{#QMAKE_LFLAGS_RELEASE}{QMAKE_LFLAGS_RELEASE}, instead of general @@ -1050,7 +1050,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 26 + \snippet code/doc_src_qmake-manual.pro 26 \target DEFINES \section1 DEFINES @@ -1060,7 +1060,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 27 + \snippet code/doc_src_qmake-manual.pro 27 \target DEF_FILE \section1 DEF_FILE @@ -1090,7 +1090,7 @@ For example, the following definition uploads all PNG images in \c path to the directory where the build target is deployed: - \snippet snippets/code/doc_src_qmake-manual.pro 28 + \snippet code/doc_src_qmake-manual.pro 28 The default deployment target path for Windows CE is \c{%CSIDL_PROGRAM_FILES%\target}, which usually gets expanded to @@ -1102,7 +1102,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 29 + \snippet code/doc_src_qmake-manual.pro 29 \note In Windows CE all linked Qt libraries will be deployed to the path specified by \c{myFiles.path}. @@ -1123,7 +1123,7 @@ For example, the following definition uploads the jpeg imageformat plugin to the plugins directory on the Windows CE device: - \snippet snippets/code/doc_src_qmake-manual.pro 142 + \snippet code/doc_src_qmake-manual.pro 142 \target DESTDIR \section1 DESTDIR @@ -1132,7 +1132,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 30 + \snippet code/doc_src_qmake-manual.pro 30 \target DISTFILES \section1 DISTFILES @@ -1142,7 +1142,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 31 + \snippet code/doc_src_qmake-manual.pro 31 \target DLLDESTDIR \section1 DLLDESTDIR @@ -1160,7 +1160,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 32 + \snippet code/doc_src_qmake-manual.pro 32 \target GUID \section1 GUID @@ -1183,7 +1183,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 34 + \snippet code/doc_src_qmake-manual.pro 34 See also \l{#SOURCES}{SOURCES}. @@ -1202,12 +1202,12 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 35 + \snippet code/doc_src_qmake-manual.pro 35 To specify a path containing spaces, quote the path using the technique described in \l{Whitespace}. - \snippet snippets/qmake/spaces.pro quoting include paths with spaces + \snippet qmake/spaces.pro quoting include paths with spaces \target INSTALLS \section1 INSTALLS @@ -1221,7 +1221,7 @@ build target will be installed, and the \c INSTALLS assignment adds the build target to the list of existing resources to be installed: - \snippet snippets/code/doc_src_qmake-manual.pro 36 + \snippet code/doc_src_qmake-manual.pro 36 For more information, see \l{Installing Files}. @@ -1248,7 +1248,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 37 + \snippet code/doc_src_qmake-manual.pro 37 \target LIBS \section1 LIBS @@ -1261,18 +1261,18 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 38 + \snippet code/doc_src_qmake-manual.pro 38 To specify a path containing spaces, quote the path using the technique described in \l{Whitespace}. - \snippet snippets/qmake/spaces.pro quoting library paths with spaces + \snippet qmake/spaces.pro quoting library paths with spaces By default, the list of libraries stored in \c LIBS is reduced to a list of unique names before it is used. To change this behavior, add the \c no_lflags_merge option to the \l{CONFIG} variable: - \snippet snippets/code/doc_src_qmake-manual.pro 39 + \snippet code/doc_src_qmake-manual.pro 39 \target LITERAL_HASH \section1 LITERAL_HASH @@ -1283,7 +1283,7 @@ For example: - \snippet snippets/qmake/comments.pro 1 + \snippet qmake/comments.pro 1 By using \c LITERAL_HASH in this way, the \c # character can be used to construct a URL for the \c message() function to print to the console. @@ -1311,7 +1311,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 40 + \snippet code/doc_src_qmake-manual.pro 40 \target OBJECTS \section1 OBJECTS @@ -1328,7 +1328,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 41 + \snippet code/doc_src_qmake-manual.pro 41 \target POST_TARGETDEPS \section1 POST_TARGETDEPS @@ -1417,7 +1417,7 @@ and \c path/to/header_two.h to a group containing information about the headers supplied with the framework: - \snippet snippets/code/doc_src_qmake-manual.pro 43 + \snippet code/doc_src_qmake-manual.pro 43 The last line adds the information about the headers to the collection of resources that will be installed with the library bundle. @@ -1439,7 +1439,7 @@ For example, the following definition will result in a framework with the \c{.myframework} extension: - \snippet snippets/code/doc_src_qmake-manual.pro 44 + \snippet code/doc_src_qmake-manual.pro 44 \section1 QMAKE_CC @@ -2027,7 +2027,7 @@ \c{-compress} options are used with particular values each time that \c rcc is invoked: - \snippet snippets/code/doc_src_qmake-manual.pro 45 + \snippet code/doc_src_qmake-manual.pro 45 \section1 QMAKE_RPATHDIR @@ -2120,6 +2120,7 @@ \row \li webkit \li \l{Qt WebKit} \row \li webkitwidgets \li \l{Qt WebKit Widgets} \row \li widgets \li \l{Qt Widgets} + \row \li winextras \li \l{Qt Windows Extras} \row \li xml \li \l{Qt XML} (deprecated) \row \li xmlpatterns \li \l{Qt XML Patterns} \endtable @@ -2131,7 +2132,7 @@ exclude the \c gui value with the "-=" operator. The following line will result in a minimal Qt project being built: - \snippet snippets/code/doc_src_qmake-manual.pro 47 + \snippet code/doc_src_qmake-manual.pro 47 \section1 QTPLUGIN @@ -2177,7 +2178,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 48 + \snippet code/doc_src_qmake-manual.pro 48 \target REQUIRES \section1 REQUIRES @@ -2219,7 +2220,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 49 + \snippet code/doc_src_qmake-manual.pro 49 See also \l{#HEADERS}{HEADERS}. @@ -2233,7 +2234,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 50 + \snippet code/doc_src_qmake-manual.pro 50 It is essential that the project file in each subdirectory has the same name as the subdirectory itself, so that qmake @@ -2244,7 +2245,7 @@ which they are specified, update the \l{#CONFIG}{CONFIG} variable to include the \c ordered option: - \snippet snippets/code/doc_src_qmake-manual.pro 51 + \snippet code/doc_src_qmake-manual.pro 51 It is possible to modify this default behavior of \c SUBDIRS by giving additional modifiers to \c SUBDIRS elements. Supported modifiers are: @@ -2266,7 +2267,7 @@ For example, define two subdirectories, both of which reside in a different directory than the \c SUBDIRS value, and one of the subdirectories must be built before the other: - \snippet snippets/code/doc_src_qmake-manual.pro 149 + \snippet code/doc_src_qmake-manual.pro 149 \target TARGET \section1 TARGET @@ -2276,7 +2277,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 52 + \snippet code/doc_src_qmake-manual.pro 52 The project file above would produce an executable named \c myapp on unix and \c{myapp.exe} on Windows. @@ -2324,7 +2325,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 53 + \snippet code/doc_src_qmake-manual.pro 53 The template can be overridden by specifying a new template type with the \c -t command line option. This overrides the template type \e after the .pro @@ -2348,7 +2349,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 54 + \snippet code/doc_src_qmake-manual.pro 54 \target VERSION \section1 VERSION @@ -2358,7 +2359,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 57 + \snippet code/doc_src_qmake-manual.pro 57 \section1 VER_MAJ @@ -2392,7 +2393,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 58 + \snippet code/doc_src_qmake-manual.pro 58 \section1 _PRO_FILE_ @@ -2401,7 +2402,7 @@ For example, the following line causes the location of the project file to be written to the console: - \snippet snippets/qmake/project_location.pro project file + \snippet qmake/project_location.pro project file \note Do not attempt to overwrite the value of this variable. @@ -2412,7 +2413,7 @@ For example, the following line causes the location of the directory containing the project file to be written to the console: - \snippet snippets/qmake/project_location.pro project file directory + \snippet qmake/project_location.pro project file directory \note Do not attempt to overwrite the value of this variable. */ @@ -2448,7 +2449,7 @@ For example, the following call returns the string \c {"/home/johndoe/myproject/readme.txt"}: - \snippet snippets/code/doc_src_qmake-manual.pro 159 + \snippet code/doc_src_qmake-manual.pro 159 See also \l{clean_path(path)}{clean_path()}, \l{relative_path(filePath[, base])}{relative_path()}. @@ -2459,7 +2460,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 59 + \snippet code/doc_src_qmake-manual.pro 59 \section2 cat(filename[, mode]) @@ -2491,7 +2492,7 @@ Returns the directory name part of the specified file. For example: - \snippet snippets/qmake/dirname.pro 0 + \snippet qmake/dirname.pro 0 \section2 enumerate_vars @@ -2506,7 +2507,7 @@ \note If you specify the string to expand literally, you need to escape the backslashes, as illustrated by the following code snippet: - \snippet snippets/code/doc_src_qmake-manual.pro 173 + \snippet code/doc_src_qmake-manual.pro 173 \target findfunction \section2 find(variablename, substr) @@ -2514,7 +2515,7 @@ Returns all the values in \c variablename that match the regular expression \c substr. - \snippet snippets/code/doc_src_qmake-manual.pro 64 + \snippet code/doc_src_qmake-manual.pro 64 MY_VAR2 will contain '-Lone -Ltwo -Lthree -Lfour -Lfive', and MY_VAR3 will contain 'three two three'. @@ -2525,7 +2526,7 @@ For example, the following call returns \c firstname: - \snippet snippets/code/doc_src_qmake-manual.pro 161 + \snippet code/doc_src_qmake-manual.pro 161 See also \l{last(variablename)}{last()}. @@ -2551,7 +2552,7 @@ For example, the following call converts the hexadecimal number \c BAD to \c 002989: - \snippet snippets/code/doc_src_qmake-manual.pro 163 + \snippet code/doc_src_qmake-manual.pro 163 \section2 fromfile(filename, variablename) @@ -2574,7 +2575,7 @@ For example, the following call returns \c phone: - \snippet snippets/code/doc_src_qmake-manual.pro 162 + \snippet code/doc_src_qmake-manual.pro 162 See also \l{first(variablename)}{first()}. @@ -2585,11 +2586,11 @@ of that variable. You can use the variable to write a loop as illustrated by the following code snippet - \snippet snippets/code/doc_src_qmake-manual.pro 170 + \snippet code/doc_src_qmake-manual.pro 170 instead of: - \snippet snippets/code/doc_src_qmake-manual.pro 171 + \snippet code/doc_src_qmake-manual.pro 171 \section2 lower(arg1 [, arg2 ..., argn]) @@ -2635,11 +2636,11 @@ contents of the variable supplied as \c string. For example, the code - \snippet snippets/qmake/replace.pro 0 + \snippet qmake/replace.pro 0 prints the message: - \snippet snippets/code/doc_src_qmake-manual.pro 70 + \snippet code/doc_src_qmake-manual.pro 70 \section2 sprintf(string, arguments...) @@ -2661,7 +2662,7 @@ For example, the following call outputs \c surname: - \snippet snippets/code/doc_src_qmake-manual.pro 167 + \snippet code/doc_src_qmake-manual.pro 167 \section2 shadowed(path) @@ -2699,7 +2700,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 168 + \snippet code/doc_src_qmake-manual.pro 168 \section2 system(command[, mode]) @@ -2708,7 +2709,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 72 + \snippet code/doc_src_qmake-manual.pro 72 See also the test variant of \l{system(command)}{system()}. @@ -2734,7 +2735,7 @@ Returns the list of values in \c variablename with duplicate entries removed. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 73 + \snippet code/doc_src_qmake-manual.pro 73 \section2 upper(arg1 [, arg2 ..., argn]) @@ -2779,7 +2780,7 @@ mutually exclusive values) a second parameter can be used to specify a set of values to consider. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 60 + \snippet code/doc_src_qmake-manual.pro 60 Because release is considered the active setting (for feature parsing) it will be the CONFIG used to generate the build file. In the common @@ -2796,7 +2797,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 61 + \snippet code/doc_src_qmake-manual.pro 61 The contents of the scope are only processed if the \c drivers variable contains the value \c network. If this is the case, the @@ -2813,7 +2814,7 @@ only processed if the variable contains the correct number of values. For example: - \snippet snippets/qmake/functions.pro 2 + \snippet qmake/functions.pro 2 \section2 debug(level, message) @@ -2838,7 +2839,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 160 + \snippet code/doc_src_qmake-manual.pro 160 \section2 error(string) @@ -2848,7 +2849,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 62 + \snippet code/doc_src_qmake-manual.pro 62 \section2 eval(string) @@ -2858,7 +2859,7 @@ values of existing variables or create new definitions. For example: - \snippet snippets/qmake/functions.pro 4 + \snippet qmake/functions.pro 4 \note Quotation marks can be used to delimit the string, and the return value can be discarded if it is not needed. @@ -2871,7 +2872,7 @@ succeeds if any file matches the regular expression specified. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 63 + \snippet code/doc_src_qmake-manual.pro 63 \note "/" should be used as a directory separator, regardless of the platform in use. @@ -2895,7 +2896,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 65 + \snippet code/doc_src_qmake-manual.pro 65 \section2 greaterThan(variablename, value) @@ -2905,7 +2906,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 164 + \snippet code/doc_src_qmake-manual.pro 164 It is impossible to compare two numbers as strings directly. As a workaround, construct temporary values with a non-numeric prefix and compare @@ -2913,7 +2914,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 172 + \snippet code/doc_src_qmake-manual.pro 172 See also \l{lessThan(variablename, value)}{lessThan()}. @@ -2923,7 +2924,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 166 + \snippet code/doc_src_qmake-manual.pro 166 \section2 include(filename) @@ -2935,7 +2936,7 @@ You can check whether the file was included by using this function as the condition for a scope. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 66 + \snippet code/doc_src_qmake-manual.pro 66 \section2 infile(filename, var, val) @@ -2955,7 +2956,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 67 + \snippet code/doc_src_qmake-manual.pro 67 \section2 isEqual @@ -2968,7 +2969,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 165 + \snippet code/doc_src_qmake-manual.pro 165 \section2 load(feature) @@ -2987,7 +2988,7 @@ Always succeeds, and displays \c string as a general message to the user. Unlike the \c error() function, this function allows processing to continue. - \snippet snippets/code/doc_src_qmake-manual.pro 68 + \snippet code/doc_src_qmake-manual.pro 68 The above line causes "This is a message" to be written to the console. The use of quotation marks is optional, but recommended. @@ -2998,7 +2999,7 @@ \l{Scopes}{in conjunction with a scope} to filter out messages during builds. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 69 + \snippet code/doc_src_qmake-manual.pro 69 \section2 mkpath(dirPath) @@ -3021,7 +3022,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 71 + \snippet code/doc_src_qmake-manual.pro 71 See also the replace variant of \l{system(command[, mode])}{system()}. @@ -3037,7 +3038,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 169 + \snippet code/doc_src_qmake-manual.pro 169 \section2 warning(string) @@ -3061,11 +3062,11 @@ This can be useful to optionally enable or disable features. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 157 + \snippet code/doc_src_qmake-manual.pro 157 And then, in the code: - \snippet snippets/code/doc_src_qmake-manual.pro 158 + \snippet code/doc_src_qmake-manual.pro 158 */ /*! @@ -3082,14 +3083,14 @@ property in qmake once, and query it each time qmake is invoked. You can set a property in qmake as follows: - \snippet snippets/code/doc_src_qmake-manual.pro 74 + \snippet code/doc_src_qmake-manual.pro 74 The appropriate property and value should be substituted for \c PROPERTY and \c VALUE. You can retrieve this information back from qmake as follows: - \snippet snippets/code/doc_src_qmake-manual.pro 75 + \snippet code/doc_src_qmake-manual.pro 75 \note \c{qmake -query} lists built-in properties in addition to the properties that you set with \c{qmake -set PROPERTY VALUE}. @@ -3135,11 +3136,11 @@ For example, you can query the installation of Qt for this version of qmake with the \c QT_INSTALL_PREFIX property: - \snippet snippets/code/doc_src_qmake-manual.pro 77 + \snippet code/doc_src_qmake-manual.pro 77 You can query the values of properties in a project file as follows: - \snippet snippets/code/doc_src_qmake-manual.pro 78 + \snippet code/doc_src_qmake-manual.pro 78 \target QMAKESPEC \section1 QMAKESPEC @@ -3189,7 +3190,7 @@ example, the extension used for \l moc files can be redefined with the following assignment in a project file: - \snippet snippets/code/doc_src_qmake-manual.pro 85 + \snippet code/doc_src_qmake-manual.pro 85 The following variables can be used to redefine common file extensions recognized by qmake: @@ -3249,7 +3250,7 @@ The \c = operator assigns a value to a variable: - \snippet snippets/code/doc_src_qmake-manual.pro 89 + \snippet code/doc_src_qmake-manual.pro 89 The above line sets the \l{TARGET} variable to \c myapp. This will overwrite any values previously set for \c TARGET with \c myapp. @@ -3258,7 +3259,7 @@ The \c += operator appends a new value to the list of values in a variable: - \snippet snippets/code/doc_src_qmake-manual.pro 90 + \snippet code/doc_src_qmake-manual.pro 90 The above line appends \c USE_MY_STUFF to the list of pre-processor defines to be put in the generated Makefile. @@ -3267,7 +3268,7 @@ The \c -= operator removes a value from the list of values in a variable: - \snippet snippets/code/doc_src_qmake-manual.pro 91 + \snippet code/doc_src_qmake-manual.pro 91 The above line removes \c USE_MY_STUFF from the list of pre-processor defines to be put in the generated Makefile. @@ -3278,7 +3279,7 @@ if it is not already present. This prevents values from being included many times in a variable. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 92 + \snippet code/doc_src_qmake-manual.pro 92 In the above line, \c USE_MY_STUFF will only be added to the list of pre-processor defines if it is not already defined. Note that the \l{unique}{unique()} @@ -3290,7 +3291,7 @@ The \c ~= operator replaces any values that match a regular expression with the specified value: - \snippet snippets/code/doc_src_qmake-manual.pro 93 + \snippet code/doc_src_qmake-manual.pro 93 In the above line, any values in the list that start with \c QT_D or \c QT_T are replaced with \c QT. @@ -3300,7 +3301,7 @@ The \c $$ operator is used to extract the contents of a variable, and can be used to pass values between variables or supply them to functions: - \snippet snippets/code/doc_src_qmake-manual.pro 94 + \snippet code/doc_src_qmake-manual.pro 94 Variables can be used to store the contents of environment variables. These can be evaluated at the time when qmake @@ -3310,7 +3311,7 @@ To obtain the contents of an environment value when qmake is run, use the \c $$(...) operator: - \snippet snippets/qmake/environment.pro 0 + \snippet qmake/environment.pro 0 In the above assignment, the value of the \c PWD environment variable is read when the project file is processed. @@ -3318,7 +3319,7 @@ To obtain the contents of an environment value at the time when the generated Makefile is processed, use the \c $(...) operator: - \snippet snippets/qmake/environment.pro 1 + \snippet qmake/environment.pro 1 In the above assignment, the value of \c PWD is read immediately when the project file is processed, but \c $(PWD) is assigned to @@ -3330,7 +3331,7 @@ The special \c $$[...] operator can be used to access qmake properties: - \snippet snippets/qmake/qtconfiguration.pro 0 + \snippet qmake/qtconfiguration.pro 0 For more information, see \l{Configuring qmake}. @@ -3339,7 +3340,7 @@ For example, a \QD plugin can be installed alongside \QD's built-in plugins if the following declaration is made in its project file: - \snippet snippets/code/doc_src_qmake-manual.pro 101 + \snippet code/doc_src_qmake-manual.pro 101 \target Scopes \section1 Scopes @@ -3352,7 +3353,7 @@ Scopes consist of a condition followed by an opening brace on the same line, a sequence of commands and definitions, and a closing brace on a new line: - \snippet snippets/qmake/scopes.pro syntax + \snippet qmake/scopes.pro syntax The opening brace \e{must be written on the same line as the condition}. Scopes may be concatenated to include more than one condition, as described @@ -3363,7 +3364,7 @@ A scope is written as a condition followed by a series of declarations contained within a pair of braces. For example: - \snippet snippets/qmake/scopes.pro 0 + \snippet qmake/scopes.pro 0 The above code will add the \c paintwidget_win.cpp file to the sources listed in the generated Makefile when building for a Windows platform. When @@ -3374,24 +3375,24 @@ original condition is false. For example, to process something when building for all platforms \e except Windows, negate the scope like this: - \snippet snippets/qmake/scopes.pro 1 + \snippet qmake/scopes.pro 1 Scopes can be nested to combine more than one condition. For instance, to include a particular file for a certain platform only if debugging is enabled, write the following: - \snippet snippets/qmake/scopes.pro 2 + \snippet qmake/scopes.pro 2 To save writing many nested scopes, you can nest scopes using the \c : operator. The nested scopes in the above example can be rewritten in the following way: - \snippet snippets/qmake/scopes.pro 3 + \snippet qmake/scopes.pro 3 You may also use the \c : operator to perform single line conditional assignments. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 95 + \snippet code/doc_src_qmake-manual.pro 95 The above line adds \c USE_MY_STUFF to the \l{DEFINES} variable only when building for the Windows platform. @@ -3401,7 +3402,7 @@ There is also the \c | operator to act like a logical OR operator, joining together a number of conditions, and requiring only one of them to be true. - \snippet snippets/qmake/scopes.pro 4 + \snippet qmake/scopes.pro 4 You can also provide alternative declarations to those within a scope by using an \c else scope. Each \c else scope is processed if the conditions @@ -3409,7 +3410,7 @@ This allows you to write complex tests when combined with other scopes (separated by the \c : operator as above). For example: - \snippet snippets/code/doc_src_qmake-manual.pro 96 + \snippet code/doc_src_qmake-manual.pro 96 \section2 Configuration and Scopes @@ -3418,15 +3419,15 @@ values can be used as the condition for a scope. For example, the list of values held by \c CONFIG can be extended with the \c opengl value: - \snippet snippets/qmake/configscopes.pro 0 + \snippet qmake/configscopes.pro 0 As a result of this operation, any scopes that test for \c opengl will be processed. We can use this feature to give the final executable an appropriate name: - \snippet snippets/qmake/configscopes.pro 1 - \snippet snippets/qmake/configscopes.pro 2 - \snippet snippets/qmake/configscopes.pro 3 + \snippet qmake/configscopes.pro 1 + \snippet qmake/configscopes.pro 2 + \snippet qmake/configscopes.pro 3 This feature makes it easy to change the configuration for a project without losing all the custom settings that might be needed for a specific @@ -3449,7 +3450,7 @@ following lines from a project file show the current specification in use and test for the \c linux-g++ specification: - \snippet snippets/qmake/specifications.pro 0 + \snippet qmake/specifications.pro 0 You can test for any other platform-compiler combination as long as a specification exists for it in the \c mkspecs directory. @@ -3464,7 +3465,7 @@ variables with a given name when it encounters an assignment to that name. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 97 + \snippet code/doc_src_qmake-manual.pro 97 There are no restricitions on what you do to your own variables, as qmake will ignore them unless it needs to evaluate them when processing @@ -3473,19 +3474,19 @@ You can also assign the value of a current variable to another variable by prefixing $$ to the variable name. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 98 + \snippet code/doc_src_qmake-manual.pro 98 Now the MY_DEFINES variable contains what is in the DEFINES variable at this point in the project file. This is also equivalent to: - \snippet snippets/code/doc_src_qmake-manual.pro 99 + \snippet code/doc_src_qmake-manual.pro 99 The second notation allows you to append the contents of the variable to another value without separating the two with a space. For example, the following will ensure that the final executable will be given a name that includes the project template being used: - \snippet snippets/code/doc_src_qmake-manual.pro 100 + \snippet code/doc_src_qmake-manual.pro 100 \target UsingReplaceFunctions \section1 Replace Functions @@ -3497,7 +3498,7 @@ operator with this type of function as you would to assign contents of one variable to another: - \snippet snippets/qmake/functions.pro 1 + \snippet qmake/functions.pro 1 This type of function should be used on the right-hand side of assignments (that is, as an operand). @@ -3505,13 +3506,13 @@ You can define your own functions for processing the contents of variables as follows: - \snippet snippets/code/doc_src_qmake-manual.pro 102 + \snippet code/doc_src_qmake-manual.pro 102 The following example function takes a variable name as its only argument, extracts a list of values from the variable with the \l{eval(string)}{eval()} built-in function, and compiles a list of files: - \snippet snippets/qmake/replacefunction.pro 0 + \snippet qmake/replacefunction.pro 0 \target UsingTestFunctions \section1 Test Functions @@ -3520,7 +3521,7 @@ used as conditions when writing scopes. These functions do not return a value, but instead indicate \e success or \e failure: - \snippet snippets/qmake/functions.pro 3 + \snippet qmake/functions.pro 3 This type of function should be used in conditional expressions only. @@ -3529,7 +3530,7 @@ for scopes. The following example tests whether each file in a list exists and returns true if they all exist, or false if not: - \snippet snippets/qmake/testfunction.pro 0 + \snippet qmake/testfunction.pro 0 */ /*! @@ -3586,7 +3587,7 @@ For example, consider the following assignment in a project file: - \snippet snippets/code/doc_src_qmake-manual.pro 103 + \snippet code/doc_src_qmake-manual.pro 103 With this addition to the \c CONFIG variable, qmake will search the locations listed above for @@ -3621,7 +3622,7 @@ be installed. For example, a collection of documentation files can be described in the following way: - \snippet snippets/code/doc_src_qmake-manual.pro 79 + \snippet code/doc_src_qmake-manual.pro 79 The \c path member informs qmake that the files should be installed in \c /usr/local/program/doc (the path member), and the @@ -3632,7 +3633,7 @@ Once an install set has been fully described, you can append it to the install list with a line like this: - \snippet snippets/code/doc_src_qmake-manual.pro 80 + \snippet code/doc_src_qmake-manual.pro 80 qmake will ensure that the specified files are copied to the installation directory. If you require more control over @@ -3641,7 +3642,7 @@ qmake to execute a series of commands for this install set: - \snippet snippets/code/doc_src_qmake-manual.pro 81 + \snippet code/doc_src_qmake-manual.pro 81 The \c unix \l{Scopes and Conditions}{scope} ensures that these particular commands are only executed on Unix platforms. @@ -3656,7 +3657,7 @@ will decide what needs to be copied for you. Currently, the \c target and \c dlltarget install sets are supported. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 82 + \snippet code/doc_src_qmake-manual.pro 82 In the above lines, qmake knows what needs to be copied, and will handle the installation process automatically. @@ -3672,7 +3673,7 @@ API as found in other places in qmake. Objects are defined automatically by specifying their \e members. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 86 + \snippet code/doc_src_qmake-manual.pro 86 The definitions above define a qmake target called \c mytarget, containing a Makefile target called \c{.buildfile} which in turn is generated with the @@ -3684,7 +3685,7 @@ The final step is to use the \c QMAKE_EXTRA_TARGETS variable to instruct qmake that this object is a target to be built: - \snippet snippets/code/doc_src_qmake-manual.pro 87 + \snippet code/doc_src_qmake-manual.pro 87 This is all you need to do to actually build custom targets. Of course, you may want to tie one of these targets to the @@ -3733,7 +3734,7 @@ It is possible to customize qmake to support new compilers and preprocessors: - \snippet snippets/code/doc_src_qmake-manual.pro 88 + \snippet code/doc_src_qmake-manual.pro 88 With the above definitions, you can use a drop-in replacement for moc if one is available. The command is executed on all arguments given to the @@ -3835,7 +3836,7 @@ The first step is to enable dependency tracking in the library itself. To do this you must tell qmake to save information about the library: - \snippet snippets/code/doc_src_qmake-manual.pro 83 + \snippet code/doc_src_qmake-manual.pro 83 This is only relevant to the \c lib template, and will be ignored for all others. When this option is enabled, qmake will create a file ending in .prl @@ -3848,7 +3849,7 @@ The second step in this process is to enable reading of this meta information in the applications that use the static library: - \snippet snippets/code/doc_src_qmake-manual.pro 84 + \snippet code/doc_src_qmake-manual.pro 84 When this is enabled, qmake will process all libraries linked to by the application and find their meta-information. @@ -3908,7 +3909,7 @@ and \e static throughout your project. A typical precompiled header might look like this: - \snippet snippets/code/doc_src_qmake-manual.cpp 104 + \snippet code/doc_src_qmake-manual.cpp 104 \note A precompiled header file needs to separate C includes from C++ includes, since the precompiled header file for C files may not @@ -3920,7 +3921,7 @@ To make your project use precompiled headers, you only need to define the \l{PRECOMPILED_HEADER} variable in your project file: - \snippet snippets/code/doc_src_qmake-manual.pro 105 + \snippet code/doc_src_qmake-manual.pro 105 qmake will handle the rest, to ensure the creation and use of the precompiled header file. You do not need to @@ -3933,7 +3934,7 @@ precompiled headers. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 106 + \snippet code/doc_src_qmake-manual.pro 106 \section1 Notes on Possible Issues @@ -3942,7 +3943,7 @@ declarations may cause two different object files with the same name to be generated: - \snippet snippets/code/doc_src_qmake-manual.pro 107 + \snippet code/doc_src_qmake-manual.pro 107 To avoid potential conflicts like these, give distinctive names to header files that will be precompiled. @@ -3962,7 +3963,7 @@ \section2 \c stable.h - \snippet snippets/qmake/precompile-stable.h 0 + \snippet qmake/precompile-stable.h 0 \omit ##Keeping the snippet in qtdoc is a workaround, because it contains code @@ -4110,17 +4111,17 @@ Just start a new line with \c {SOURCES +=} and put hello.cpp after it. You should have something like this: - \snippet snippets/code/doc_src_qmake-manual.pro 108 + \snippet code/doc_src_qmake-manual.pro 108 We repeat this for each source file in the project, until we end up with the following: - \snippet snippets/code/doc_src_qmake-manual.pro 109 + \snippet code/doc_src_qmake-manual.pro 109 If you prefer to use a Make-like syntax, with all the files listed in one go you can use the newline escaping like this: - \snippet snippets/code/doc_src_qmake-manual.pro 110 + \snippet code/doc_src_qmake-manual.pro 110 Now that the source files are listed in the project file, the header files must be added. These are added in exactly the same way as source @@ -4129,7 +4130,7 @@ Once you have done this, your project file should look something like this: - \snippet snippets/code/doc_src_qmake-manual.pro 111 + \snippet code/doc_src_qmake-manual.pro 111 The target name is set automatically. It is the same as the project filename, but with the suffix appropriate for the platform. For example, if @@ -4137,24 +4138,24 @@ on Windows and \c hello on Unix. If you want to use a different name you can set it in the project file: - \snippet snippets/code/doc_src_qmake-manual.pro 112 + \snippet code/doc_src_qmake-manual.pro 112 The finished project file should look like this: - \snippet snippets/code/doc_src_qmake-manual.pro 113 + \snippet code/doc_src_qmake-manual.pro 113 You can now use qmake to generate a Makefile for your application. On the command line, in your project directory, type the following: - \snippet snippets/code/doc_src_qmake-manual.pro 114 + \snippet code/doc_src_qmake-manual.pro 114 Then type \c make or \c nmake depending on the compiler you use. For Visual Studio users, qmake can also generate Visual Studio project files. For example: - \snippet snippets/code/doc_src_qmake-manual.pro 115 + \snippet code/doc_src_qmake-manual.pro 115 \section1 Making an Application Debuggable @@ -4166,7 +4167,7 @@ For example: - \snippet snippets/code/doc_src_qmake-manual.pro 116 + \snippet code/doc_src_qmake-manual.pro 116 Use qmake as before to generate a Makefile. You will now obtain useful information about your application when running it in a debugging @@ -4186,7 +4187,7 @@ A simple scope that adds the platform-dependent file for Windows looks like this: - \snippet snippets/code/doc_src_qmake-manual.pro 117 + \snippet code/doc_src_qmake-manual.pro 117 When building for Windows, qmake adds \c hellowin.cpp to the list of source files. When building for any other platform, qmake simply ignores it. Now @@ -4195,7 +4196,7 @@ When you have done that, your project file should look something like this: - \snippet snippets/code/doc_src_qmake-manual.pro 118 + \snippet code/doc_src_qmake-manual.pro 118 Use qmake as before to generate a Makefile. @@ -4208,13 +4209,13 @@ the scope condition with the function. A check for a file called main.cpp looks like this: - \snippet snippets/code/doc_src_qmake-manual.pro 119 + \snippet code/doc_src_qmake-manual.pro 119 The \c{!} symbol is used to negate the test. That is, \c{exists( main.cpp )} is true if the file exists, and \c{!exists( main.cpp )} is true if the file does not exist. - \snippet snippets/code/doc_src_qmake-manual.pro 120 + \snippet code/doc_src_qmake-manual.pro 120 Use qmake as before to generate a makefile. If you rename \c main.cpp temporarily, you will see the message and @@ -4233,12 +4234,12 @@ the other inside it. Put the settings to be processed inside the second scope, like this: - \snippet snippets/code/doc_src_qmake-manual.pro 121 + \snippet code/doc_src_qmake-manual.pro 121 Nested scopes can be joined together using colons, so the final project file looks like this: - \snippet snippets/code/doc_src_qmake-manual.pro 122 + \snippet code/doc_src_qmake-manual.pro 122 That's it! You have now completed the tutorial for qmake, and are ready to write project files for @@ -4311,7 +4312,7 @@ to specify any. qmake will add the necessary default values. An example project file might look like this: - \snippet snippets/code/doc_src_qmake-manual.pro 123 + \snippet code/doc_src_qmake-manual.pro 123 For items that are single valued, such as the template or the destination directory, we use "="; but for multi-valued items we use "+=" to \e @@ -4449,8 +4450,8 @@ To enable a project to be built in both modes, you must add the \c debug_and_release option to the \c CONFIG variable: - \snippet snippets/qmake/debug_and_release.pro 0 - \snippet snippets/qmake/debug_and_release.pro 1 + \snippet qmake/debug_and_release.pro 0 + \snippet qmake/debug_and_release.pro 1 The scope in the above snippet modifies the build target in each mode to ensure that the resulting targets have different names. Providing different @@ -4460,23 +4461,23 @@ generate a Makefile rule to allow the project to be built in both modes. This can be invoked in the following way: - \snippet snippets/code/doc_src_qmake-manual.pro 124 + \snippet code/doc_src_qmake-manual.pro 124 The \c build_all option can be added to the \c CONFIG variable in the project file to ensure that the project is built in both modes by default: - \snippet snippets/qmake/debug_and_release.pro 2 + \snippet qmake/debug_and_release.pro 2 This allows the Makefile to be processed using the default rule: - \snippet snippets/code/doc_src_qmake-manual.pro 125 + \snippet code/doc_src_qmake-manual.pro 125 \section2 Installing in Both Modes The \c build_all option also ensures that both versions of the target will be installed when the installation rule is invoked: - \snippet snippets/code/doc_src_qmake-manual.pro 126 + \snippet code/doc_src_qmake-manual.pro 126 It is possible to customize the names of the build targets depending on the target platform. For example, a library or plugin may be named using a @@ -4486,11 +4487,10 @@ Note: This was originally used in the customwidgetplugin.pro file, but is no longer needed there. \endomit - \snippet snippets/code/doc_src_qmake-manual.pro 127 + \snippet code/doc_src_qmake-manual.pro 127 The default behavior in the above snippet is to modify the name used for the build target when building in debug mode. An \c else clause could be added to the scope to do the same for release mode. Left as it is, the target name remains unmodified. */ - diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 41e5754251..d1c70900fb 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -1381,24 +1381,24 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) !project->values("QMAKE_FRAMEWORKPATH").isEmpty() ? SettingsAsList : 0, 5) << ";\n"; { - ProStringList cflags = fixListForOutput("QMAKE_CFLAGS"); + ProStringList cflags = project->values("QMAKE_CFLAGS"); const ProStringList &prl_defines = project->values("PRL_EXPORT_DEFINES"); for (int i = 0; i < prl_defines.size(); ++i) cflags += "-D" + prl_defines.at(i); const ProStringList &defines = project->values("DEFINES"); for (int i = 0; i < defines.size(); ++i) cflags += "-D" + defines.at(i); - t << "\t\t\t\t" << writeSettings("OTHER_CFLAGS", cflags, SettingsAsList, 5) << ";\n"; + t << "\t\t\t\t" << writeSettings("OTHER_CFLAGS", fixListForOutput(cflags), SettingsAsList, 5) << ";\n"; } { - ProStringList cxxflags = fixListForOutput("QMAKE_CXXFLAGS"); + ProStringList cxxflags = project->values("QMAKE_CXXFLAGS"); const ProStringList &prl_defines = project->values("PRL_EXPORT_DEFINES"); for (int i = 0; i < prl_defines.size(); ++i) cxxflags += "-D" + prl_defines.at(i); const ProStringList &defines = project->values("DEFINES"); for (int i = 0; i < defines.size(); ++i) cxxflags += "-D" + defines.at(i); - t << "\t\t\t\t" << writeSettings("OTHER_CPLUSPLUSFLAGS", cxxflags, SettingsAsList, 5) << ";\n"; + t << "\t\t\t\t" << writeSettings("OTHER_CPLUSPLUSFLAGS", fixListForOutput(cxxflags), SettingsAsList, 5) << ";\n"; } if (!project->isActiveConfig("staticlib")) { t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS", @@ -1408,7 +1408,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) + fixListForOutput("QMAKE_LIBS_PRIVATE"), SettingsAsList, 6) << ";\n"; } - const ProStringList &archs = project->values("QT_ARCH"); + const ProStringList &archs = !project->values("QMAKE_XCODE_ARCHS").isEmpty() ? + project->values("QMAKE_XCODE_ARCHS") : project->values("QT_ARCH"); if (!archs.isEmpty()) t << "\t\t\t\t" << writeSettings("ARCHS", archs) << ";\n"; if (!project->isEmpty("OBJECTS_DIR")) @@ -1518,19 +1519,20 @@ ProjectBuilderMakefileGenerator::fixForOutput(const QString &values) project->values("QMAKE_PBX_VARS").append(reg_var.cap(1)); rep += reg_var.matchedLength(); } - QString ret = values; - ret = ret.replace(QRegExp("\\\\ "), " "); //unescape spaces - ret = ret.replace(QRegExp("('|\\\\|\")"), "\\\\1"); //fix quotes - ret = ret.replace("\t", " "); //fix tabs - ret = ret.replace(QRegExp(" "), "\\ "); //escape spaces - return ret; + + return values; } ProStringList ProjectBuilderMakefileGenerator::fixListForOutput(const char *where) { + return fixListForOutput(project->values(where)); +} + +ProStringList +ProjectBuilderMakefileGenerator::fixListForOutput(const ProStringList &l) +{ ProStringList ret; - const ProStringList &l = project->values(where); for(int i = 0; i < l.count(); i++) ret += fixForOutput(l[i].toQString()); return ret; @@ -1747,37 +1749,81 @@ ProjectBuilderMakefileGenerator::escapeFilePath(const QString &path) const #endif } +static QString quotedStringLiteral(const QString &value) +{ + QString result; + const int len = value.length(); + result.reserve(int(len * 1.1) + 2); + + result += QLatin1Char('"'); + + // Escape + for (int i = 0; i < len; ++i) { + QChar character = value.at(i);; + ushort code = character.unicode(); + switch (code) { + case '\\': + result += QLatin1String("\\\\"); + break; + case '"': + result += QLatin1String("\\\""); + break; + case '\b': + result += QLatin1String("\\b"); + break; + case '\n': + result += QLatin1String("\\n"); + break; + case '\r': + result += QLatin1String("\\r"); + break; + case '\t': + result += QLatin1String("\\t"); + break; + default: + if (code >= 32 && code <= 127) + result += character; + else + result += QLatin1String("\\u") + QString::number(code, 16).rightJustified(4, '0'); + } + } + + result += QLatin1Char('"'); + + result.squeeze(); + return result; +} + QString ProjectBuilderMakefileGenerator::writeSettings(const QString &var, const ProStringList &vals, int flags, int indent_level) { QString ret; - const QString quote = (flags & SettingsNoQuote) ? "" : "\""; - const QString escape_quote = quote.isEmpty() ? "" : QString("\\" + quote); + bool shouldQuote = !((flags & SettingsNoQuote)); + QString newline = "\n"; for(int i = 0; i < indent_level; ++i) newline += "\t"; + + ret += var + " = "; + if(flags & SettingsAsList) { - ret += var + " = (" + newline; + ret += "(" + newline; for(int i = 0, count = 0; i < vals.size(); ++i) { QString val = vals.at(i).toQString(); if(!val.isEmpty()) { if(count++ > 0) ret += "," + newline; - ret += quote + val.replace(quote, escape_quote) + quote; + if (shouldQuote) + val = quotedStringLiteral(val); + ret += val; } } ret += ")"; } else { - ret += var + " = " + quote; - for(int i = 0; i < vals.size(); ++i) { - QString val = vals.at(i).toQString(); -// if(val.isEmpty()) -// val = quote + quote; - if(i) - ret += " "; - ret += val; - } - ret += quote; + QString val = vals.join(QLatin1Char(' ')); + if (shouldQuote) + val = quotedStringLiteral(val); + ret += val; } return ret; } diff --git a/qmake/generators/mac/pbuilder_pbx.h b/qmake/generators/mac/pbuilder_pbx.h index 255dd43348..a08dc7c2bd 100644 --- a/qmake/generators/mac/pbuilder_pbx.h +++ b/qmake/generators/mac/pbuilder_pbx.h @@ -61,6 +61,7 @@ class ProjectBuilderMakefileGenerator : public UnixMakefileGenerator QString findProgram(const ProString &prog); QString fixForOutput(const QString &file); ProStringList fixListForOutput(const char *where); + ProStringList fixListForOutput(const ProStringList &list); int reftypeForFile(const QString &where); QString sourceTreeForFile(const QString &where); QString projectSuffix() const; diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 98b5a328e4..a8ae84a4e2 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2272,8 +2272,7 @@ MakefileGenerator::writeHeader(QTextStream &t) { t << "#############################################################################\n"; t << "# Makefile for building: " << escapeFilePath(var("TARGET")) << endl; - t << "# Generated by qmake (" QMAKE_VERSION_STR ") (Qt " QT_VERSION_STR ") on: "; - t << QDateTime::currentDateTime().toString() << endl; + t << "# Generated by qmake (" QMAKE_VERSION_STR ") (Qt " QT_VERSION_STR ")\n"; t << "# Project: " << fileFixify(project->projectFile()) << endl; t << "# Template: " << var("TEMPLATE") << endl; if(!project->isActiveConfig("build_pass")) diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp index 3c2801594a..cc19aa5c42 100644 --- a/qmake/library/ioutils.cpp +++ b/qmake/library/ioutils.cpp @@ -88,6 +88,11 @@ bool IoUtils::isRelativePath(const QString &path) return true; } +QStringRef IoUtils::pathName(const QString &fileName) +{ + return fileName.leftRef(fileName.lastIndexOf(QLatin1Char('/')) + 1); +} + QStringRef IoUtils::fileName(const QString &fileName) { return fileName.midRef(fileName.lastIndexOf(QLatin1Char('/')) + 1); diff --git a/qmake/library/ioutils.h b/qmake/library/ioutils.h index 160e879fce..d69725fa27 100644 --- a/qmake/library/ioutils.h +++ b/qmake/library/ioutils.h @@ -64,6 +64,7 @@ public: static bool exists(const QString &fileName) { return fileType(fileName) != FileNotFound; } static bool isRelativePath(const QString &fileName); static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); } + static QStringRef pathName(const QString &fileName); // Requires normalized path static QStringRef fileName(const QString &fileName); // Requires normalized path static QString resolvePath(const QString &baseDir, const QString &fileName); static QString shellQuoteUnix(const QString &arg); diff --git a/qmake/library/qmake_global.h b/qmake/library/qmake_global.h index 7e2247e8c6..acb95e7ab3 100644 --- a/qmake/library/qmake_global.h +++ b/qmake/library/qmake_global.h @@ -64,4 +64,8 @@ # define ALWAYS_INLINE inline #endif +#ifdef PROEVALUATOR_FULL +# define PROEVALUATOR_DEBUG +#endif + #endif diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index be0d8ea172..c0f1724563 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -44,6 +44,7 @@ #include "qmakeevaluator_p.h" #include "qmakeglobals.h" #include "qmakeparser.h" +#include "qmakevfs.h" #include "ioutils.h" #include <qbytearray.h> @@ -281,46 +282,17 @@ quoteValue(const ProString &val) return ret; } -static bool -doWriteFile(const QString &name, QIODevice::OpenMode mode, const QString &contents, QString *errStr) -{ - QByteArray bytes = contents.toLocal8Bit(); - QFile cfile(name); - if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) { - if (cfile.readAll() == bytes) - return true; - cfile.close(); - } - if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) { - *errStr = cfile.errorString(); - return false; - } - cfile.write(bytes); - cfile.close(); - if (cfile.error() != QFile::NoError) { - *errStr = cfile.errorString(); - return false; - } - return true; -} - QMakeEvaluator::VisitReturn QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, const QString &contents) { - QFileInfo qfi(fn); - if (!QDir::current().mkpath(qfi.path())) { - evalError(fL1S("Cannot create %1directory %2.") - .arg(ctx, QDir::toNativeSeparators(qfi.path()))); - return ReturnFalse; - } QString errStr; - if (!doWriteFile(qfi.filePath(), mode, contents, &errStr)) { + if (!m_vfs->writeFile(fn, mode, contents, &errStr)) { evalError(fL1S("Cannot write %1file %2: %3.") - .arg(ctx, QDir::toNativeSeparators(qfi.filePath()), errStr)); + .arg(ctx, QDir::toNativeSeparators(fn), errStr)); return ReturnFalse; } - m_parser->discardFileFromCache(qfi.filePath()); + m_parser->discardFileFromCache(fn); return ReturnTrue; } @@ -1118,11 +1090,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } } return ReturnFalse; -#ifdef PROEVALUATOR_FULL case T_REQUIRES: +#ifdef PROEVALUATOR_FULL checkRequirements(args); - return ReturnFalse; // Another qmake breakage #endif + return ReturnFalse; // Another qmake breakage case T_EVAL: { VisitReturn ret = ReturnFalse; ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep), @@ -1389,14 +1361,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } return (func_t == T_ERROR && !m_cumulative) ? ReturnError : ReturnTrue; } -#ifdef PROEVALUATOR_FULL case T_SYSTEM: { - if (m_cumulative) // Anything else would be insanity - return ReturnFalse; if (args.count() != 1) { evalError(fL1S("system(exec) requires one argument.")); return ReturnFalse; } +#ifdef PROEVALUATOR_FULL + if (m_cumulative) // Anything else would be insanity + return ReturnFalse; #ifndef QT_BOOTSTRAPPED QProcess proc; proc.setProcessChannelMode(QProcess::ForwardedChannels); @@ -1407,8 +1379,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory())) + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()) == 0); #endif - } +#else + return ReturnTrue; #endif + } case T_ISEMPTY: { if (args.count() != 1) { evalError(fL1S("isEmpty(var) requires one argument.")); @@ -1423,6 +1397,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } const QString &file = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1))); + // Don't use VFS here: + // - it supports neither listing nor even directories + // - it's unlikely that somebody would test for files they created themselves if (IoUtils::exists(file)) return ReturnTrue; int slsh = file.lastIndexOf(QLatin1Char('/')); @@ -1435,17 +1412,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } -#ifdef PROEVALUATOR_FULL case T_MKPATH: { if (args.count() != 1) { evalError(fL1S("mkpath(file) requires one argument.")); return ReturnFalse; } +#ifdef PROEVALUATOR_FULL const QString &fn = resolvePath(args.at(0).toQString(m_tmp1)); if (!QDir::current().mkpath(fn)) { evalError(fL1S("Cannot create directory %1.").arg(QDir::toNativeSeparators(fn))); return ReturnFalse; } +#endif return ReturnTrue; } case T_WRITE_FILE: { @@ -1470,6 +1448,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( evalError(fL1S("touch(file, reffile) requires two arguments.")); return ReturnFalse; } +#ifdef PROEVALUATOR_FULL const QString &tfn = resolvePath(args.at(0).toQString(m_tmp1)); const QString &rfn = resolvePath(args.at(1).toQString(m_tmp2)); #ifdef Q_OS_UNIX @@ -1506,6 +1485,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( SetFileTime(wHand, 0, 0, &ft); CloseHandle(wHand); #endif +#endif return ReturnTrue; } case T_CACHE: { @@ -1639,7 +1619,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr); } -#endif default: evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1))); return ReturnFalse; diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index 09ea231684..7c20bb8492 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -44,6 +44,7 @@ #include "qmakeglobals.h" #include "qmakeparser.h" +#include "qmakevfs.h" #include "ioutils.h" #include <qbytearray.h> @@ -174,13 +175,13 @@ const ProKey &QMakeEvaluator::map(const ProKey &var) } -QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, - QMakeParser *parser, QMakeHandler *handler) +QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs, + QMakeHandler *handler) : #ifdef PROEVALUATOR_DEBUG m_debugLevel(option->debugLevel), #endif - m_option(option), m_parser(parser), m_handler(handler) + m_option(option), m_parser(parser), m_handler(handler), m_vfs(vfs) { // So that single-threaded apps don't have to call initialize() for now. initStatics(); @@ -936,7 +937,7 @@ void QMakeEvaluator::visitProVariable( if (varName == statics.strTEMPLATE) setTemplate(); else if (varName == statics.strQMAKE_PLATFORM) - updateFeaturePaths(); + m_featureRoots = 0; #ifdef PROEVALUATOR_FULL else if (varName == statics.strREQUIRES) checkRequirements(values(varName)); @@ -1064,7 +1065,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) superdir = m_outputDir; forever { QString superfile = superdir + QLatin1String("/.qmake.super"); - if (IoUtils::exists(superfile)) { + if (m_vfs->exists(superfile)) { m_superfile = QDir::cleanPath(superfile); break; } @@ -1079,10 +1080,10 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) QString dir = m_outputDir; forever { conffile = sdir + QLatin1String("/.qmake.conf"); - if (!IoUtils::exists(conffile)) + if (!m_vfs->exists(conffile)) conffile.clear(); cachefile = dir + QLatin1String("/.qmake.cache"); - if (!IoUtils::exists(cachefile)) + if (!m_vfs->exists(cachefile)) cachefile.clear(); if (!conffile.isEmpty() || !cachefile.isEmpty()) { if (dir != sdir) @@ -1160,6 +1161,7 @@ bool QMakeEvaluator::loadSpecInternal() #endif valuesRef(ProKey("QMAKESPEC")) << ProString(m_qmakespec); m_qmakespecName = IoUtils::fileName(m_qmakespec).toString(); + // This also ensures that m_featureRoots is valid. if (evaluateFeatureFile(QLatin1String("spec_post.prf")) != ReturnTrue) return false; // The MinGW and x-build specs may change the separator; $$shell_{path,quote}() need it @@ -1173,7 +1175,9 @@ bool QMakeEvaluator::loadSpec() m_hostBuild ? m_option->qmakespec : m_option->xqmakespec); { - QMakeEvaluator evaluator(m_option, m_parser, m_handler); + QMakeEvaluator evaluator(m_option, m_parser, m_vfs, m_handler); + evaluator.m_sourceRoot = m_sourceRoot; + evaluator.m_buildRoot = m_buildRoot; if (!m_superfile.isEmpty()) { valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile); if (evaluator.evaluateFile( @@ -1330,7 +1334,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( locker.unlock(); #endif - QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_handler); + QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_vfs, m_handler); baseEnv->evaluator = baseEval; baseEval->m_superfile = m_superfile; baseEval->m_conffile = m_conffile; @@ -1429,6 +1433,7 @@ void QMakeEvaluator::updateMkspecPaths() ret << m_sourceRoot + concat; ret << m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat; + ret << m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + concat; ret.removeDuplicates(); m_mkspecPaths = ret; @@ -1450,10 +1455,14 @@ void QMakeEvaluator::updateFeaturePaths() m_option->dirlist_sep, QString::SkipEmptyParts); QStringList feature_bases; - if (!m_buildRoot.isEmpty()) + if (!m_buildRoot.isEmpty()) { + feature_bases << m_buildRoot + mkspecs_concat; feature_bases << m_buildRoot; - if (!m_sourceRoot.isEmpty()) + } + if (!m_sourceRoot.isEmpty()) { + feature_bases << m_sourceRoot + mkspecs_concat; feature_bases << m_sourceRoot; + } foreach (const QString &item, m_option->getPathListEnv(QLatin1String("QMAKEPATH"))) feature_bases << (item + mkspecs_concat); @@ -1477,8 +1486,8 @@ void QMakeEvaluator::updateFeaturePaths() } } - feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/get")).toQString(m_mtmp) - + mkspecs_concat); + feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + mkspecs_concat); + feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + mkspecs_concat); foreach (const QString &fb, feature_bases) { foreach (const ProString &sfx, values(ProKey("QMAKE_PLATFORM"))) @@ -1496,7 +1505,7 @@ void QMakeEvaluator::updateFeaturePaths() foreach (const QString &root, feature_roots) if (IoUtils::exists(root)) ret << root; - m_featureRoots = ret; + m_featureRoots = new QMakeFeatureRoots(ret); } ProString QMakeEvaluator::propertyValue(const ProKey &name) const @@ -1825,7 +1834,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile( #endif return ok; } else { - if (!(flags & LoadSilent) && !IoUtils::exists(fileName)) + if (!(flags & LoadSilent) && !m_vfs->exists(fileName)) evalError(fL1S("WARNING: Include file %1 not found").arg(fileName)); return ReturnFalse; } @@ -1854,34 +1863,55 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile( if (!fn.endsWith(QLatin1String(".prf"))) fn += QLatin1String(".prf"); - if (m_featureRoots.isEmpty()) + if (!m_featureRoots) updateFeaturePaths(); - int start_root = 0; +#ifdef PROEVALUATOR_THREAD_SAFE + m_featureRoots->mutex.lock(); +#endif QString currFn = currentFileName(); - if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) { - for (int root = 0; root < m_featureRoots.size(); ++root) - if (currFn == m_featureRoots.at(root) + fn) { - start_root = root + 1; - break; + if (IoUtils::fileName(currFn) != IoUtils::fileName(fn)) + currFn.clear(); + // Null values cannot regularly exist in the hash, so they indicate that the value still + // needs to be determined. Failed lookups are represented via non-null empty strings. + QString *fnp = &m_featureRoots->cache[qMakePair(fn, currFn)]; + if (fnp->isNull()) { + int start_root = 0; + const QStringList &paths = m_featureRoots->paths; + if (!currFn.isEmpty()) { + QStringRef currPath = IoUtils::pathName(currFn); + for (int root = 0; root < paths.size(); ++root) + if (currPath == paths.at(root)) { + start_root = root + 1; + break; + } + } + for (int root = start_root; root < paths.size(); ++root) { + QString fname = paths.at(root) + fn; + if (IoUtils::exists(fname)) { + fn = fname; + goto cool; } - } - for (int root = start_root; root < m_featureRoots.size(); ++root) { - QString fname = m_featureRoots.at(root) + fn; - if (IoUtils::exists(fname)) { - fn = fname; - goto cool; } - } #ifdef QMAKE_BUILTIN_PRFS - fn.prepend(QLatin1String(":/qmake/features/")); - if (QFileInfo(fn).exists()) - goto cool; + fn.prepend(QLatin1String(":/qmake/features/")); + if (QFileInfo(fn).exists()) + goto cool; #endif - if (!silent) - evalError(fL1S("Cannot find feature %1").arg(fileName)); - return ReturnFalse; + fn = QLatin1String(""); // Indicate failed lookup. See comment above. - cool: + cool: + *fnp = fn; + } else { + fn = *fnp; + } +#ifdef PROEVALUATOR_THREAD_SAFE + m_featureRoots->mutex.unlock(); +#endif + if (fn.isEmpty()) { + if (!silent) + evalError(fL1S("Cannot find feature %1").arg(fileName)); + return ReturnFalse; + } ProStringList &already = valuesRef(ProKey("QMAKE_INTERNAL_INCLUDED_FEATURES")); ProString afn(fn); if (already.contains(afn)) { @@ -1908,7 +1938,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile( QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileInto( const QString &fileName, ProValueMap *values, LoadFlags flags) { - QMakeEvaluator visitor(m_option, m_parser, m_handler); + QMakeEvaluator visitor(m_option, m_parser, m_vfs, m_handler); visitor.m_caller = this; visitor.m_outputDir = m_outputDir; visitor.m_featureRoots = m_featureRoots; diff --git a/qmake/library/qmakeevaluator.h b/qmake/library/qmakeevaluator.h index 09617ba019..8ca2b182c7 100644 --- a/qmake/library/qmakeevaluator.h +++ b/qmake/library/qmakeevaluator.h @@ -55,9 +55,13 @@ #include <qstack.h> #include <qstring.h> #include <qstringlist.h> +#include <qshareddata.h> #ifndef QT_BOOTSTRAPPED # include <qprocess.h> #endif +#ifdef PROEVALUATOR_THREAD_SAFE +# include <qmutex.h> +#endif QT_BEGIN_NAMESPACE @@ -83,6 +87,20 @@ public: virtual void doneWithEval(ProFile *parent) = 0; }; +typedef QPair<QString, QString> QMakeFeatureKey; // key, parent +typedef QHash<QMakeFeatureKey, QString> QMakeFeatureHash; + +class QMAKE_EXPORT QMakeFeatureRoots : public QSharedData +{ +public: + QMakeFeatureRoots(const QStringList &_paths) : paths(_paths) {} + const QStringList paths; + mutable QMakeFeatureHash cache; +#ifdef PROEVALUATOR_THREAD_SAFE + mutable QMutex mutex; +#endif +}; + // We use a QLinkedList based stack instead of a QVector based one (QStack), so that // the addresses of value maps stay constant. The qmake generators rely on that. class QMAKE_EXPORT ProValueMapStack : public QLinkedList<ProValueMap> @@ -109,7 +127,7 @@ public: static void initStatics(); static void initFunctionStatics(); - QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, + QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs, QMakeHandler *handler); ~QMakeEvaluator(); @@ -284,7 +302,7 @@ public: QStringList m_qmakepath; QStringList m_qmakefeatures; QStringList m_mkspecPaths; - QStringList m_featureRoots; + QExplicitlySharedDataPointer<QMakeFeatureRoots> m_featureRoots; ProString m_dirSep; ProFunctionDefs m_functionDefs; ProStringList m_returnValue; @@ -295,6 +313,7 @@ public: QMakeGlobals *m_option; QMakeParser *m_parser; QMakeHandler *m_handler; + QMakeVfs *m_vfs; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags) diff --git a/qmake/library/qmakeglobals.cpp b/qmake/library/qmakeglobals.cpp index 3570aa70b7..bf37d51c40 100644 --- a/qmake/library/qmakeglobals.cpp +++ b/qmake/library/qmakeglobals.cpp @@ -324,34 +324,46 @@ bool QMakeGlobals::initProperties() QT_PCLOSE(proc); } #endif - foreach (QByteArray line, data.split('\n')) - if (!line.startsWith("QMAKE_")) { - int off = line.indexOf(':'); - if (off < 0) // huh? - continue; - if (line.endsWith('\r')) - line.chop(1); - QString name = QString::fromLatin1(line.left(off)); - ProString value = ProString(QDir::fromNativeSeparators( - QString::fromLocal8Bit(line.mid(off + 1)))); - properties.insert(ProKey(name), value); - if (name.startsWith(QLatin1String("QT_")) && !name.contains(QLatin1Char('/'))) { - if (name.startsWith(QLatin1String("QT_INSTALL_"))) { + foreach (QByteArray line, data.split('\n')) { + int off = line.indexOf(':'); + if (off < 0) // huh? + continue; + if (line.endsWith('\r')) + line.chop(1); + QString name = QString::fromLatin1(line.left(off)); + ProString value = ProString(QDir::fromNativeSeparators( + QString::fromLocal8Bit(line.mid(off + 1)))); + properties.insert(ProKey(name), value); + if (name.startsWith(QLatin1String("QT_"))) { + bool plain = !name.contains(QLatin1Char('/')); + if (!plain) { + if (!name.endsWith(QLatin1String("/get"))) + continue; + name.chop(4); + } + if (name.startsWith(QLatin1String("QT_INSTALL_"))) { + if (plain) { properties.insert(ProKey(name + QLatin1String("/raw")), value); properties.insert(ProKey(name + QLatin1String("/get")), value); - if (name == QLatin1String("QT_INSTALL_PREFIX") - || name == QLatin1String("QT_INSTALL_DATA") - || name == QLatin1String("QT_INSTALL_BINS")) { - name.replace(3, 7, QLatin1String("HOST")); + } + properties.insert(ProKey(name + QLatin1String("/src")), value); + if (name == QLatin1String("QT_INSTALL_PREFIX") + || name == QLatin1String("QT_INSTALL_DATA") + || name == QLatin1String("QT_INSTALL_BINS")) { + name.replace(3, 7, QLatin1String("HOST")); + if (plain) { properties.insert(ProKey(name), value); properties.insert(ProKey(name + QLatin1String("/get")), value); } - } else if (name.startsWith(QLatin1String("QT_HOST_"))) { - properties.insert(ProKey(name + QLatin1String("/get")), value); + properties.insert(ProKey(name + QLatin1String("/src")), value); } + } else if (name.startsWith(QLatin1String("QT_HOST_"))) { + if (plain) + properties.insert(ProKey(name + QLatin1String("/get")), value); + properties.insert(ProKey(name + QLatin1String("/src")), value); } } - properties.insert(ProKey("QMAKE_VERSION"), ProString("2.01a")); + } return true; } #else diff --git a/qmake/library/qmakeparser.cpp b/qmake/library/qmakeparser.cpp index 49b5429130..35533864eb 100644 --- a/qmake/library/qmakeparser.cpp +++ b/qmake/library/qmakeparser.cpp @@ -41,6 +41,7 @@ #include "qmakeparser.h" +#include "qmakevfs.h" #include "ioutils.h" using namespace QMakeInternal; @@ -142,9 +143,10 @@ void QMakeParser::initialize() statics.strLITERAL_WHITESPACE = QLatin1String("LITERAL_WHITESPACE"); } -QMakeParser::QMakeParser(ProFileCache *cache, QMakeParserHandler *handler) +QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler) : m_cache(cache) , m_handler(handler) + , m_vfs(vfs) { // So that single-threaded apps don't have to call initialize() for now. initialize(); @@ -230,24 +232,14 @@ void QMakeParser::discardFileFromCache(const QString &fileName) bool QMakeParser::read(ProFile *pro) { - QFile file(pro->fileName()); - if (!file.open(QIODevice::ReadOnly)) { - if (m_handler && IoUtils::exists(pro->fileName())) + QString content; + QString errStr; + if (!m_vfs->readFile(pro->fileName(), &content, &errStr)) { + if (m_handler && m_vfs->exists(pro->fileName())) m_handler->message(QMakeParserHandler::ParserIoError, - fL1S("Cannot read %1: %2").arg(pro->fileName(), file.errorString())); + fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr)); return false; } - - QByteArray bcont = file.readAll(); - if (bcont.startsWith("\xef\xbb\xbf")) { - // UTF-8 BOM will cause subtle errors - m_handler->message(QMakeParserHandler::ParserIoError, - fL1S("Unexpected UTF-8 BOM in %1").arg(pro->fileName())); - return false; - } - QString content(QString::fromLocal8Bit(bcont)); - bcont.clear(); - file.close(); return read(pro, content, 1, FullGrammar); } diff --git a/qmake/library/qmakeparser.h b/qmake/library/qmakeparser.h index 732e6a05e6..e3da05cc9e 100644 --- a/qmake/library/qmakeparser.h +++ b/qmake/library/qmakeparser.h @@ -79,6 +79,7 @@ public: }; class ProFileCache; +class QMakeVfs; class QMAKE_EXPORT QMakeParser { @@ -86,7 +87,7 @@ public: // Call this from a concurrency-free context static void initialize(); - QMakeParser(ProFileCache *cache, QMakeParserHandler *handler); + QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler); enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; // fileName is expected to be absolute and cleanPath()ed. @@ -175,6 +176,7 @@ private: ProFileCache *m_cache; QMakeParserHandler *m_handler; + QMakeVfs *m_vfs; // This doesn't help gcc 3.3 ... template<typename T> friend class QTypeInfo; diff --git a/qmake/library/qmakevfs.cpp b/qmake/library/qmakevfs.cpp new file mode 100644 index 0000000000..2039387a0f --- /dev/null +++ b/qmake/library/qmakevfs.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the qmake application of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmakevfs.h" + +#include "ioutils.h" +using namespace QMakeInternal; + +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> + +#define fL1S(s) QString::fromLatin1(s) + +QT_BEGIN_NAMESPACE + +QMakeVfs::QMakeVfs() +#ifndef PROEVALUATOR_FULL + : m_magicMissing(fL1S("missing")) + , m_magicExisting(fL1S("existing")) +#endif +{ +} + +bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, + QString *errStr) +{ +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QString *cont = &m_files[fn]; + if (mode & QIODevice::Append) + *cont += contents; + else + *cont = contents; + Q_UNUSED(errStr) + return true; +#else + QFileInfo qfi(fn); + if (!QDir::current().mkpath(qfi.path())) { + *errStr = fL1S("Cannot create parent directory"); + return false; + } + QByteArray bytes = contents.toLocal8Bit(); + QFile cfile(fn); + if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) { + if (cfile.readAll() == bytes) + return true; + cfile.close(); + } + if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) { + *errStr = cfile.errorString(); + return false; + } + cfile.write(bytes); + cfile.close(); + if (cfile.error() != QFile::NoError) { + *errStr = cfile.errorString(); + return false; + } + return true; +#endif +} + +bool QMakeVfs::readFile(const QString &fn, QString *contents, QString *errStr) +{ +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QHash<QString, QString>::ConstIterator it = m_files.constFind(fn); + if (it != m_files.constEnd()) { + if (it->constData() == m_magicMissing.constData()) { + *errStr = fL1S("No such file or directory"); + return false; + } + if (it->constData() != m_magicExisting.constData()) { + *contents = *it; + return true; + } + } +#endif + + QFile file(fn); + if (!file.open(QIODevice::ReadOnly)) { +#ifndef PROEVALUATOR_FULL + if (!IoUtils::exists(fn)) { + m_files[fn] = m_magicMissing; + *errStr = fL1S("No such file or directory"); + } else +#endif + *errStr = file.errorString(); + return false; + } +#ifndef PROEVALUATOR_FULL + m_files[fn] = m_magicExisting; +#endif + + QByteArray bcont = file.readAll(); + if (bcont.startsWith("\xef\xbb\xbf")) { + // UTF-8 BOM will cause subtle errors + *errStr = fL1S("Unexpected UTF-8 BOM"); + return false; + } + *contents = QString::fromLocal8Bit(bcont); + return true; +} + +bool QMakeVfs::exists(const QString &fn) +{ +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QHash<QString, QString>::ConstIterator it = m_files.constFind(fn); + if (it != m_files.constEnd()) + return it->constData() != m_magicMissing.constData(); +#endif + bool ex = IoUtils::exists(fn); +#ifndef PROEVALUATOR_FULL + m_files[fn] = ex ? m_magicExisting : m_magicMissing; +#endif + return ex; +} + +#ifndef PROEVALUATOR_FULL +// This should be called when the sources may have changed (e.g., VCS update). +void QMakeVfs::invalidateCache() +{ +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QHash<QString, QString>::Iterator it = m_files.begin(), eit = m_files.end(); + while (it != eit) { + if (it->constData() == m_magicMissing.constData() + ||it->constData() == m_magicExisting.constData()) + it = m_files.erase(it); + else + ++it; + } +} + +// This should be called when generated files may have changed (e.g., actual build). +void QMakeVfs::invalidateContents() +{ +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + m_files.clear(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsudevlistener.h b/qmake/library/qmakevfs.h index 7534f0bcd3..13204ece9d 100644 --- a/src/plugins/platforms/kms/qkmsudevlistener.h +++ b/qmake/library/qmakevfs.h @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the plugins of the Qt Toolkit. +** This file is part of the qmake application of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,40 +39,47 @@ ** ****************************************************************************/ -#ifndef QKMSUDEVLISTENER_H -#define QKMSUDEVLISTENER_H +#ifndef QMAKEVFS_H +#define QMAKEVFS_H -#include <QObject> -#include <QMap> -#include <QList> -#include <QPointer> -#include <QString> +#include "qmake_global.h" -#include <qkmsudevhandler.h> - -#include <libudev.h> +# include <qiodevice.h> +#ifndef PROEVALUATOR_FULL +# include <qhash.h> +# include <qstring.h> +# ifdef PROEVALUATOR_THREAD_SAFE +# include <qmutex.h> +# endif +#endif QT_BEGIN_NAMESPACE -class QKmsUdevListener : public QObject +class QMAKE_EXPORT QMakeVfs { - Q_OBJECT - public: - QKmsUdevListener(QObject *parent = 0); - ~QKmsUdevListener(); + QMakeVfs(); - void addHandler(QKmsUdevHandler *); + bool writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, QString *errStr); + bool readFile(const QString &fn, QString *contents, QString *errStr); + bool exists(const QString &fn); -private: - QList<QPointer<QKmsUdevHandler> > m_handlers; - QMap<QString, QPointer<QObject> > m_devices; - struct udev *m_udev; +#ifndef PROEVALUATOR_FULL + void invalidateCache(); + void invalidateContents(); +#endif - void scan(); - bool create(struct udev_device *); +private: +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutex m_mutex; +# endif + QHash<QString, QString> m_files; + QString m_magicMissing; + QString m_magicExisting; +#endif }; QT_END_NAMESPACE -#endif // QKMSUDEVLISTENER_H +#endif // QMAKEVFS_H diff --git a/qmake/main.cpp b/qmake/main.cpp index 55f915b52f..66364b83a7 100644 --- a/qmake/main.cpp +++ b/qmake/main.cpp @@ -85,6 +85,8 @@ int runQMake(int argc, char **argv) // This is particularly important for things like QtCreator and scripted builds. setvbuf(stdout, (char *)NULL, _IONBF, 0); + QMakeVfs vfs; + Option::vfs = &vfs; QMakeGlobals globals; Option::globals = &globals; @@ -130,7 +132,7 @@ int runQMake(int argc, char **argv) ProFileCache proFileCache; Option::proFileCache = &proFileCache; - QMakeParser parser(&proFileCache, &Option::evalHandler); + QMakeParser parser(&proFileCache, &vfs, &Option::evalHandler); Option::parser = &parser; QMakeProject project; diff --git a/qmake/option.cpp b/qmake/option.cpp index 4f7cdb34a2..387d8ce375 100644 --- a/qmake/option.cpp +++ b/qmake/option.cpp @@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE EvalHandler Option::evalHandler; QMakeGlobals *Option::globals; ProFileCache *Option::proFileCache; +QMakeVfs *Option::vfs; QMakeParser *Option::parser; //convenience diff --git a/qmake/option.h b/qmake/option.h index 6225f6b4d2..af8e3b7ab8 100644 --- a/qmake/option.h +++ b/qmake/option.h @@ -43,6 +43,7 @@ #define OPTION_H #include <qmakeglobals.h> +#include <qmakevfs.h> #include <qmakeparser.h> #include <qmakeevaluator.h> @@ -87,6 +88,7 @@ struct Option static QMakeGlobals *globals; static ProFileCache *proFileCache; + static QMakeVfs *vfs; static QMakeParser *parser; //simply global convenience diff --git a/qmake/project.cpp b/qmake/project.cpp index 64e8e3c3b2..9f75d1da27 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -53,12 +53,12 @@ using namespace QMakeInternal; QT_BEGIN_NAMESPACE QMakeProject::QMakeProject() - : QMakeEvaluator(Option::globals, Option::parser, &Option::evalHandler) + : QMakeEvaluator(Option::globals, Option::parser, Option::vfs, &Option::evalHandler) { } QMakeProject::QMakeProject(QMakeProject *p) - : QMakeEvaluator(Option::globals, Option::parser, &Option::evalHandler) + : QMakeEvaluator(Option::globals, Option::parser, Option::vfs, &Option::evalHandler) { initFrom(*p); } diff --git a/qmake/property.cpp b/qmake/property.cpp index 4685440b48..38d454cb5d 100644 --- a/qmake/property.cpp +++ b/qmake/property.cpp @@ -83,6 +83,7 @@ QMakeProperty::QMakeProperty() : settings(0) { for (int i = 0; i < sizeof(propList)/sizeof(propList[0]); i++) { QString name = QString::fromLatin1(propList[i].name); + m_values[ProKey(name + "/src")] = QLibraryInfo::rawLocation(propList[i].loc, QLibraryInfo::EffectiveSourcePaths); m_values[ProKey(name + "/get")] = QLibraryInfo::rawLocation(propList[i].loc, QLibraryInfo::EffectivePaths); QString val = QLibraryInfo::rawLocation(propList[i].loc, QLibraryInfo::FinalPaths); if (!propList[i].raw) { @@ -164,11 +165,14 @@ QMakeProperty::exec() ProString val = value(ProKey(prop)); ProString pval = value(ProKey(prop + "/raw")); ProString gval = value(ProKey(prop + "/get")); + ProString sval = value(ProKey(prop + "/src")); fprintf(stdout, "%s:%s\n", prop.toLatin1().constData(), val.toLatin1().constData()); if (!pval.isEmpty() && pval != val) fprintf(stdout, "%s/raw:%s\n", prop.toLatin1().constData(), pval.toLatin1().constData()); if (!gval.isEmpty() && gval != (pval.isEmpty() ? val : pval)) fprintf(stdout, "%s/get:%s\n", prop.toLatin1().constData(), gval.toLatin1().constData()); + if (!sval.isEmpty() && sval != gval) + fprintf(stdout, "%s/src:%s\n", prop.toLatin1().constData(), sval.toLatin1().constData()); } return true; } diff --git a/qmake/qmake.pri b/qmake/qmake.pri index 66f7964c5f..4cc401bc13 100644 --- a/qmake/qmake.pri +++ b/qmake/qmake.pri @@ -4,7 +4,7 @@ DEFINES += QT_NO_TEXTCODEC QT_NO_LIBRARY QT_NO_COMPRESS QT_NO_UNICODETABLES \ #qmake code SOURCES += project.cpp property.cpp main.cpp \ - library/ioutils.cpp library/proitems.cpp library/qmakeglobals.cpp \ + library/ioutils.cpp library/proitems.cpp library/qmakevfs.cpp library/qmakeglobals.cpp \ library/qmakeparser.cpp library/qmakeevaluator.cpp library/qmakebuiltins.cpp \ generators/makefile.cpp \ generators/unix/unixmake2.cpp generators/unix/unixmake.cpp meta.cpp \ @@ -19,7 +19,7 @@ SOURCES += project.cpp property.cpp main.cpp \ generators/win32/cesdkhandler.cpp HEADERS += project.h property.h \ - library/qmake_global.h library/ioutils.h library/proitems.h library/qmakeglobals.h \ + library/qmake_global.h library/ioutils.h library/proitems.h library/qmakevfs.h library/qmakeglobals.h \ library/qmakeparser.h library/qmakeevaluator.h library/qmakeevaluator_p.h \ generators/makefile.h \ generators/unix/unixmake.h meta.h option.h cachekeys.h \ diff --git a/qmake/qmake.pro b/qmake/qmake.pro index a81d0cdf77..568ad41ce1 100644 --- a/qmake/qmake.pro +++ b/qmake/qmake.pro @@ -6,7 +6,7 @@ option(host_build) CONFIG += console bootstrap CONFIG -= qt shared app_bundle uic DEFINES += QT_BUILD_QMAKE QT_BOOTSTRAPPED \ - PROEVALUATOR_FULL PROEVALUATOR_DEBUG + PROEVALUATOR_FULL DESTDIR = ../bin/ OBJECTS_DIR = . diff --git a/qtbase.pro b/qtbase.pro index d6726b5e93..d3b03d1fba 100644 --- a/qtbase.pro +++ b/qtbase.pro @@ -107,7 +107,7 @@ prefix_build|!equals(PWD, $$OUT_PWD) { mkspecs.path = $$[QT_HOST_DATA]/mkspecs mkspecs.files = \ $$OUT_PWD/mkspecs/qconfig.pri $$OUT_PWD/mkspecs/qmodule.pri $$OUT_PWD/mkspecs/qdevice.pri \ - $$files($$PWD/mkspecs/*) # $$OUT_PWD contains only symlinks under Unix + $$files($$PWD/mkspecs/*) mkspecs.files -= $$PWD/mkspecs/modules INSTALLS += mkspecs diff --git a/src/concurrent/doc/qtconcurrent.qdocconf b/src/concurrent/doc/qtconcurrent.qdocconf index 3d5e9de5e0..7fa437c17f 100644 --- a/src/concurrent/doc/qtconcurrent.qdocconf +++ b/src/concurrent/doc/qtconcurrent.qdocconf @@ -40,3 +40,6 @@ exampledirs += ../../../examples/qtconcurrent \ excludedirs += ../../../examples/widgets/doc imagedirs += images + +navigation.landingpage = "Qt Concurrent" +navigation.cppclassespage = "Qt Concurrent C++ Classes" diff --git a/src/concurrent/doc/src/qtconcurrent-module.qdoc b/src/concurrent/doc/src/qtconcurrent-module.qdoc index b8d89cbde3..37298017c7 100644 --- a/src/concurrent/doc/src/qtconcurrent-module.qdoc +++ b/src/concurrent/doc/src/qtconcurrent-module.qdoc @@ -31,6 +31,7 @@ \brief The Qt Concurrent module contains functionality to support concurrent execution of program code \ingroup modules + \qtvariable concurrent The Qt Concurrent module extends the basic threading support found in \l{Qt Core} module and simplifies the development of code that can be executed in parallel on all available CPU cores. diff --git a/src/corelib/Qt5CoreConfigExtras.cmake.in b/src/corelib/Qt5CoreConfigExtras.cmake.in index e01b448351..36a54787b3 100644 --- a/src/corelib/Qt5CoreConfigExtras.cmake.in +++ b/src/corelib/Qt5CoreConfigExtras.cmake.in @@ -55,11 +55,8 @@ set_property(TARGET Qt5::Core APPEND PROPERTY COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION ) -!!IF isEmpty(CMAKE_HOST_DATA_DIR_IS_ABSOLUTE) -set(_qt5_corelib_extra_includes \"${_qt5Core_install_prefix}/$${CMAKE_HOST_DATA_DIR}/mkspecs/$${CMAKE_MKSPEC}\") -!!ELSE -set(_qt5_corelib_extra_includes \"$${CMAKE_HOST_DATA_DIR}mkspecs/$${CMAKE_MKSPEC}\") -!!ENDIF +include(\"${CMAKE_CURRENT_LIST_DIR}/Qt5CoreConfigExtrasMkspecDir.cmake\") + foreach(_dir ${_qt5_corelib_extra_includes}) _qt5_Core_check_file_exists(${_dir}) endforeach() diff --git a/src/corelib/Qt5CoreConfigExtrasMkspecDir.cmake.in b/src/corelib/Qt5CoreConfigExtrasMkspecDir.cmake.in new file mode 100644 index 0000000000..c357237d0e --- /dev/null +++ b/src/corelib/Qt5CoreConfigExtrasMkspecDir.cmake.in @@ -0,0 +1,6 @@ + +!!IF isEmpty(CMAKE_HOST_DATA_DIR_IS_ABSOLUTE) +set(_qt5_corelib_extra_includes \"${_qt5Core_install_prefix}/$${CMAKE_HOST_DATA_DIR}/mkspecs/$${CMAKE_MKSPEC}\") +!!ELSE +set(_qt5_corelib_extra_includes \"$${CMAKE_HOST_DATA_DIR}mkspecs/$${CMAKE_MKSPEC}\") +!!ENDIF diff --git a/src/corelib/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in b/src/corelib/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in new file mode 100644 index 0000000000..706304cf34 --- /dev/null +++ b/src/corelib/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in @@ -0,0 +1,6 @@ + +!!IF isEmpty(CMAKE_INSTALL_DATA_DIR_IS_ABSOLUTE) +set(_qt5_corelib_extra_includes \"${_qt5Core_install_prefix}/$${CMAKE_INSTALL_DATA_DIR}/mkspecs/$${CMAKE_MKSPEC}\") +!!ELSE +set(_qt5_corelib_extra_includes \"$${CMAKE_INSTALL_DATA_DIR}mkspecs/$${CMAKE_MKSPEC}\") +!!ENDIF diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index 44a3f06f50..766529c587 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -77,12 +77,32 @@ cmake_umbrella_config_file.output = $$DESTDIR/cmake/Qt5/Qt5Config.cmake cmake_umbrella_config_version_file.input = $$PWD/../../mkspecs/features/data/cmake/Qt5ConfigVersion.cmake.in cmake_umbrella_config_version_file.output = $$DESTDIR/cmake/Qt5/Qt5ConfigVersion.cmake +load(cmake_functions) + +CMAKE_HOST_DATA_DIR = $$cmakeRelativePath($$[QT_HOST_DATA/src], $$[QT_INSTALL_PREFIX]) +contains(CMAKE_HOST_DATA_DIR, "^\\.\\./.*"):!isEmpty(CMAKE_HOST_DATA_DIR) { + CMAKE_HOST_DATA_DIR = $$[QT_HOST_DATA/src]/ + CMAKE_HOST_DATA_DIR_IS_ABSOLUTE = True +} + +cmake_extras_mkspec_dir.input = $$PWD/Qt5CoreConfigExtrasMkspecDir.cmake.in +cmake_extras_mkspec_dir.output = $$DESTDIR/cmake/Qt5Core/Qt5CoreConfigExtrasMkspecDir.cmake + +CMAKE_INSTALL_DATA_DIR = $$cmakeRelativePath($$[QT_HOST_DATA], $$[QT_INSTALL_PREFIX]) +contains(CMAKE_INSTALL_DATA_DIR, "^\\.\\./.*"):!isEmpty(CMAKE_INSTALL_DATA_DIR) { + CMAKE_INSTALL_DATA_DIR = $$[QT_HOST_DATA]/ + CMAKE_INSTALL_DATA_DIR_IS_ABSOLUTE = True +} + +cmake_extras_mkspec_dir_for_install.input = $$PWD/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in +cmake_extras_mkspec_dir_for_install.output = $$DESTDIR/cmake/install/Qt5Core/Qt5CoreConfigExtrasMkspecDir.cmake + cmake_qt5_umbrella_module_files.files = $$cmake_umbrella_config_file.output $$cmake_umbrella_config_version_file.output cmake_qt5_umbrella_module_files.path = $$[QT_INSTALL_LIBS]/cmake/Qt5 -QMAKE_SUBSTITUTES += ctest_macros_file cmake_umbrella_config_file cmake_umbrella_config_version_file +QMAKE_SUBSTITUTES += ctest_macros_file cmake_umbrella_config_file cmake_umbrella_config_version_file cmake_extras_mkspec_dir cmake_extras_mkspec_dir_for_install -ctest_qt5_module_files.files += $$ctest_macros_file.output +ctest_qt5_module_files.files += $$ctest_macros_file.output $$cmake_extras_mkspec_dir_for_install.output ctest_qt5_module_files.path = $$[QT_INSTALL_LIBS]/cmake/Qt5Core diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf index 0e275ee8d4..7a3e20aa89 100644 --- a/src/corelib/doc/qtcore.qdocconf +++ b/src/corelib/doc/qtcore.qdocconf @@ -39,3 +39,8 @@ exampledirs += \ ../../../examples/tools/ imagedirs += images + +excludedirs += snippets + +navigation.landingpage = "Qt Core" +navigation.cppclassespage = "Qt Core C++ Classes" diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp index 532a0e1f59..91eaf298e1 100644 --- a/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp @@ -85,3 +85,9 @@ QByteArray ba = QUrl::toPercentEncoding("{a fishy string?}", "{}", "s"); qDebug(ba.constData()); // prints "{a fi%73hy %73tring%3F}" //! [6] + +//! [7] +QUrl url("http://qt-project.org/support/file.html"); +// url.adjusted(RemoveFilename) == "http://qt-project.org/support/" +// url.fileName() == "file.html" +//! [7] diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp index 25d24185ee..ab909e5065 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp @@ -134,3 +134,61 @@ return QVariant::fromValue(s); QObject *object = getObjectFromSomewhere(); QVariant data = QVariant::fromValue(object); //! [8] + +//! [9] + +QList<int> intList; +intList.push_back(7); +intList.push_back(11); +intList.push_back(42); + +QVariant variant = QVariant::fromValue(intList); +if (variant.canConvert<QVariantList>()) { + QSequentialIterable iterable = variant.value<QSequentialIterable>(); + // Can use foreach: + foreach (const QVariant &v, iterable) { + qDebug() << v; + } + // Can use C++11 range-for: + for (const QVariant &v : iterable) { + qDebug() << v; + } + // Can use iterators: + QSequentialIterable::const_iterator it = iterable.begin(); + const QSequentialIterable::const_iterator end = iterable.end(); + for ( ; it != end; ++it) { + qDebug() << *it; + } +} + +//! [9] + +//! [10] + +QHash<int, QString> mapping; +mapping.insert(7, "Seven"); +mapping.insert(11, "Eleven"); +mapping.insert(42, "Forty-two"); + +QVariant variant = QVariant::fromValue(mapping); +if (variant.canConvert<QVariantHash>()) { + QAssociativeIterable iterable = variant.value<QAssociativeIterable>(); + // Can use foreach over the values: + foreach (const QVariant &v, iterable) { + qDebug() << v; + } + // Can use C++11 range-for over the values: + for (const QVariant &v : iterable) { + qDebug() << v; + } + // Can use iterators: + QAssociativeIterable::const_iterator it = iterable.begin(); + const QAssociativeIterable::const_iterator end = iterable.end(); + for ( ; it != end; ++it) { + qDebug() << *it; // The current value + qDebug() << it.key(); + qDebug() << it.value(); + } +} + +//! [10] diff --git a/src/corelib/doc/src/qtcore.qdoc b/src/corelib/doc/src/qtcore.qdoc index 155a6cd8c0..88afad75c5 100644 --- a/src/corelib/doc/src/qtcore.qdoc +++ b/src/corelib/doc/src/qtcore.qdoc @@ -29,6 +29,7 @@ \module QtCore \title Qt Core C++ Classes \ingroup modules + \qtvariable core \brief Provides core non-GUI functionality. diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index f899d63a4d..41e11ea652 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -881,4 +881,26 @@ Q_UNUSED(valueOfExpression); /* the value may not be used if Q_ASSERT_X and Q_ASSUME_IMPL are noop */\ } while (0) + +/* + Sanitize compiler feature availability +*/ +#if !defined(Q_PROCESSOR_X86) +# undef QT_COMPILER_SUPPORTS_SSE2 +# undef QT_COMPILER_SUPPORTS_SSE3 +# undef QT_COMPILER_SUPPORTS_SSSE3 +# undef QT_COMPILER_SUPPORTS_SSE4_1 +# undef QT_COMPILER_SUPPORTS_SSE4_2 +# undef QT_COMPILER_SUPPORTS_AVX +# undef QT_COMPILER_SUPPORTS_AVX2 +#endif +#if !defined(Q_PROCESSOR_ARM) +# undef QT_COMPILER_SUPPORTS_IWMMXT +# undef QT_COMPILER_SUPPORTS_NEON +#endif +#if !defined(Q_PROCESSOR_MIPS) +# undef QT_COMPILER_SUPPORTS_MIPS_DSP +# undef QT_COMPILER_SUPPORTS_MIPS_DSPR2 +#endif + #endif // QCOMPILERDETECTION_H diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 85cb698afc..4ee4235278 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -934,7 +934,7 @@ bool qSharedBuild() Q_DECL_NOTHROW \endlist Some constants are defined only on certain platforms. You can use - the preprocessor symbols Q_OS_WIN and Q_OS_MACX to test that + the preprocessor symbols Q_OS_WIN and Q_OS_OSX to test that the application is compiled under Windows or OS X. \sa QLibraryInfo @@ -1077,18 +1077,20 @@ bool qSharedBuild() Q_DECL_NOTHROW \macro Q_OS_DARWIN \relates <QtGlobal> - Defined on Darwin OS (synonym for Q_OS_MAC). + Defined on Darwin-based operating systems such as OS X and iOS, + including any open source version(s) of Darwin. */ /*! \macro Q_OS_MAC \relates <QtGlobal> - Defined on OS X and iOS (synonym for Q_OS_DARWIN). + Defined on Darwin-based operating systems distributed by Apple, which + currently includes OS X and iOS, but not the open source version. */ /*! - \macro Q_OS_MACX + \macro Q_OS_OSX \relates <QtGlobal> Defined on OS X. diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index cde3e96ed1..f9629ff430 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -45,11 +45,11 @@ #include <stddef.h> -#define QT_VERSION_STR "5.1.2" +#define QT_VERSION_STR "5.2.0" /* QT_VERSION is (major << 16) + (minor << 8) + patch. */ -#define QT_VERSION 0x050102 +#define QT_VERSION 0x050200 /* can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)) */ @@ -68,12 +68,15 @@ #define QT_STRINGIFY(x) QT_STRINGIFY2(x) #include <QtCore/qsystemdetection.h> -#include <QtCore/qcompilerdetection.h> #include <QtCore/qprocessordetection.h> +#include <QtCore/qcompilerdetection.h> #if defined (__ELF__) # define Q_OF_ELF #endif +#if defined (__MACH__) && defined (__APPLE__) +# define Q_OF_MACH_O +#endif #ifdef __cplusplus diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 53a3ebbc10..18f293bba5 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -78,6 +78,7 @@ struct QLibrarySettings QLibrarySettings(); QScopedPointer<QSettings> settings; #ifdef QT_BOOTSTRAPPED + bool haveEffectiveSourcePaths; bool haveEffectivePaths; bool havePaths; #endif @@ -99,8 +100,10 @@ public: static bool haveGroup(QLibraryInfo::PathGroup group) { QLibrarySettings *ls = qt_library_settings(); - return ls ? (group == QLibraryInfo::EffectivePaths - ? ls->haveEffectivePaths : ls->havePaths) : false; + return ls ? (group == QLibraryInfo::EffectiveSourcePaths + ? ls->haveEffectiveSourcePaths + : group == QLibraryInfo::EffectivePaths + ? ls->haveEffectivePaths : ls->havePaths) : false; } #endif static QSettings *configuration() @@ -122,7 +125,12 @@ QLibrarySettings::QLibrarySettings() // This code needs to be in the regular library, as otherwise a qt.conf that // works for qmake would break things for dynamically built Qt tools. QStringList children = settings->childGroups(); +#ifdef QT_BOOTSTRAPPED + haveEffectiveSourcePaths = children.contains(QLatin1String("EffectiveSourcePaths")); + haveEffectivePaths = haveEffectiveSourcePaths || children.contains(QLatin1String("EffectivePaths")); +#else haveEffectivePaths = children.contains(QLatin1String("EffectivePaths")); +#endif // Backwards compat: an existing but empty file is claimed to contain the Paths section. havePaths = !haveEffectivePaths || children.contains(QLatin1String("Paths")); #ifndef QT_BOOTSTRAPPED @@ -130,6 +138,9 @@ QLibrarySettings::QLibrarySettings() settings.reset(0); #else } else { +#ifdef QT_BOOTSTRAPPED + haveEffectiveSourcePaths = false; +#endif haveEffectivePaths = false; havePaths = false; #endif @@ -334,9 +345,12 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group) // and qt.conf with that section is present, use it, otherwise fall back to // FinalPaths. For FinalPaths, use qt.conf if present and contains not only // [EffectivePaths], otherwise fall back to builtins. + // EffectiveSourcePaths falls back to EffectivePaths. if (!QLibraryInfoPrivate::haveGroup(group) - && (group == FinalPaths - || !(group = FinalPaths, QLibraryInfoPrivate::haveGroup(FinalPaths)))) + && !(group == EffectiveSourcePaths + && (group = EffectivePaths, QLibraryInfoPrivate::haveGroup(group))) + && !(group == EffectivePaths + && (group = FinalPaths, QLibraryInfoPrivate::haveGroup(group)))) #elif !defined(QT_NO_SETTINGS) if (!QLibraryInfoPrivate::configuration()) #endif @@ -368,6 +382,7 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group) QSettings *config = QLibraryInfoPrivate::configuration(); config->beginGroup(QLatin1String( #ifdef QT_BOOTSTRAPPED + group == EffectiveSourcePaths ? "EffectiveSourcePaths" : group == EffectivePaths ? "EffectivePaths" : #endif "Paths")); diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h index b275e018a0..17864b555b 100644 --- a/src/corelib/global/qlibraryinfo.h +++ b/src/corelib/global/qlibraryinfo.h @@ -92,7 +92,7 @@ public: }; static QString location(LibraryLocation); // ### Qt 6: consider renaming it to path() #ifdef QT_BOOTSTRAPPED - enum PathGroup { FinalPaths, EffectivePaths }; + enum PathGroup { FinalPaths, EffectivePaths, EffectiveSourcePaths }; static QString rawLocation(LibraryLocation, PathGroup); #endif diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 25c47d5d34..e714839f26 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -982,6 +982,14 @@ public: Key_MicMute = 0x01000113, + Key_Red = 0x01000114, + Key_Green = 0x01000115, + Key_Yellow = 0x01000116, + Key_Blue = 0x01000117, + + Key_ChannelUp = 0x01000118, + Key_ChannelDown = 0x01000119, + Key_MediaLast = 0x0100ffff, // Keypad navigation keys @@ -1173,7 +1181,8 @@ public: SystemLocaleShortDate, SystemLocaleLongDate, DefaultLocaleShortDate, - DefaultLocaleLongDate + DefaultLocaleLongDate, + RFC2822Date // RFC 2822 (+ 850 and 1036 during parsing) }; enum TimeSpec { diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 677cddc87e..d8d7b9cbcd 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -585,6 +585,10 @@ \value LocalDate \e{This enum value is deprecated.} Use Qt::SystemLocaleShortDate instead (or Qt::SystemLocaleLongDate if you want long dates). + \value RFC2822Date \l{RFC 2822}, \l{RFC 850} and \l{RFC 1036} format: either + \c{[ddd,] dd MMM yyyy hh:mm[:ss] +/-TZ} or \c{ddd MMM dd yyyy hh:mm[:ss] +/-TZ} + for combined dates and times. + \note For \c ISODate formats, each \c Y, \c M and \c D represents a single digit of the year, month and day used to specify the date. Each \c H, \c M and \c S represents a single digit of the hour, minute and second used to specify the time. @@ -1618,6 +1622,12 @@ \value Key_TouchpadOn \value Key_TouchpadOff \value Key_MicMute + \value Key_Red + \value Key_Green + \value Key_Yellow + \value Key_Blue + \value Key_ChannelUp + \value Key_ChannelDown \value Key_MediaLast \value Key_unknown diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index b638b4d509..dc9fa7383a 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -49,9 +49,9 @@ /* The operating system, must be one of: (Q_OS_x) - DARWIN - Darwin OS (synonym for Q_OS_MAC) - MAC - OS X or iOS (synonym for Q_OS_DARWIN) - MACX - OS X + DARWIN - Any Darwin system + MAC - OS X and iOS + OSX - OS X IOS - iOS MSDOS - MS-DOS and Windows OS2 - OS/2 @@ -186,8 +186,9 @@ # include <TargetConditionals.h> # if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE # define Q_OS_IOS -# else -# define Q_OS_MACX +# elif defined(TARGET_OS_MAC) && TARGET_OS_MAC +# define Q_OS_OSX +# define Q_OS_MACX // compatibility synonym # endif #endif diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index b6926bc544..52b80badb8 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -251,7 +251,7 @@ QT_BEGIN_NAMESPACE return retVal; enum { - DefaultStreamVersion = QDataStream::Qt_5_1 + DefaultStreamVersion = QDataStream::Qt_5_2 }; /*! @@ -539,7 +539,8 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_4_8 Same as Qt_4_6. \value Qt_4_9 Same as Qt_4_6. \value Qt_5_0 Version 13 (Qt 5.0) - \value Qt_5_1 Version 14 (Qt 5.1) + \value Qt_5_1 Version 14 (Qt 5.1, Qt 5.2) + \value Qt_5_2 Same as Qt_5_1. \sa setVersion(), version() */ diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index 969cdf4517..eb064b3fe2 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -86,8 +86,9 @@ public: Qt_4_8 = Qt_4_7, Qt_4_9 = Qt_4_8, Qt_5_0 = 13, - Qt_5_1 = 14 -#if QT_VERSION >= 0x050200 + Qt_5_1 = 14, + Qt_5_2 = Qt_5_1 +#if QT_VERSION >= 0x050300 #error Add the datastream version for this Qt version #endif }; diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 9ca512e84f..9b3ea2fe2c 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -2005,25 +2005,14 @@ bool QDir::match(const QString &filter, const QString &fileName) #endif // QT_NO_REGEXP /*! - Returns \a path with directory separators normalized (converted to "/") and - redundant ones removed, and "."s and ".."s resolved (as far as possible). - - Symbolic links are kept. This function does not return the - canonical path, but rather the simplest version of the input. - For example, "./local" becomes "local", "local/../bin" becomes - "bin" and "/local/usr/../bin" becomes "/local/bin". + Returns \a path with redundant directory separators removed, + and "."s and ".."s resolved (as far as possible). - \sa absolutePath(), canonicalPath() + This method is shared with QUrl, so it doesn't deal with QDir::separator(), + nor does it remove the trailing slash, if any. */ -QString QDir::cleanPath(const QString &path) +QString qt_normalizePathSegments(const QString &name, bool allowUncPaths) { - if (path.isEmpty()) - return path; - QString name = path; - QChar dir_separator = separator(); - if (dir_separator != QLatin1Char('/')) - name.replace(dir_separator, QLatin1Char('/')); - int used = 0, levels = 0; const int len = name.length(); QVarLengthArray<QChar> outVector(len); @@ -2033,10 +2022,8 @@ QString QDir::cleanPath(const QString &path) for (int i = 0, last = -1, iwrite = 0; i < len; ++i) { if (p[i] == QLatin1Char('/')) { while (i+1 < len && p[i+1] == QLatin1Char('/')) { -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) //allow unc paths - if (!i) + if (allowUncPaths && i == 0) break; -#endif i++; } bool eaten = false; @@ -2099,8 +2086,6 @@ QString QDir::cleanPath(const QString &path) eaten = true; #endif last = -1; - } else if (last != -1 && i == len-1) { - eaten = true; } else { levels++; } @@ -2126,6 +2111,36 @@ QString QDir::cleanPath(const QString &path) } QString ret = (used == len ? name : QString(out, used)); + return ret; +} + +/*! + Returns \a path with directory separators normalized (converted to "/") and + redundant ones removed, and "."s and ".."s resolved (as far as possible). + + Symbolic links are kept. This function does not return the + canonical path, but rather the simplest version of the input. + For example, "./local" becomes "local", "local/../bin" becomes + "bin" and "/local/usr/../bin" becomes "/local/bin". + + \sa absolutePath(), canonicalPath() +*/ +QString QDir::cleanPath(const QString &path) +{ + if (path.isEmpty()) + return path; + QString name = path; + QChar dir_separator = separator(); + if (dir_separator != QLatin1Char('/')) + name.replace(dir_separator, QLatin1Char('/')); + + bool allowUncPaths = false; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) //allow unc paths + allowUncPaths = true; +#endif + + QString ret = qt_normalizePathSegments(name, allowUncPaths); + // Strip away last slash except for root directories if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) { #if defined (Q_OS_WIN) diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp index bd36d36ac1..334c239c91 100644 --- a/src/corelib/io/qipaddress.cpp +++ b/src/corelib/io/qipaddress.cpp @@ -53,7 +53,7 @@ static QString number(quint8 val, int base = 10) } typedef QVarLengthArray<char, 64> Buffer; -static bool checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end) +static const QChar *checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end) { const ushort *const ubegin = reinterpret_cast<const ushort *>(begin); const ushort *const uend = reinterpret_cast<const ushort *>(end); @@ -64,11 +64,11 @@ static bool checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end) while (src != uend) { if (*src >= 0x7f) - return false; + return reinterpret_cast<const QChar *>(src); *dst++ = *src++; } *dst = '\0'; - return true; + return 0; } static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptLeadingZero); @@ -76,7 +76,7 @@ bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end) { Q_ASSERT(begin != end); Buffer buffer; - if (!checkedToAscii(buffer, begin, end)) + if (checkedToAscii(buffer, begin, end)) return false; const char *ptr = buffer.data(); @@ -137,12 +137,23 @@ void toString(QString &appendTo, IPv4Address address) % number(address); } -bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end) +/*! + \internal + \since 5.0 + + Parses one IPv6 address from \a begin to \a end and stores the + representation in \a address. Returns null if everything was parsed + correctly, or the pointer to the first bad character where parsing failed. + If the parsing failed for a reason not related to a particular character, + returns \a end. +*/ +const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end) { Q_ASSERT(begin != end); Buffer buffer; - if (!checkedToAscii(buffer, begin, end)) - return false; + const QChar *ret = checkedToAscii(buffer, begin, end); + if (ret) + return ret; const char *ptr = buffer.data(); @@ -158,11 +169,11 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end) } // IPv4-in-IPv6 addresses are stricter in what they accept if (dotCount != 0 && dotCount != 3) - return false; + return end; memset(address, 0, sizeof address); if (colonCount == 2 && end - begin == 2) // "::" - return true; + return 0; // if there's a double colon ("::"), this is how many zeroes it means int zeroWordsToFill; @@ -174,7 +185,7 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end) (ptr[end - begin - 2] == ':' && ptr[end - begin - 1] == ':')) { zeroWordsToFill = 9 - colonCount; } else if (colonCount < 2 || colonCount > 7) { - return false; + return end; } else { zeroWordsToFill = 8 - colonCount; } @@ -183,18 +194,13 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end) int pos = 0; while (pos < 15) { - const char *endptr; - bool ok; - quint64 ll = qstrtoull(ptr, &endptr, 16, &ok); - quint16 x = ll; - - if (ptr == endptr) { + if (*ptr == ':') { // empty field, we hope it's "::" if (zeroWordsToFill < 1) - return false; + return begin + (ptr - buffer.data()); if (pos == 0 || pos == colonCount * 2) { if (ptr[0] == '\0' || ptr[1] != ':') - return false; + return begin + (ptr - buffer.data()); ++ptr; } pos += zeroWordsToFill * 2; @@ -202,24 +208,30 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end) ++ptr; continue; } + + const char *endptr; + bool ok; + quint64 ll = qstrtoull(ptr, &endptr, 16, &ok); + quint16 x = ll; + if (!ok || ll != x) - return false; + return begin + (ptr - buffer.data()); if (*endptr == '.') { // this could be an IPv4 address // it's only valid in the last element if (pos != 12) - return false; + return begin + (ptr - buffer.data()); IPv4Address ip4; if (!parseIp4Internal(ip4, ptr, false)) - return false; + return begin + (ptr - buffer.data()); address[12] = ip4 >> 24; address[13] = ip4 >> 16; address[14] = ip4 >> 8; address[15] = ip4; - return true; + return 0; } address[pos++] = x >> 8; @@ -228,10 +240,10 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end) if (*endptr == '\0') break; if (*endptr != ':') - return false; + return begin + (endptr - buffer.data()); ptr = endptr + 1; } - return pos == 16; + return pos == 16 ? 0 : end; } static inline QChar toHex(uchar c) diff --git a/src/corelib/io/qipaddress_p.h b/src/corelib/io/qipaddress_p.h index d5c158d4d1..3059a1c205 100644 --- a/src/corelib/io/qipaddress_p.h +++ b/src/corelib/io/qipaddress_p.h @@ -63,7 +63,7 @@ typedef quint32 IPv4Address; typedef quint8 IPv6Address[16]; Q_CORE_EXPORT bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end); -Q_CORE_EXPORT bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end); +Q_CORE_EXPORT const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end); Q_CORE_EXPORT void toString(QString &appendTo, IPv4Address address); Q_CORE_EXPORT void toString(QString &appendTo, IPv6Address address); diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index e9957d2384..bc0ae5a382 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -1031,6 +1031,41 @@ static int qt_timeout_value(int msecs, int elapsed) return timeout < 0 ? 0 : timeout; } +#ifdef Q_OS_BLACKBERRY +// The BlackBerry event dispatcher uses bps_get_event. Unfortunately, already registered +// socket notifiers are disabled by a call to select. This is to rearm the standard streams. +static int bb_select(QProcessPrivate *process, int nfds, fd_set *fdread, fd_set *fdwrite, int timeout) +{ + bool stdoutEnabled = false; + bool stderrEnabled = false; + bool stdinEnabled = false; + + if (process->stdoutChannel.notifier && process->stdoutChannel.notifier->isEnabled()) { + stdoutEnabled = true; + process->stdoutChannel.notifier->setEnabled(false); + } + if (process->stderrChannel.notifier && process->stderrChannel.notifier->isEnabled()) { + stderrEnabled = true; + process->stderrChannel.notifier->setEnabled(false); + } + if (process->stdinChannel.notifier && process->stdinChannel.notifier->isEnabled()) { + stdinEnabled = true; + process->stdinChannel.notifier->setEnabled(false); + } + + const int ret = select_msecs(nfds, fdread, fdwrite, timeout); + + if (stdoutEnabled) + process->stdoutChannel.notifier->setEnabled(true); + if (stderrEnabled) + process->stderrChannel.notifier->setEnabled(true); + if (stdinEnabled) + process->stdinChannel.notifier->setEnabled(true); + + return ret; +} +#endif // Q_OS_BLACKBERRY + bool QProcessPrivate::waitForStarted(int msecs) { Q_Q(QProcess); @@ -1091,7 +1126,11 @@ bool QProcessPrivate::waitForReadyRead(int msecs) add_fd(nfds, stdinChannel.pipe[1], &fdwrite); int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); +#ifdef Q_OS_BLACKBERRY + int ret = bb_select(this, nfds + 1, &fdread, &fdwrite, timeout); +#else int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); +#endif if (ret < 0) { break; } @@ -1163,8 +1202,12 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) add_fd(nfds, stdinChannel.pipe[1], &fdwrite); - int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); - int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); + int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); +#ifdef Q_OS_BLACKBERRY + int ret = bb_select(this, nfds + 1, &fdread, &fdwrite, timeout); +#else + int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); +#endif if (ret < 0) { break; } @@ -1230,8 +1273,12 @@ bool QProcessPrivate::waitForFinished(int msecs) if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) add_fd(nfds, stdinChannel.pipe[1], &fdwrite); - int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); - int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); + int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); +#ifdef Q_OS_BLACKBERRY + int ret = bb_select(this, nfds + 1, &fdread, &fdwrite, timeout); +#else + int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout); +#endif if (ret < 0) { break; } diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index bd399f511e..ea917c90d9 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -347,6 +347,10 @@ QString QStandardPaths::displayName(StandardLocation type) /*! \fn void QStandardPaths::enableTestMode(bool testMode) + \obsolete Use QStandardPaths::setTestModeEnabled + */ +/*! + \fn void QStandardPaths::setTestModeEnabled(bool testMode) If \a testMode is true, this enables a special "test mode" in QStandardPaths, which changes writable locations @@ -369,10 +373,17 @@ QString QStandardPaths::displayName(StandardLocation type) static bool qsp_testMode = false; +#if QT_DEPRECATED_SINCE(5, 2) void QStandardPaths::enableTestMode(bool testMode) { qsp_testMode = testMode; } +#endif + +void QStandardPaths::setTestModeEnabled(bool testMode) +{ + qsp_testMode = testMode; +} /*! \fn void QStandardPaths::isTestModeEnabled() diff --git a/src/corelib/io/qstandardpaths.h b/src/corelib/io/qstandardpaths.h index d8b6d24f57..df9089ace7 100644 --- a/src/corelib/io/qstandardpaths.h +++ b/src/corelib/io/qstandardpaths.h @@ -89,7 +89,10 @@ public: static QString findExecutable(const QString &executableName, const QStringList &paths = QStringList()); - static void enableTestMode(bool testMode); +#if QT_DEPRECATED_SINCE(5, 2) + static QT_DEPRECATED void enableTestMode(bool testMode); +#endif + static void setTestModeEnabled(bool testMode); static bool isTestModeEnabled(); private: diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index f2e1f9bbc7..9607f14853 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -65,7 +65,8 @@ unencoded representation is suitable for showing to users, but the encoded representation is typically what you would send to a web server. For example, the unencoded URL - "http://b\\uuml\c{}hler.example.com" would be sent to the server as + "http://bühler.example.com/List of applicants.xml" + would be sent to the server as "http://xn--bhler-kva.example.com/List%20of%20applicants.xml". A URL can also be constructed piece by piece by calling @@ -75,8 +76,10 @@ password, host and port. setUserInfo() sets the user name and password at once. - Call isValid() to check if the URL is valid. This can be done at - any point during the constructing of a URL. + Call isValid() to check if the URL is valid. This can be done at any point + during the constructing of a URL. If isValid() returns false, you should + clear() the URL before proceeding, or start over by parsing a new URL with + setUrl(). Constructing a query is particularly convenient through the use of the \l QUrlQuery class and its methods QUrlQuery::setQueryItems(), @@ -101,13 +104,19 @@ toString(). This representation is appropriate for displaying a URL to a user in unencoded form. The encoded form however, as returned by toEncoded(), is for internal use, passing to web - servers, mail clients and so on. + servers, mail clients and so on. Both forms are technically correct + and represent the same URL unambiguously -- in fact, passing either + form to QUrl's constructor or to setUrl() will yield the same QUrl + object. QUrl conforms to the URI specification from \l{RFC 3986} (Uniform Resource Identifier: Generic Syntax), and includes scheme extensions from \l{RFC 1738} (Uniform Resource Locators). Case folding rules in QUrl conform to \l{RFC 3491} (Nameprep: A Stringprep - Profile for Internationalized Domain Names (IDN)). + Profile for Internationalized Domain Names (IDN)). It is also compatible with the + \l{http://freedesktop.org/wiki/Specifications/file-uri-spec/}{file URI specification} + from freedesktop.org, provided that the locale encodes file names using + UTF-8 (required by IDN). \section2 Error checking @@ -170,6 +179,8 @@ of a percent-encoded sequence. This mode is only valid for the setters setting components of a URL; it is not permitted in the QUrl constructor, in fromEncoded() or in setUrl(). + For more information on this mode, see the documentation for + QUrl::FullyDecoded. In TolerantMode, the parser has the following behaviour: @@ -186,11 +197,12 @@ \li Reserved and unreserved characters: An encoded URL should only contain a few characters as literals; all other characters should be percent-encoded. In TolerantMode, these characters will be - automatically percent-encoded where they are not allowed: + accepted if they are found in the URL: space / double-quote / "<" / ">" / "\" / "^" / "`" / "{" / "|" / "}" Those same characters can be decoded again by passing QUrl::DecodeReserved - to toString() or toEncoded(). + to toString() or toEncoded(). In the getters of individual components, + those characters are often returned in decoded form. \endlist @@ -225,9 +237,14 @@ \value RemoveQuery The query part of the URL (following a '?' character) is removed. \value RemoveFragment + \value RemoveFilename The filename (i.e. everything after the last '/' in the path) is removed. + The trailing '/' is kept, unless StripTrailingSlash is set. + Only valid if RemovePath is not set. \value PreferLocalFile If the URL is a local file according to isLocalFile() and contains no query or fragment, a local file path is returned. \value StripTrailingSlash The trailing slash is removed if one is present. + \value NormalizePathSegments Modifies the path to remove redundant directory separators, + and to resolve "."s and ".."s (as far as possible). Note that the case folding rules in \l{RFC 3491}{Nameprep}, which QUrl conforms to, require host names to always be converted to lower case, @@ -263,11 +280,15 @@ would appear in the URL when the full URL is represented as text. The delimiters are affected by this option change from component to component. + This flag has no effect in toString() or toEncoded(). - \value EncodeReserved Leave the US-ASCII reserved characters in their encoded - forms. + \value EncodeReserved Leave US-ASCII characters not permitted in the URL by + the specification in their encoded form. This is the + default on toString() and toEncoded(). - \value DecodeReserved Decode the US-ASCII reserved characters. + \value DecodeReserved Decode the US-ASCII characters that the URL specification + does not allow to appear in the URL. This is the + default on the getters of individual components. \value FullyEncoded Leave all characters in their properly-encoded form, as this component would appear as part of a URL. When @@ -279,28 +300,65 @@ components of the URL, this decodes every percent encoding sequence, including control characters (U+0000 to U+001F) and UTF-8 sequences found in percent-encoded form. - Note: if the component contains non-US-ASCII sequences - that aren't valid UTF-8 sequences, the behaviour is - undefined since QString cannot represent those values - (data will be lost!) - This mode is should not be used in functions where more - than one URL component is returned (userInfo() and authority()) - and it is not allowed in url() and toString(). + Use of this mode may cause data loss, see below for more information. The values of EncodeReserved and DecodeReserved should not be used together - in one call. The behaviour is undefined if that happens. They are provided - as separate values because the behaviour of the "pretty mode" with regards + in one call. The behavior is undefined if that happens. They are provided + as separate values because the behavior of the "pretty mode" with regards to reserved characters is different on certain components and specially on the full URL. - The FullyDecoded mode is similar to the behaviour of the functions - returning QString in Qt 4.x, including the fact that they will most likely - cause data loss if the component in question contains a non-UTF-8 - percent-encoded sequence. Fortunately, those cases aren't common, so this - mode should be used when the component in question is used in a non-URL - context. For example, in an FTP client application, the path to the remote - file could be stored in a QUrl object, and the string to be transmitted to - the FTP server should be obtained using this flag. + \section2 Full decoding + + The FullyDecoded mode is similar to the behavior of the functions returning + QString in Qt 4.x, in that every character represents itself and never has + any special meaning. This is true even for the percent character ('%'), + which should be interpreted to mean a literal percent, not the beginning of + a percent-encoded sequence. The same actual character, in all other + decoding modes, is represented by the sequence "%25". + + Whenever re-applying data obtained with QUrl::FullyDecoded into a QUrl, + care must be taken to use the QUrl::DecodedMode parameter to the setters + (like setPath() and setUserName()). Failure to do so may cause + re-interpretation of the percent character ('%') as the beginning of a + percent-encoded sequence. + + This mode is quite useful when portions of a URL are used in a non-URL + context. For example, to extract the username, password or file paths in an + FTP client application, the FullyDecoded mode should be used. + + This mode should be used with care, since there are two conditions that + cannot be reliably represented in the returned QString. They are: + + \list + \li \b{Non-UTF-8 sequences:} URLs may contain sequences of + percent-encoded characters that do not form valid UTF-8 sequences. Since + URLs need to be decoded using UTF-8, any decoder failure will result in + the QString containing one or more replacement characters where the + sequence existed. + + \li \b{Encoded delimiters:} URLs are also allowed to make a distinction + between a delimiter found in its literal form and its equivalent in + percent-encoded form. This is most commonly found in the query, but is + permitted in most parts of the URL. + \endlist + + The following example illustrates the problem: + + \code + QUrl original("http://example.com/?q=a%2B%3Db%26c"); + QUrl copy(original); + copy.setQuery(copy.query(QUrl::FullyDecoded), QUrl::DecodedMode); + + qDebug() << original.toString(); // prints: http://example.com/?q=a%2B%3Db%26c + qDebug() << copy.toString(); // prints: http://example.com/?q=a+=b&c + \endcode + + If the two URLs were used via HTTP GET, the interpretation by the web + server would probably be different. In the first case, it would interpret + as one parameter, with a key of "q" and value "a+=b&c". In the second + case, it would probably interpret as two parameters, one with a key of "q" + and value "a =b", and the second with a key "c" and no value. \sa QUrl::FormattingOptions */ @@ -321,6 +379,7 @@ #endif QT_BEGIN_NAMESPACE +extern QString qt_normalizePathSegments(const QString &name, bool allowUncPaths); // qdir.cpp inline static bool isHex(char c) { @@ -368,6 +427,7 @@ public: InvalidRegNameError = Host << 8, InvalidIPv4AddressError, InvalidIPv6AddressError, + InvalidCharacterInIPv6Error, InvalidIPvFutureError, HostMissingEndBracket, @@ -418,7 +478,7 @@ public: void appendHost(QString &appendTo, QUrl::FormattingOptions options) const; void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; - void appendFragment(QString &appendTo, QUrl::FormattingOptions options) const; + void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; // the "end" parameters are like STL iterators: they point to one past the last valid element bool setScheme(const QString &value, int len, bool doSetError); @@ -513,7 +573,7 @@ inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, in error->position = supplement; } -// From RFC 3896, Appendix A Collected ABNF for URI +// From RFC 3986, Appendix A Collected ABNF for URI // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] //[...] // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) @@ -541,46 +601,62 @@ inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, in // the path component has a complex ABNF that basically boils down to // slash-separated segments of "pchar" -// The above is the strict definition of the URL components and it is what we -// return encoded as FullyEncoded. However, we store the equivalent to -// PrettyDecoded internally, as that is the default formatting mode and most -// likely to be used. PrettyDecoded decodes spaces, unicode sequences and -// unambiguous delimiters. +// The above is the strict definition of the URL components and we mostly +// adhere to it, with few exceptions. QUrl obeys the following behavior: +// - percent-encoding sequences always use uppercase HEXDIG; +// - unreserved characters are *always* decoded, no exceptions; +// - the space character and bytes with the high bit set are controlled by +// the EncodeSpaces and EncodeUnicode bits; +// - control characters, the percent sign itself, and bytes with the high +// bit set that don't form valid UTF-8 sequences are always encoded, +// except in FullyDecoded mode; +// - sub-delims are always left alone, except in FullyDecoded mode; +// - gen-delim change behavior depending on which section of the URL (or +// the entire URL) we're looking at; see below; +// - characters not mentioned above, like "<", and ">", are usually +// decoded in individual sections of the URL, but encoded when the full +// URL is put together (we can change on subjective definition of +// "pretty"). // -// An ambiguous delimiter is a delimiter that, if appeared decoded, would be -// interpreted as the beginning of a new component. The exact delimiters that -// match that definition change according to the use. When each field is -// considered in isolation from the rest, there are no ambiguities. In other -// words, we always store the most decoded form (except for the query, see -// below). +// The behavior for the delimiters bears some explanation. The spec says in +// section 2.2: +// URIs that differ in the replacement of a reserved character with its +// corresponding percent-encoded octet are not equivalent. +// (note: QUrl API mistakenly uses the "reserved" term, so we will refer to +// them here as "delimiters"). // -// The ambiguities arise when components are put together. From last to first -// component of a full URL, the ambiguities are: -// - fragment: none, since it's the last. -// - query: the "#" character is ambiguous, as it starts the fragment. In -// addition, the "+" character is treated specially, as should be both -// intra-query delimiters. Since we don't know which ones they are, we -// keep all reserved characters untouched. -// - path: the "#" and "?" characters are ambigous. In addition to them, -// the slash itself is considered special. +// For that reason, we cannot encode delimiters found in decoded form and we +// cannot decode the ones found in encoded form if that would change the +// interpretation. Conversely, we *can* perform the transformation if it would +// not change the interpretation. From the last component of a URL to the first, +// here are the gen-delims we can unambiguously transform when the field is +// taken in isolation: +// - fragment: none, since it's the last +// - query: "#" is unambiguous +// - path: "#" and "?" are unambiguous // - host: completely special but never ambiguous, see setHost() below. -// - password: the "#", "?", "/", "[", "]" and "@" characters are ambiguous -// - username: the "#", "?", "/", "[", "]", "@", and ":" characters are ambiguous +// - password: the "#", "?", "/", "[", "]" and "@" characters are unambiguous +// - username: the "#", "?", "/", "[", "]", "@", and ":" characters are unambiguous // - scheme: doesn't accept any delimiter, see setScheme() below. // -// When the authority component is considered in isolation, the ambiguities of -// its components are: -// - host: special, never ambiguous -// - password: "[", "]", "@" are ambiguous -// - username: "[", "]", "@", ":" are ambiguous +// Internally, QUrl stores each component in the format that corresponds to the +// default mode (PrettyDecoded). It deviates from the "strict" FullyEncoded +// mode in the following way: +// - spaces are decoded +// - valid UTF-8 sequences are decoded +// - gen-delims that can be unambiguously transformed are decoded +// - characters controlled by DecodeReserved are often decoded, though this behavior +// can change depending on the subjective definition of "pretty" // -// Finally, when the userinfo is considered in isolation, the ambiguities of its -// components are: -// - password: none, since it's the last -// - username: ":" is ambiguous +// Note that the list of gen-delims that we can transform is different for the +// user info (user name + password) and the authority (user info + host + +// port). + // list the recoding table modifications to be used with the recodeFromUser and -// appendToUser functions, according to the rules above. +// appendToUser functions, according to the rules above. Spaces and UTF-8 +// sequences are handled outside the tables. + // the encodedXXX tables are run with the delimiters set to "leave" by default; // the decodedXXX tables are run with the delimiters set to "decode" by default // (except for the query, which doesn't use these functions) @@ -589,103 +665,88 @@ inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, in #define leave(x) ushort(0x100 | (x)) #define encode(x) ushort(0x200 | (x)) -static const ushort encodedUserNameActions[] = { - // first field, everything must be encoded, including the ":" - // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) - encode('/'), // 0 - encode('?'), // 1 - encode('#'), // 2 - encode('['), // 3 - encode(']'), // 4 - encode('@'), // 5 - encode(':'), // 6 - 0 -}; -static const ushort * const decodedUserNameInAuthorityActions = encodedUserNameActions + 3; -static const ushort * const decodedUserNameInUserInfoActions = encodedUserNameActions + 6; -static const ushort * const decodedUserNameInUrlActions = encodedUserNameActions; -static const ushort * const decodedUserNameInIsolationActions = 0; - -static const ushort encodedPasswordActions[] = { - // same as encodedUserNameActions, but decode ":" - // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) - encode('/'), // 0 - encode('?'), // 1 - encode('#'), // 2 - encode('['), // 3 - encode(']'), // 4 - encode('@'), // 5 - 0 -}; -static const ushort * const decodedPasswordInAuthorityActions = encodedPasswordActions + 3; -static const ushort * const decodedPasswordInUserInfoActions = 0; -static const ushort * const decodedPasswordInUrlActions = encodedPasswordActions; -static const ushort * const decodedPasswordInIsolationActions = 0; - -static const ushort encodedPathActions[] = { - // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - encode('['), // 0 - encode(']'), // 1 - encode('?'), // 2 - encode('#'), // 3 - leave('/'), // 4 - 0 -}; -static const ushort decodedPathInUrlActions[] = { - decode('{'), // 0 - decode('}'), // 1 - encode('?'), // 2 - encode('#'), // 3 - leave('/'), // 4 +static const ushort userNameInIsolation[] = { + decode(':'), // 0 + decode('@'), // 1 + decode(']'), // 2 + decode('['), // 3 + decode('/'), // 4 + decode('?'), // 5 + decode('#'), // 6 + + decode('"'), // 7 + decode('<'), + decode('>'), + decode('^'), + decode('\\'), + decode('|'), + decode('{'), + decode('}'), 0 }; -static const ushort * const decodedPathInIsolationActions = encodedPathActions + 4; // leave('/') - -static const ushort encodedFragmentActions[] = { - // fragment = *( pchar / "/" / "?" ) - // gen-delims permitted: ":" / "@" / "/" / "?" - // -> must encode: "[" / "]" / "#" - // HOWEVER: we allow "#" to remain decoded - decode('#'), // 0 - decode(':'), // 1 - decode('@'), // 2 - decode('/'), // 3 - decode('?'), // 4 - encode('['), // 5 - encode(']'), // 6 +static const ushort * const passwordInIsolation = userNameInIsolation + 1; +static const ushort * const pathInIsolation = userNameInIsolation + 5; +static const ushort * const queryInIsolation = userNameInIsolation + 6; +static const ushort * const fragmentInIsolation = userNameInIsolation + 7; + +static const ushort userNameInUserInfo[] = { + encode(':'), // 0 + decode('@'), // 1 + decode(']'), // 2 + decode('['), // 3 + decode('/'), // 4 + decode('?'), // 5 + decode('#'), // 6 + + decode('"'), // 7 + decode('<'), + decode('>'), + decode('^'), + decode('\\'), + decode('|'), + decode('{'), + decode('}'), 0 }; -//static const ushort * const decodedFragmentInUrlActions = 0; -static const ushort * const decodedFragmentInIsolationActions = 0; - -// the query is handled specially: the decodedQueryXXX tables are run with -// the delimiters set to "leave" by default and the others set to "encode" -static const ushort encodedQueryActions[] = { - // query = *( pchar / "/" / "?" ) - // gen-delims permitted: ":" / "@" / "/" / "?" - // HOWEVER: we leave alone them alone, plus "[" and "]" - // -> must encode: "#" - encode('#'), // 0 - 0 -}; -static const ushort decodedQueryInIsolationActions[] = { - decode('"'), // 0 - decode('<'), // 1 - decode('>'), // 2 - decode('^'), // 3 - decode('\\'),// 4 - decode('|'), // 5 - decode('{'), // 6 - decode('}'), // 7 - decode('#'), // 8 +static const ushort * const passwordInUserInfo = userNameInUserInfo + 1; + +static const ushort userNameInAuthority[] = { + encode(':'), // 0 + encode('@'), // 1 + encode(']'), // 2 + encode('['), // 3 + decode('/'), // 4 + decode('?'), // 5 + decode('#'), // 6 + + decode('"'), // 7 + decode('<'), + decode('>'), + decode('^'), + decode('\\'), + decode('|'), + decode('{'), + decode('}'), 0 }; -static const ushort decodedQueryInUrlActions[] = { - decode('{'), // 6 - decode('}'), // 7 - encode('#'), // 8 +static const ushort * const passwordInAuthority = userNameInAuthority + 1; + +static const ushort userNameInUrl[] = { + encode(':'), // 0 + encode('@'), // 1 + encode(']'), // 2 + encode('['), // 3 + encode('/'), // 4 + encode('?'), // 5 + encode('#'), // 6 + + // no need to list encode(x) for the other characters 0 }; +static const ushort * const passwordInUrl = userNameInUrl + 1; +static const ushort * const pathInUrl = userNameInUrl + 5; +static const ushort * const queryInUrl = userNameInUrl + 6; +static const ushort * const fragmentInUrl = userNameInUrl + 6; static inline void parseDecodedComponent(QString &data) { @@ -698,33 +759,22 @@ recodeFromUser(const QString &input, const ushort *actions, int from, int to) QString output; const QChar *begin = input.constData() + from; const QChar *end = input.constData() + to; - if (qt_urlRecode(output, begin, end, - QUrl::DecodeReserved, actions)) + if (qt_urlRecode(output, begin, end, 0, actions)) return output; return input.mid(from, to - from); } -// appendXXXX functions: -// the internal value is stored in its most decoded form, so that case is easy. -// DecodeUnicode and DecodeSpaces are handled by qt_urlRecode. -// That leaves these functions to handle two cases related to delimiters: -// 1) encoded encodedXXXX tables -// 2) decoded decodedXXXX tables +// appendXXXX functions: copy from the internal form to the external, user form. +// the internal value is stored in its PrettyDecoded form, so that case is easy. static inline void appendToUser(QString &appendTo, const QString &value, QUrl::FormattingOptions options, - const ushort *encodedActions, const ushort *decodedActions) + const ushort *actions) { if (options == QUrl::PrettyDecoded) { appendTo += value; return; } - const ushort *actions = 0; - if (options & QUrl::EncodeDelimiters) - actions = encodedActions; - else - actions = decodedActions; - if (!qt_urlRecode(appendTo, value.constData(), value.constEnd(), options, actions)) appendTo += value; } @@ -751,31 +801,32 @@ inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptio const ushort *userNameActions; const ushort *passwordActions; if (options & QUrl::EncodeDelimiters) { - userNameActions = encodedUserNameActions; - passwordActions = encodedPasswordActions; + userNameActions = userNameInUrl; + passwordActions = passwordInUrl; } else { switch (appendingTo) { case UserInfo: - userNameActions = decodedUserNameInUserInfoActions; - passwordActions = decodedPasswordInUserInfoActions; + userNameActions = userNameInUserInfo; + passwordActions = passwordInUserInfo; break; case Authority: - userNameActions = decodedUserNameInAuthorityActions; - passwordActions = decodedPasswordInAuthorityActions; + userNameActions = userNameInAuthority; + passwordActions = passwordInAuthority; break; case FullUrl: + userNameActions = userNameInUrl; + passwordActions = passwordInUrl; + break; + default: - userNameActions = decodedUserNameInUrlActions; - passwordActions = decodedPasswordInUrlActions; + // can't happen + Q_UNREACHABLE(); break; } } - if ((options & QUrl::EncodeReserved) == 0) - options |= QUrl::DecodeReserved; - if (!qt_urlRecode(appendTo, userName.constData(), userName.constEnd(), options, userNameActions)) appendTo += userName; if (options & QUrl::RemovePassword || !hasPassword()) { @@ -789,51 +840,52 @@ inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptio inline void QUrlPrivate::appendUserName(QString &appendTo, QUrl::FormattingOptions options) const { - appendToUser(appendTo, userName, options, encodedUserNameActions, decodedUserNameInIsolationActions); + // only called from QUrl::userName() + appendToUser(appendTo, userName, options, + options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation); } inline void QUrlPrivate::appendPassword(QString &appendTo, QUrl::FormattingOptions options) const { - appendToUser(appendTo, password, options, encodedPasswordActions, decodedPasswordInIsolationActions); + // only called from QUrl::password() + appendToUser(appendTo, password, options, + options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation); } inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const { - if (appendingTo != Path && !(options & QUrl::EncodeDelimiters)) { - if (!qt_urlRecode(appendTo, path.constData(), path.constEnd(), options, decodedPathInUrlActions)) - appendTo += path; - - } else { - appendToUser(appendTo, path, options, encodedPathActions, decodedPathInIsolationActions); + QString thePath = path; + if (options & QUrl::NormalizePathSegments) { + thePath = qt_normalizePathSegments(path, false); + } + if (options & QUrl::RemoveFilename) { + const int slash = path.lastIndexOf(QLatin1Char('/')); + if (slash == -1) + return; + thePath = path.left(slash+1); + } + // check if we need to remove trailing slashes + if (options & QUrl::StripTrailingSlash) { + while (thePath.length() > 1 && thePath.endsWith(QLatin1Char('/'))) + thePath.chop(1); } + + appendToUser(appendTo, thePath, options, + appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation); + } -inline void QUrlPrivate::appendFragment(QString &appendTo, QUrl::FormattingOptions options) const +inline void QUrlPrivate::appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const { - appendToUser(appendTo, fragment, options, encodedFragmentActions, decodedFragmentInIsolationActions); + appendToUser(appendTo, fragment, options, + options & QUrl::EncodeDelimiters ? fragmentInUrl : + appendingTo == FullUrl ? 0 : fragmentInIsolation); } inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const { - // almost the same code as the previous functions - // except we prefer not to touch the delimiters - if (options == QUrl::PrettyDecoded && appendingTo == Query) { - appendTo += query; - return; - } - - const ushort *actions = 0; - if (options & QUrl::EncodeDelimiters) { - actions = encodedQueryActions; - } else { - // reset to default qt_urlRecode behaviour (leave delimiters alone) - options |= QUrl::EncodeDelimiters; - actions = appendingTo == Query ? decodedQueryInIsolationActions : decodedQueryInUrlActions; - } - - if (!qt_urlRecode(appendTo, query.constData(), query.constData() + query.length(), - options, actions)) - appendTo += query; + appendToUser(appendTo, query, options, + appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation); } // setXXX functions @@ -978,42 +1030,31 @@ inline void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end) inline void QUrlPrivate::setUserName(const QString &value, int from, int end) { sectionIsPresent |= UserName; - userName = recodeFromUser(value, decodedUserNameInIsolationActions, from, end); + userName = recodeFromUser(value, userNameInIsolation, from, end); } inline void QUrlPrivate::setPassword(const QString &value, int from, int end) { sectionIsPresent |= Password; - password = recodeFromUser(value, decodedPasswordInIsolationActions, from, end); + password = recodeFromUser(value, passwordInIsolation, from, end); } inline void QUrlPrivate::setPath(const QString &value, int from, int end) { // sectionIsPresent |= Path; // not used, save some cycles - path = recodeFromUser(value, decodedPathInIsolationActions, from, end); + path = recodeFromUser(value, pathInIsolation, from, end); } inline void QUrlPrivate::setFragment(const QString &value, int from, int end) { sectionIsPresent |= Fragment; - fragment = recodeFromUser(value, decodedFragmentInIsolationActions, from, end); + fragment = recodeFromUser(value, fragmentInIsolation, from, end); } inline void QUrlPrivate::setQuery(const QString &value, int from, int iend) { sectionIsPresent |= Query; - - // use the default actions for the query (don't set QUrl::DecodeAllDelimiters) - QString output; - const QChar *begin = value.constData() + from; - const QChar *end = value.constData() + iend; - - // leave delimiters alone but decode the rest - if (qt_urlRecode(output, begin, end, QUrl::EncodeDelimiters, - decodedQueryInIsolationActions)) - query = output; - else - query = value.mid(from, iend - from); + query = recodeFromUser(value, queryInIsolation, from, iend); } // Host handling @@ -1059,7 +1100,7 @@ inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions o // this is either an IPv4Address or a reg-name // if it is a reg-name, it is already stored in Unicode form if (options == QUrl::EncodeUnicode) - appendTo += qt_ACE_do(host, ToAceOnly); + appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot); else appendTo += host; } @@ -1067,7 +1108,7 @@ inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions o // the whole IPvFuture is passed and parsed here, including brackets; // returns null if the parsing was successful, or the QChar of the first failure -static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end) +static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode) { // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) static const char acceptable[] = @@ -1076,19 +1117,25 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar "-._~"; // unreserved // the brackets and the "v" have been checked + const QChar *const origBegin = begin; if (begin[3].unicode() != '.') return &begin[3]; - if ((begin[2].unicode() >= 'A' && begin[2].unicode() >= 'F') || + if ((begin[2].unicode() >= 'A' && begin[2].unicode() <= 'F') || (begin[2].unicode() >= 'a' && begin[2].unicode() <= 'f') || (begin[2].unicode() >= '0' && begin[2].unicode() <= '9')) { // this is so unlikely that we'll just go down the slow path // decode the whole string, skipping the "[vH." and "]" which we already know to be there host += QString::fromRawData(begin, 4); + + // uppercase the version, if necessary + if (begin[2].unicode() >= 'a') + host[host.length() - 2] = begin[2].unicode() - 0x20; + begin += 4; --end; QString decoded; - if (qt_urlRecode(decoded, begin, end, QUrl::FullyEncoded, 0)) { + if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, begin, end, QUrl::FullyDecoded, 0)) { begin = decoded.constBegin(); end = decoded.constEnd(); } @@ -1103,37 +1150,44 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) != 0) host += *begin; else - return begin; + return decoded.isEmpty() ? begin : &origBegin[2]; } host += QLatin1Char(']'); return 0; } - return &begin[2]; + return &origBegin[2]; } // ONLY the IPv6 address is parsed here, WITHOUT the brackets -static bool parseIp6(QString &host, const QChar *begin, const QChar *end) +static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode) { QIPAddressUtils::IPv6Address address; - if (!QIPAddressUtils::parseIp6(address, begin, end)) { + const QChar *ret = QIPAddressUtils::parseIp6(address, begin, end); + if (ret) { + // this struct is kept in automatic storage because it's only 4 bytes + const ushort decodeColon[] = { decode(':'), 0 }; + // IPv6 failed parsing, check if it was a percent-encoded character in // the middle and try again QString decoded; - if (!qt_urlRecode(decoded, begin, end, QUrl::FullyEncoded, 0)) { - // no transformation, nothing to re-parse - return false; + if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, begin, end, 0, decodeColon)) { + // recurse + // if the parsing fails again, the qt_urlRecode above will return 0 + ret = parseIp6(host, decoded.constBegin(), decoded.constEnd(), mode); + + // we can't return ret, otherwise it would be dangling + return ret ? end : 0; } - // recurse - // if the parsing fails again, the qt_urlRecode above will return 0 - return parseIp6(host, decoded.constBegin(), decoded.constEnd()); + // no transformation, nothing to re-parse + return ret; } host.reserve(host.size() + (end - begin)); host += QLatin1Char('['); QIPAddressUtils::toString(host, address); host += QLatin1Char(']'); - return true; + return 0; } inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl::ParsingMode mode) @@ -1157,17 +1211,22 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl: } if (len > 5 && begin[1].unicode() == 'v') { - const QChar *c = parseIpFuture(host, begin, end); + const QChar *c = parseIpFuture(host, begin, end, mode); if (c) setError(InvalidIPvFutureError, value, c - value.constData()); return !c; + } else if (begin[1].unicode() == 'v') { + setError(InvalidIPvFutureError, value, from); } - if (parseIp6(host, begin + 1, end - 1)) + const QChar *c = parseIp6(host, begin + 1, end - 1, mode); + if (!c) return true; - setError(begin[1].unicode() == 'v' ? InvalidIPvFutureError : InvalidIPv6AddressError, - value, from); + if (c == end - 1) + setError(InvalidIPv6AddressError, value, from); + else + setError(InvalidCharacterInIPv6Error, value, c - value.constData()); return false; } @@ -1194,7 +1253,7 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl: // check for percent-encoding first QString s; - if (mode == QUrl::TolerantMode && qt_urlRecode(s, begin, end, QUrl::DecodeReserved, 0)) { + if (mode == QUrl::TolerantMode && qt_urlRecode(s, begin, end, 0, 0)) { // something was decoded // anything encoded left? int pos = s.indexOf(QChar(0x25)); // '%' @@ -1207,7 +1266,7 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl: return setHost(s, 0, s.length(), QUrl::StrictMode); } - s = qt_ACE_do(QString::fromRawData(begin, len), NormalizeAce); + s = qt_ACE_do(QString::fromRawData(begin, len), NormalizeAce, ForbidLeadingDot); if (s.isEmpty()) { setError(InvalidRegNameError, value); return false; @@ -1583,87 +1642,6 @@ inline void QUrlPrivate::validate() const } } } - -inline const QByteArray &QUrlPrivate::normalized() const -{ - if (QURL_HASFLAG(stateFlags, QUrlPrivate::Normalized)) - return encodedNormalized; - - QUrlPrivate *that = const_cast<QUrlPrivate *>(this); - QURL_SETFLAG(that->stateFlags, QUrlPrivate::Normalized); - - QUrlPrivate tmp = *this; - tmp.scheme = tmp.scheme.toLower(); - tmp.host = tmp.canonicalHost(); - - // ensure the encoded and normalized parts of the URL - tmp.ensureEncodedParts(); - if (tmp.encodedUserName.contains('%')) - q_normalizePercentEncoding(&tmp.encodedUserName, userNameExcludeChars); - if (tmp.encodedPassword.contains('%')) - q_normalizePercentEncoding(&tmp.encodedPassword, passwordExcludeChars); - if (tmp.encodedFragment.contains('%')) - q_normalizePercentEncoding(&tmp.encodedFragment, fragmentExcludeChars); - - if (tmp.encodedPath.contains('%')) { - // the path is a bit special: - // the slashes shouldn't be encoded or decoded. - // They should remain exactly like they are right now - // - // treat the path as a slash-separated sequence of pchar - QByteArray result; - result.reserve(tmp.encodedPath.length()); - if (tmp.encodedPath.startsWith('/')) - result.append('/'); - - const char *data = tmp.encodedPath.constData(); - int lastSlash = 0; - int nextSlash; - do { - ++lastSlash; - nextSlash = tmp.encodedPath.indexOf('/', lastSlash); - int len; - if (nextSlash == -1) - len = tmp.encodedPath.length() - lastSlash; - else - len = nextSlash - lastSlash; - - if (memchr(data + lastSlash, '%', len)) { - // there's at least one percent before the next slash - QByteArray block = QByteArray(data + lastSlash, len); - q_normalizePercentEncoding(&block, pathExcludeChars); - result.append(block); - } else { - // no percents in this path segment, append wholesale - result.append(data + lastSlash, len); - } - - // append the slash too, if it's there - if (nextSlash != -1) - result.append('/'); - - lastSlash = nextSlash; - } while (lastSlash != -1); - - tmp.encodedPath = result; - } - - if (!tmp.scheme.isEmpty()) // relative test - removeDotsFromPath(&tmp.encodedPath); - - int qLen = tmp.query.length(); - for (int i = 0; i < qLen; i++) { - if (qLen - i > 2 && tmp.query.at(i) == '%') { - ++i; - tmp.query[i] = qToLower(tmp.query.at(i)); - ++i; - tmp.query[i] = qToLower(tmp.query.at(i)); - } - } - encodedNormalized = tmp.toEncoded(); - - return encodedNormalized; -} #endif /*! @@ -1692,7 +1670,9 @@ inline const QByteArray &QUrlPrivate::normalized() const /*! Constructs a URL by parsing \a url. QUrl will automatically percent encode all characters that are not allowed in a URL and decode the percent-encoded - sequences that represent a character that is allowed in a URL. + sequences that represent an unreserved character (letters, digits, hyphens, + undercores, dots and tildes). All other characters are left in their + original forms. Parses the \a url using the parser mode \a parsingMode. In TolerantMode (the default), QUrl will correct certain mistakes, notably the presence of @@ -1794,8 +1774,9 @@ void QUrl::clear() /*! Parses \a url and sets this object to that value. QUrl will automatically percent encode all characters that are not allowed in a URL and decode the - percent-encoded sequences that represent a character that is allowed in a - URL. + percent-encoded sequences that represent an unreserved character (letters, + digits, hyphens, undercores, dots and tildes). All other characters are + left in their original forms. Parses the \a url using the parser mode \a parsingMode. In TolerantMode (the default), QUrl will correct certain mistakes, notably the presence of @@ -1869,6 +1850,7 @@ void QUrl::setScheme(const QString &scheme) The scheme can only contain US-ASCII letters or digits, which means it cannot contain any character that would otherwise require encoding. + Additionally, schemes are always returned in lowercase form. \sa setScheme(), isRelative() */ @@ -1900,10 +1882,11 @@ QString QUrl::scheme() const and some characters (including space) are not allowed in undecoded form. In TolerantMode (the default), all characters are accepted in undecoded form and the tolerant parser will correct stray '%' not followed by two hex - characters. In DecodedMode, '%' stand for themselves and encoded characters - are not possible. Because of that, in DecodedMode, it is not possible to - use the delimiter characters as non-delimiters (e.g., a password containing - a '@'). + characters. + + This function does not allow \a mode to be QUrl::DecodedMode. To set fully + decoded data, call setUserName(), setPassword(), setHost() and setPort() + individually. \sa setUserInfo(), setHost(), setPort() */ @@ -1911,13 +1894,13 @@ void QUrl::setAuthority(const QString &authority, ParsingMode mode) { detach(); d->clearError(); - QString data = authority; + if (mode == DecodedMode) { - parseDecodedComponent(data); - mode = TolerantMode; + qWarning("QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function"); + return; } - d->setAuthority(data, 0, data.length(), mode); + d->setAuthority(authority, 0, authority.length(), mode); if (authority.isNull()) { // QUrlPrivate::setAuthority cleared almost everything // but it leaves the Host bit set @@ -1929,13 +1912,14 @@ void QUrl::setAuthority(const QString &authority, ParsingMode mode) Returns the authority of the URL if it is defined; otherwise an empty string is returned. - The \a options argument controls how to format the authority portion of the - URL. The value of QUrl::FullyDecoded should be avoided, since it may - produce an ambiguous return value (for example, if the username contains a - colon ':' or either the username or password contain an at-sign '@'). In - all other cases, this function returns an unambiguous value, which may - contain those characters still percent-encoded, plus some control - sequences not representable in decoded form in QString. + This function returns an unambiguous value, which may contain that + characters still percent-encoded, plus some control sequences not + representable in decoded form in QString. + + The \a options argument controls how to format the user info component. The + value of QUrl::FullyDecoded is not permitted in this function. If you need + to obtain fully decoded data, call userName(), password(), host() and + port() individually. \sa setAuthority(), userInfo(), userName(), password(), host(), port() */ @@ -1943,6 +1927,11 @@ QString QUrl::authority(ComponentFormattingOptions options) const { if (!d) return QString(); + if (options == QUrl::FullyDecoded) { + qWarning("QUrl::authority(): QUrl::FullyDecoded is not permitted in this function"); + return QString(); + } + QString result; d->appendAuthority(result, options, QUrlPrivate::Authority); return result; @@ -1964,9 +1953,10 @@ QString QUrl::authority(ComponentFormattingOptions options) const and some characters (including space) are not allowed in undecoded form. In TolerantMode (the default), all characters are accepted in undecoded form and the tolerant parser will correct stray '%' not followed by two hex - characters. In DecodedMode, '%' stand for themselves and encoded characters - are not possible. Because of that, in DecodedMode, it is not possible to - use the ':' delimiter characters as non-delimiter in the user name. + characters. + + This function does not allow \a mode to be QUrl::DecodedMode. To set fully + decoded data, call setUserName() and setPassword() individually. \sa userInfo(), setUserName(), setPassword(), setAuthority() */ @@ -1976,8 +1966,8 @@ void QUrl::setUserInfo(const QString &userInfo, ParsingMode mode) d->clearError(); QString trimmed = userInfo.trimmed(); if (mode == DecodedMode) { - parseDecodedComponent(trimmed); - mode = TolerantMode; + qWarning("QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function"); + return; } d->setUserInfo(trimmed, 0, trimmed.length()); @@ -1996,12 +1986,13 @@ void QUrl::setUserInfo(const QString &userInfo, ParsingMode mode) Returns the user info of the URL, or an empty string if the user info is undefined. + This function returns an unambiguous value, which may contain that + characters still percent-encoded, plus some control sequences not + representable in decoded form in QString. + The \a options argument controls how to format the user info component. The - value of QUrl::FullyDecoded should be avoided, since it may produce an - ambiguous return value (for example, if the username contains a colon ':'). - In all other cases, this function returns an unambiguous value, which may - contain that characters still percent-encoded, plus some control sequences - not representable in decoded form in QString. + value of QUrl::FullyDecoded is not permitted in this function. If you need + to obtain fully decoded data, call userName() and password() individually. \sa setUserInfo(), userName(), password(), authority() */ @@ -2009,6 +2000,11 @@ QString QUrl::userInfo(ComponentFormattingOptions options) const { if (!d) return QString(); + if (options == QUrl::FullyDecoded) { + qWarning("QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function"); + return QString(); + } + QString result; d->appendUserInfo(result, options, QUrlPrivate::UserInfo); return result; @@ -2458,6 +2454,36 @@ QString QUrl::path(ComponentFormattingOptions options) const */ /*! + \since 5.2 + + Returns the name of the file, excluding the directory path. + + Note that, if this QUrl object is given a path ending in a slash, the name of the file is considered empty. + + If the path doesn't contain any slash, it is fully returned as the fileName. + + Example: + + \snippet code/src_corelib_io_qurl.cpp 7 + + The \a options argument controls how to format the file name component. All + values produce an unambiguous result. With QUrl::FullyDecoded, all + percent-encoded sequences are decoded; otherwise, the returned value may + contain some percent-encoded sequences for some control sequences not + representable in decoded form in QString. + + \sa path() +*/ +QString QUrl::fileName(ComponentFormattingOptions options) const +{ + const QString ourPath = path(options); + const int slash = ourPath.lastIndexOf(QLatin1Char('/')); + if (slash == -1) + return ourPath; + return ourPath.mid(slash + 1); +} + +/*! \since 4.2 Returns true if this URL contains a Query (i.e., if ? was seen on it). @@ -2903,7 +2929,7 @@ QString QUrl::fragment(ComponentFormattingOptions options) const if (!d) return QString(); QString result; - d->appendFragment(result, options); + d->appendFragment(result, options, QUrlPrivate::Fragment); if (d->hasFragment() && result.isNull()) result.detach(); return result; @@ -2976,7 +3002,7 @@ QString QUrl::topLevelDomain(ComponentFormattingOptions options) const { QString tld = qTopLevelDomain(host()); if (options & EncodeUnicode) { - return qt_ACE_do(tld, ToAceOnly); + return qt_ACE_do(tld, ToAceOnly, AllowLeadingDot); } return tld; } @@ -3148,12 +3174,8 @@ QString QUrl::toString(FormattingOptions options) const url += QLatin1String("//"); } - if (!(options & QUrl::RemovePath)) { + if (!(options & QUrl::RemovePath)) d->appendPath(url, options, QUrlPrivate::FullUrl); - // check if we need to remove trailing slashes - if ((options & StripTrailingSlash) && !d->path.isEmpty() && d->path != QLatin1String("/") && url.endsWith(QLatin1Char('/'))) - url.chop(1); - } if (!(options & QUrl::RemoveQuery) && d->hasQuery()) { url += QLatin1Char('?'); @@ -3161,7 +3183,7 @@ QString QUrl::toString(FormattingOptions options) const } if (!(options & QUrl::RemoveFragment) && d->hasFragment()) { url += QLatin1Char('#'); - d->appendFragment(url, options); + d->appendFragment(url, options, QUrlPrivate::FullUrl); } return url; @@ -3188,6 +3210,52 @@ QString QUrl::toDisplayString(FormattingOptions options) const } /*! + \since 5.2 + + Returns an adjusted version of the URL. + The output can be customized by passing flags with \a options. + + The encoding options from QUrl::ComponentFormattingOption don't make + much sense for this method, nor does QUrl::PreferLocalFile. + + This is always equivalent to QUrl(url.toString(options)). + + \sa FormattingOptions, toEncoded(), toString() +*/ +QUrl QUrl::adjusted(QUrl::FormattingOptions options) const +{ + if (!isValid()) { + // also catches isEmpty() + return QUrl(); + } + QUrl that = *this; + if (options & RemoveScheme) + that.setScheme(QString()); + if ((options & RemoveAuthority) == RemoveAuthority) { + that.setAuthority(QString()); + } else { + if ((options & RemoveUserInfo) == RemoveUserInfo) + that.setUserInfo(QString()); + else if (options & RemovePassword) + that.setPassword(QString()); + if (options & RemovePort) + that.setPort(-1); + } + if (options & RemoveQuery) + that.setQuery(QString()); + if (options & RemoveFragment) + that.setFragment(QString()); + if (options & RemovePath) { + that.setPath(QString()); + } else if (options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) { + QString path; + d->appendPath(path, options, QUrlPrivate::Path); + that.setPath(path); + } + return that; +} + +/*! Returns the encoded representation of the URL if it's valid; otherwise an empty QByteArray is returned. The output can be customized by passing flags with \a options. @@ -3296,7 +3364,7 @@ QString QUrl::fromEncodedComponent_helper(const QByteArray &ba) */ QString QUrl::fromAce(const QByteArray &domain) { - return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce); + return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce, ForbidLeadingDot /*FIXME: make configurable*/); } /*! @@ -3317,7 +3385,7 @@ QString QUrl::fromAce(const QByteArray &domain) */ QByteArray QUrl::toAce(const QString &domain) { - QString result = qt_ACE_do(domain, ToAceOnly); + QString result = qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/); return result.toLatin1(); } @@ -3403,6 +3471,75 @@ bool QUrl::operator ==(const QUrl &url) const } /*! + \since 5.2 + + Returns true if this URL and the given \a url are equal after + applying \a options to both; otherwise returns false. + + This is equivalent to calling adjusted(options) on both URLs + and comparing the resulting urls, but faster. + +*/ +bool QUrl::matches(const QUrl &url, FormattingOptions options) const +{ + if (!d && !url.d) + return true; + if (!d) + return url.d->isEmpty(); + if (!url.d) + return d->isEmpty(); + + // Compare which sections are present, but ignore Host + // which is set by parsing but not by construction, when empty. + int mask = QUrlPrivate::FullUrl & ~QUrlPrivate::Host; + + if (options & QUrl::RemoveScheme) + mask &= ~QUrlPrivate::Scheme; + else if (d->scheme != url.d->scheme) + return false; + + if (options & QUrl::RemovePassword) + mask &= ~QUrlPrivate::Password; + else if (d->password != url.d->password) + return false; + + if (options & QUrl::RemoveUserInfo) + mask &= ~QUrlPrivate::UserName; + else if (d->userName != url.d->userName) + return false; + + if (options & QUrl::RemovePort) + mask &= ~QUrlPrivate::Port; + else if (d->port != url.d->port) + return false; + + if (options & QUrl::RemoveAuthority) + mask &= ~QUrlPrivate::Host; + else if (d->host != url.d->host) + return false; + + if (options & QUrl::RemoveQuery) + mask &= ~QUrlPrivate::Query; + else if (d->query != url.d->query) + return false; + + if (options & QUrl::RemoveFragment) + mask &= ~QUrlPrivate::Fragment; + else if (d->fragment != url.d->fragment) + return false; + + if (!(d->sectionIsPresent & mask) == (url.d->sectionIsPresent & mask)) + return false; + + // Compare paths, after applying path-related options + QString path1; + d->appendPath(path1, options, QUrlPrivate::Path); + QString path2; + url.d->appendPath(path2, options, QUrlPrivate::Path); + return path1 == path2; +} + +/*! Returns true if this URL and the given \a url are not equal; otherwise returns false. */ @@ -3668,8 +3805,10 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err return QString(); // doesn't happen yet case QUrlPrivate::InvalidIPv6AddressError: return QStringLiteral("Invalid IPv6 address"); + case QUrlPrivate::InvalidCharacterInIPv6Error: + return QStringLiteral("Invalid IPv6 address (character '%1' not permitted)").arg(c); case QUrlPrivate::InvalidIPvFutureError: - return QStringLiteral("Invalid IPvFuture address"); + return QStringLiteral("Invalid IPvFuture address (character '%1' not permitted)").arg(c); case QUrlPrivate::HostMissingEndBracket: return QStringLiteral("Expected ']' to match '[' in hostname"); diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index cf208bf71e..457440bb89 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -140,7 +140,9 @@ public: RemoveFragment = 0x80, // 0x100 was a private code in Qt 4, keep unused for a while PreferLocalFile = 0x200, - StripTrailingSlash = 0x400 + StripTrailingSlash = 0x400, + RemoveFilename = 0x800, + NormalizePathSegments = 0x1000 }; enum ComponentFormattingOption { @@ -185,6 +187,7 @@ public: QString url(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toDisplayString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; + QUrl adjusted(FormattingOptions options) const; QByteArray toEncoded(FormattingOptions options = FullyEncoded) const; static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode); @@ -221,6 +224,7 @@ public: void setPath(const QString &path, ParsingMode mode = TolerantMode); QString path(ComponentFormattingOptions options = PrettyDecoded) const; + QString fileName(ComponentFormattingOptions options = PrettyDecoded) const; bool hasQuery() const; void setQuery(const QString &query, ParsingMode mode = TolerantMode); @@ -247,6 +251,8 @@ public: bool operator ==(const QUrl &url) const; bool operator !=(const QUrl &url) const; + bool matches(const QUrl &url, FormattingOptions options) const; + static QString fromPercentEncoding(const QByteArray &); static QByteArray toPercentEncoding(const QString &, const QByteArray &exclude = QByteArray(), diff --git a/src/corelib/io/qurl_p.h b/src/corelib/io/qurl_p.h index a0c1882162..9c8fe1cfc6 100644 --- a/src/corelib/io/qurl_p.h +++ b/src/corelib/io/qurl_p.h @@ -63,8 +63,9 @@ extern Q_AUTOTEST_EXPORT int qt_urlRecode(QString &appendTo, const QChar *begin, QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications = 0); // in qurlidna.cpp +enum AceLeadingDot { AllowLeadingDot, ForbidLeadingDot }; enum AceOperation { ToAceOnly, NormalizeAce }; -extern QString qt_ACE_do(const QString &domain, AceOperation op); +extern QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot); extern Q_AUTOTEST_EXPORT void qt_nameprep(QString *source, int from); extern Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len); extern Q_AUTOTEST_EXPORT void qt_punycodeEncoder(const QChar *s, int ucLength, QString *output); diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp index 70db9e09eb..e959faccd2 100644 --- a/src/corelib/io/qurlidna.cpp +++ b/src/corelib/io/qurlidna.cpp @@ -2461,7 +2461,7 @@ static int nextDotDelimiter(const QString &domain, int from = 0) return ch - b; } -QString qt_ACE_do(const QString &domain, AceOperation op) +QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot) { if (domain.isEmpty()) return domain; @@ -2479,7 +2479,8 @@ QString qt_ACE_do(const QString &domain, AceOperation op) if (labelLength == 0) { if (idx == domain.length()) break; - return QString(); // two delimiters in a row -- empty label not allowed + if (dot == ForbidLeadingDot || idx > 0) + return QString(); // two delimiters in a row -- empty label not allowed } // RFC 3490 says, about the ToASCII operation: diff --git a/src/corelib/io/qurlquery.cpp b/src/corelib/io/qurlquery.cpp index 547084840f..f6b5cd44bd 100644 --- a/src/corelib/io/qurlquery.cpp +++ b/src/corelib/io/qurlquery.cpp @@ -82,7 +82,7 @@ QT_BEGIN_NAMESPACE All of the getter methods in QUrlQuery support an optional parameter of type QUrl::ComponentFormattingOptions, including query(), which dictate how to - encode the data in question. Regardless of the mode, the returned value must + encode the data in question. Except for QUrl::FullyDecoded, the returned value must still be considered a percent-encoded string, as there are certain values which cannot be expressed in decoded form (like control characters, byte sequences not decodable to UTF-8). For that reason, the percent character is @@ -104,6 +104,20 @@ QT_BEGIN_NAMESPACE "+" sequences found in the keys, values, or query string are left exactly like written (except for the uppercasing of "%2b" to "%2B"). + \section2 Full decoding + + With QUrl::FullyDecoded formatting, all percent-encoded sequences will be + decoded fully and the '%' character is used to represent itself. + QUrl::FullyDecoded should be used with care, since it may cause data loss. + See the documentation of QUrl::FullyDecoded for information on what data may + be lost. + + This formatting mode should be used only when dealing with text presented to + the user in contexts where percent-encoding is not desired. Note that + QUrlQuery setters and query methods do not support the counterpart + QUrl::DecodedMode parsing, so using QUrl::FullyDecoded to obtain a listing of + keys may result in keys not found in the object. + \section1 Non-standard delimiters By default, QUrlQuery uses an equal sign ("=") to separate a key from its @@ -191,12 +205,9 @@ template<> void QSharedDataPointer<QUrlQueryPrivate>::detach() // the getter methods, when called with the default encoding value, will not // have to recode anything (except for toString()). // -// The "+" sub-delimiter is always left untouched. We never encode "+" to "%2B" -// nor do we decode "%2B" to "+", no matter what the user asks. -// -// The rest of the delimiters are kept in their decoded forms and that's -// considered non-ambiguous. That includes the pair and value delimiters -// themselves. +// QUrlQuery handling of delimiters is quite simple: we never touch any of +// them, except for the "#" character and the pair and value delimiters. Those +// are always kept in their decoded forms. // // But when recreating the query string, in toString(), we must take care of // the special delimiters: the pair and value delimiters, as well as the "#" @@ -205,12 +216,17 @@ template<> void QSharedDataPointer<QUrlQueryPrivate>::detach() #define decode(x) ushort(x) #define leave(x) ushort(0x100 | (x)) #define encode(x) ushort(0x200 | (x)) -static const ushort prettyDecodedActions[] = { leave('+'), 0 }; inline QString QUrlQueryPrivate::recodeFromUser(const QString &input) const { // note: duplicated in setQuery() QString output; + ushort prettyDecodedActions[] = { + decode(pairDelimiter.unicode()), + decode(valueDelimiter.unicode()), + decode('#'), + 0 + }; if (qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::DecodeReserved, prettyDecodedActions)) @@ -233,7 +249,7 @@ inline QString QUrlQueryPrivate::recodeToUser(const QString &input, QUrl::Compon if (!(encoding & QUrl::EncodeDelimiters)) { QString output; if (qt_urlRecode(output, input.constData(), input.constData() + input.length(), - encoding, prettyDecodedActions)) + encoding, 0)) return output; return input; } @@ -249,6 +265,13 @@ inline QString QUrlQueryPrivate::recodeToUser(const QString &input, QUrl::Compon void QUrlQueryPrivate::setQuery(const QString &query) { + ushort prettyDecodedActions[] = { + decode(pairDelimiter.unicode()), + decode(valueDelimiter.unicode()), + decode('#'), + 0 + }; + itemList.clear(); const QChar *pos = query.constData(); const QChar *const end = pos + query.size(); @@ -461,24 +484,18 @@ QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const return QString(); // unlike the component encoding, for the whole query we need to modify a little: - // - the "#" character is ambiguous, so we decode it only in DecodeAllDelimiters mode + // - the "#" character is unambiguous, so we encode it in EncodeDelimiters mode // - the query delimiter pair must always be encoded - // - the non-delimiters vary on DecodeUnambiguousDelimiters - // so: - // - full encoding: encode the non-delimiters, the pair, "#", "[" and "]" - // - pretty decode: decode the non-delimiters, "[" and "]"; encode the pair and "#" - // - decode all: decode the non-delimiters, "[", "]", "#"; encode the pair // start with what's always encoded ushort tableActions[] = { - leave('+'), // 0 - encode(d->pairDelimiter.unicode()), // 1 - encode(d->valueDelimiter.unicode()), // 2 - decode('#'), // 3 + encode(d->pairDelimiter.unicode()), // 0 + encode(d->valueDelimiter.unicode()), // 1 + 0, // 2 0 }; if (encoding & QUrl::EncodeDelimiters) { - tableActions[3] = encode('#'); + tableActions[2] = encode('#'); } QString result; diff --git a/src/corelib/io/qurlrecode.cpp b/src/corelib/io/qurlrecode.cpp index 5ff0c40a4f..7e77b9c251 100644 --- a/src/corelib/io/qurlrecode.cpp +++ b/src/corelib/io/qurlrecode.cpp @@ -113,59 +113,6 @@ static const uchar defaultActionTable[96] = { // 0x00 if it belongs to this category // 0xff if it doesn't -static const uchar delimsMask[96] = { - 0xff, // space - 0x00, // '!' (sub-delim) - 0xff, // '"' - 0x00, // '#' (gen-delim) - 0x00, // '$' (gen-delim) - 0xff, // '%' (percent) - 0x00, // '&' (gen-delim) - 0x00, // "'" (sub-delim) - 0x00, // '(' (sub-delim) - 0x00, // ')' (sub-delim) - 0x00, // '*' (sub-delim) - 0x00, // '+' (sub-delim) - 0x00, // ',' (sub-delim) - 0xff, // '-' (unreserved) - 0xff, // '.' (unreserved) - 0x00, // '/' (gen-delim) - - 0xff, 0xff, 0xff, 0xff, 0xff, // '0' to '4' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, // '5' to '9' (unreserved) - 0x00, // ':' (gen-delim) - 0x00, // ';' (sub-delim) - 0xff, // '<' - 0x00, // '=' (sub-delim) - 0xff, // '>' - 0x00, // '?' (gen-delim) - - 0x00, // '@' (gen-delim) - 0xff, 0xff, 0xff, 0xff, 0xff, // 'A' to 'E' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, // 'F' to 'J' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, // 'K' to 'O' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, // 'P' to 'T' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 'U' to 'Z' (unreserved) - 0x00, // '[' (gen-delim) - 0xff, // '\' - 0x00, // ']' (gen-delim) - 0xff, // '^' - 0xff, // '_' (unreserved) - - 0xff, // '`' - 0xff, 0xff, 0xff, 0xff, 0xff, // 'a' to 'e' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, // 'f' to 'j' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, // 'k' to 'o' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, // 'p' to 't' (unreserved) - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 'u' to 'z' (unreserved) - 0xff, // '{' - 0xff, // '|' - 0xff, // '}' - 0xff, // '~' (unreserved) - - 0xff // BSKP -}; - static const uchar reservedMask[96] = { 0xff, // space 0xff, // '!' (sub-delim) @@ -560,6 +507,27 @@ non_trivial: return 0; } +/*! + \since 5.0 + \internal + + This function decodes a percent-encoded string located from \a begin to \a + end, by appending each character to \a appendTo. It returns the number of + characters appended. Each percent-encoded sequence is decoded as follows: + + \list + \li from %00 to %7F: the exact decoded value is appended; + \li from %80 to %FF: QChar::ReplacementCharacter is appended; + \li bad encoding: original input is copied to the output, undecoded. + \endlist + + Given the above, it's important for the input to already have all UTF-8 + percent sequences decoded by qt_urlRecode (that is, the input should not + have been processed with QUrl::EncodeUnicode). + + The input should also be a valid percent-encoded sequence (the output of + qt_urlRecode is always valid). +*/ static int decode(QString &appendTo, const ushort *begin, const ushort *end) { const int origSize = appendTo.size(); @@ -573,6 +541,13 @@ static int decode(QString &appendTo, const ushort *begin, const ushort *end) continue; } + if (Q_UNLIKELY(end - input < 3 || !isHex(input[1]) || !isHex(input[2]))) { + // badly-encoded data + appendTo.resize(origSize + (end - begin)); + memcpy(appendTo.begin() + origSize, begin, (end - begin) * sizeof(ushort)); + return end - begin; + } + if (Q_UNLIKELY(!output)) { // detach appendTo.resize(origSize + (end - begin)); @@ -582,10 +557,9 @@ static int decode(QString &appendTo, const ushort *begin, const ushort *end) } ++input; - Q_ASSERT(input <= end - 2); // we need two characters - Q_ASSERT(isHex(input[0])); - Q_ASSERT(isHex(input[1])); *output++ = decodeNibble(input[0]) << 4 | decodeNibble(input[1]); + if (output[-1] >= 0x80) + output[-1] = QChar::ReplacementCharacter; input += 2; } @@ -613,8 +587,6 @@ static void maskTable(uchar (&table)[N], const uchar (&mask)[N]) The \a encoding option modifies the default behaviour: \list - \li QUrl::EncodeDelimiters: if set, delimiters will be left untransformed (note: not encoded!); - if unset, delimiters will be decoded \li QUrl::DecodeReserved: if set, reserved characters will be decoded; if unset, reserved characters will be encoded \li QUrl::EncodeSpaces: if set, spaces will be encoded to "%20"; if unset, they will be " " @@ -635,6 +607,9 @@ static void maskTable(uchar (&table)[N], const uchar (&mask)[N]) handled. It consists of a sequence of 16-bit values, where the low 8 bits indicate the character in question and the high 8 bits are either \c EncodeCharacter, \c LeaveCharacter or \c DecodeCharacter. + + This function corrects percent-encoded errors by interpreting every '%' as + meaning "%25" (all percents in the same content). */ Q_AUTOTEST_EXPORT int @@ -646,24 +621,11 @@ qt_urlRecode(QString &appendTo, const QChar *begin, const QChar *end, return decode(appendTo, reinterpret_cast<const ushort *>(begin), reinterpret_cast<const ushort *>(end)); } - if (!(encoding & QUrl::EncodeDelimiters) && encoding & QUrl::DecodeReserved) { - // reset the table - memset(actionTable, DecodeCharacter, sizeof actionTable); - if (encoding & QUrl::EncodeSpaces) - actionTable[0] = EncodeCharacter; - - // these are always encoded - actionTable['%' - ' '] = EncodeCharacter; - actionTable[0x7F - ' '] = EncodeCharacter; - } else { - memcpy(actionTable, defaultActionTable, sizeof actionTable); - if (!(encoding & QUrl::EncodeDelimiters)) - maskTable(actionTable, delimsMask); - if (encoding & QUrl::DecodeReserved) - maskTable(actionTable, reservedMask); - if (!(encoding & QUrl::EncodeSpaces)) - actionTable[0] = DecodeCharacter; // decode - } + memcpy(actionTable, defaultActionTable, sizeof actionTable); + if (encoding & QUrl::DecodeReserved) + maskTable(actionTable, reservedMask); + if (!(encoding & QUrl::EncodeSpaces)) + actionTable[0] = DecodeCharacter; // decode if (tableModifications) { for (const ushort *p = tableModifications; *p; ++p) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index 4162e843a7..9791a02723 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -160,8 +160,8 @@ QPersistentModelIndex::~QPersistentModelIndex() } /*! - Returns true if this persistent model index is equal to the \a other - persistent model index; otherwise returns false. + Returns \c{true} if this persistent model index is equal to the \a other + persistent model index; otherwise returns \c{false}. All values in the persistent model index are used when comparing with another persistent model index. @@ -177,8 +177,8 @@ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const /*! \since 4.1 - Returns true if this persistent model index is smaller than the \a other - persistent model index; otherwise returns false. + Returns \c{true} if this persistent model index is smaller than the \a other + persistent model index; otherwise returns \c{false}. All values in the persistent model index are used when comparing with another persistent model index. @@ -196,8 +196,8 @@ bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const \fn bool QPersistentModelIndex::operator!=(const QPersistentModelIndex &other) const \since 4.2 - Returns true if this persistent model index is not equal to the \a - other persistent model index; otherwise returns false. + Returns \c{true} if this persistent model index is not equal to the \a + other persistent model index; otherwise returns \c{false}. */ /*! @@ -258,8 +258,8 @@ QPersistentModelIndex::operator const QModelIndex&() const /*! \fn bool QPersistentModelIndex::operator==(const QModelIndex &other) const - Returns true if this persistent model index refers to the same location as - the \a other model index; otherwise returns false. + Returns \c{true} if this persistent model index refers to the same location as + the \a other model index; otherwise returns \c{false}. All values in the persistent model index are used when comparing with another model index. @@ -275,8 +275,8 @@ bool QPersistentModelIndex::operator==(const QModelIndex &other) const /*! \fn bool QPersistentModelIndex::operator!=(const QModelIndex &other) const - Returns true if this persistent model index does not refer to the same - location as the \a other model index; otherwise returns false. + Returns \c{true} if this persistent model index does not refer to the same + location as the \a other model index; otherwise returns \c{false}. */ bool QPersistentModelIndex::operator!=(const QModelIndex &other) const @@ -423,8 +423,8 @@ const QAbstractItemModel *QPersistentModelIndex::model() const /*! \fn bool QPersistentModelIndex::isValid() const - Returns true if this persistent model index is valid; otherwise returns - false. + Returns \c{true} if this persistent model index is valid; otherwise returns + \c{false}. A valid index belongs to a model, and has non-negative row and column numbers. @@ -522,7 +522,7 @@ static uint typeOfVariant(const QVariant &value) /*! \internal - return true if \a value contains a numerical type + Return \c{true} if \a value contains a numerical type. This function is used by our Q{Tree,Widget,Table}WidgetModel classes to sort. */ @@ -984,7 +984,7 @@ void QAbstractItemModel::resetInternalData() /*! \fn bool QModelIndex::isValid() const - Returns true if this model index is valid; otherwise returns false. + Returns \c{true} if this model index is valid; otherwise returns \c{false}. A valid index belongs to a model, and has non-negative row and column numbers. @@ -1041,8 +1041,8 @@ void QAbstractItemModel::resetInternalData() /*! \fn bool QModelIndex::operator==(const QModelIndex &other) const - Returns true if this model index refers to the same location as the - \a other model index; otherwise returns false. + Returns \c{true} if this model index refers to the same location as the + \a other model index; otherwise returns \c{false}. All values in the model index are used when comparing with another model index. @@ -1052,8 +1052,8 @@ void QAbstractItemModel::resetInternalData() /*! \fn bool QModelIndex::operator!=(const QModelIndex &other) const - Returns true if this model index does not refer to the same location as - the \a other model index; otherwise returns false. + Returns \c{true} if this model index does not refer to the same location as + the \a other model index; otherwise returns \c{false}. */ @@ -1113,7 +1113,7 @@ void QAbstractItemModel::resetInternalData() Items can be queried with flags() (see \l Qt::ItemFlag) to see if they can be selected, dragged, or manipulated in other ways. - If an item has child objects, hasChildren() returns true for the + If an item has child objects, hasChildren() returns \c{true} for the corresponding index. The model has a rowCount() and a columnCount() for each level of the @@ -1236,7 +1236,7 @@ void QAbstractItemModel::resetInternalData() Inserts a single column before the given \a column in the child items of the \a parent specified. - Returns true if the column is inserted; otherwise returns false. + Returns \c{true} if the column is inserted; otherwise returns \c{false}. \sa insertColumns(), insertRow(), removeColumn() */ @@ -1249,7 +1249,7 @@ void QAbstractItemModel::resetInternalData() \note This function calls the virtual method insertRows. - Returns true if the row is inserted; otherwise returns false. + Returns \c{true} if the row is inserted; otherwise returns \c{false}. \sa insertRows(), insertColumn(), removeRow() */ @@ -1284,7 +1284,7 @@ void QAbstractItemModel::resetInternalData() Removes the given \a column from the child items of the \a parent specified. - Returns true if the column is removed; otherwise returns false. + Returns \c{true} if the column is removed; otherwise returns \c{false}. \sa removeColumns(), removeRow(), insertColumn() */ @@ -1294,7 +1294,7 @@ void QAbstractItemModel::resetInternalData() Removes the given \a row from the child items of the \a parent specified. - Returns true if the row is removed; otherwise returns false. + Returns \c{true} if the row is removed; otherwise returns \c{false}. This is a convenience function that calls removeRows(). The QAbstractItemModel implementation of removeRows() does nothing. @@ -1308,8 +1308,8 @@ void QAbstractItemModel::resetInternalData() On models that support this, moves \a sourceColumn from \a sourceParent to \a destinationChild under \a destinationParent. - Returns true if the columns were successfully moved; otherwise returns - false. + Returns \c{true} if the columns were successfully moved; otherwise returns + \c{false}. \sa moveRows(), moveColumn() */ @@ -1320,8 +1320,8 @@ void QAbstractItemModel::resetInternalData() On models that support this, moves \a sourceColumn from \a sourceParent to \a destinationChild under \a destinationParent. - Returns true if the columns were successfully moved; otherwise returns - false. + Returns \c{true} if the columns were successfully moved; otherwise returns + \c{false}. \sa moveColumns(), moveRow() */ @@ -1663,8 +1663,8 @@ QAbstractItemModel::~QAbstractItemModel() */ /*! - Returns true if the model returns a valid QModelIndex for \a row and - \a column with \a parent, otherwise returns false. + Returns \c{true} if the model returns a valid QModelIndex for \a row and + \a column with \a parent, otherwise returns \c{false}. */ bool QAbstractItemModel::hasIndex(int row, int column, const QModelIndex &parent) const { @@ -1675,7 +1675,7 @@ bool QAbstractItemModel::hasIndex(int row, int column, const QModelIndex &parent /*! - Returns true if \a parent has any children; otherwise returns false. + Returns \c{true} if \a parent has any children; otherwise returns \c{false}. Use rowCount() on the parent to find out the number of children. @@ -1732,12 +1732,12 @@ QMap<int, QVariant> QAbstractItemModel::itemData(const QModelIndex &index) const /*! Sets the \a role data for the item at \a index to \a value. - Returns true if successful; otherwise returns false. + Returns \c{true} if successful; otherwise returns \c{false}. The dataChanged() signal should be emitted if the data was successfully set. - The base class implementation returns false. This function and data() must + The base class implementation returns \c{false}. This function and data() must be reimplemented for editable models. \sa Qt::ItemDataRole, data(), itemData() @@ -1766,7 +1766,7 @@ bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value Sets the role data for the item at \a index to the associated value in \a roles, for every Qt::ItemDataRole. - Returns true if successful; otherwise returns false. + Returns \c{true} if successful; otherwise returns \c{false}. Roles that are not in \a roles will not be modified. @@ -1781,10 +1781,19 @@ bool QAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, Q } /*! - Returns a list of MIME types that can be used to describe a list of model - indexes. + Returns the list of allowed MIME types. By default, the built-in + models and views use an internal MIME type: + \c{application/x-qabstractitemmodeldatalist}. - \sa mimeData() + When implementing drag and drop support in a custom model, if you + will return data in formats other than the default internal MIME + type, reimplement this function to return your list of MIME types. + + If you reimplement this function in your custom model, you must + also reimplement the member functions that call it: mimeData() and + dropMimeData(). + + \sa mimeData(), dropMimeData() */ QStringList QAbstractItemModel::mimeTypes() const { @@ -1795,11 +1804,14 @@ QStringList QAbstractItemModel::mimeTypes() const /*! Returns an object that contains serialized items of data corresponding to - the list of \a indexes specified. The formats used to describe the encoded - data is obtained from the mimeTypes() function. + the list of \a indexes specified. The format used to describe the encoded + data is obtained from the mimeTypes() function. This default implementation + uses the default MIME type returned by the default implementation of + mimeTypes(). If you reimplement mimeTypes() in your custom model to return + more MIME types, reimplement this function to make use of them. - If the list of indexes is empty, or there are no supported MIME types, 0 is - returned rather than a serialized empty list. + If the list of \a indexes is empty, or there are no supported MIME types, 0 + is returned rather than a serialized empty list. \sa mimeTypes(), dropMimeData() */ @@ -1820,13 +1832,13 @@ QMimeData *QAbstractItemModel::mimeData(const QModelIndexList &indexes) const } /*! - Returns whether a model can accept a drop of data. + Returns \c{true} if a model can accept a drop of the \a data. This + default implementation always returns \c{true}. - This can be used to indicate whether a drop of certain data is allowed, for example - by using a 'forbidden' emblem on a mouse cursor during a drag operation. - - This method returns true by default. Reimplementations can return whether the - \a data can be dropped at \a row, \a column, \a parent with \a action. + Reimplement this function in your custom model, if you want to + test whether the \a data can be dropped at \a row, \a column, + \a parent with \a action. If you don't need that test, it is not + necessary to reimplement this function. \sa dropMimeData(), {Using drag and drop with item views} */ @@ -1846,8 +1858,8 @@ bool QAbstractItemModel::canDropMimeData(const QMimeData *data, Qt::DropAction a Handles the \a data supplied by a drag and drop operation that ended with the given \a action. - Returns true if the data and action can be handled by the model; otherwise - returns false. + Returns \c{true} if the data and action were handled by the model; otherwise + returns \c{false}. The specified \a row, \a column and \a parent indicate the location of an item in the model where the operation ended. It is the responsibility of @@ -1859,10 +1871,16 @@ bool QAbstractItemModel::canDropMimeData(const QMimeData *data, Qt::DropAction a When \a row and \a column are -1 it means that the dropped data should be considered as dropped directly on \a parent. Usually this will mean - appending the data as child items of \a parent. If \a row and column are + appending the data as child items of \a parent. If \a row and \a column are greater than or equal zero, it means that the drop occurred just before the specified \a row and \a column in the specified \a parent. + The mimeTypes() member is called to get the list of acceptable MIME types. + This default implementation assumes the default implementation of mimeTypes(), + which returns a single default MIME type. If you reimplement mimeTypes() in + your custom model to return multiple MIME types, you must reimplement this + function to make use of them. + \sa supportedDropActions(), canDropMimeData(), {Using drag and drop with item views} */ bool QAbstractItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, @@ -1950,7 +1968,7 @@ void QAbstractItemModel::doSetSupportedDragActions(Qt::DropActions actions) /*! \note The base class implementation of this function does nothing and - returns false. + returns \c{false}. On models that support this, inserts \a count rows into the model before the given \a row. Items in the new row will be children of the item @@ -1964,8 +1982,8 @@ void QAbstractItemModel::doSetSupportedDragActions(Qt::DropActions actions) If \a parent has no children, a single column with \a count rows is inserted. - Returns true if the rows were successfully inserted; otherwise returns - false. + Returns \c{true} if the rows were successfully inserted; otherwise returns + \c{false}. If you implement your own model, you can reimplement this function if you want to support insertions. Alternatively, you can provide your own API for @@ -1993,10 +2011,10 @@ bool QAbstractItemModel::insertRows(int, int, const QModelIndex &) If \a parent has no children, a single row with \a count columns is inserted. - Returns true if the columns were successfully inserted; otherwise returns - false. + Returns \c{true} if the columns were successfully inserted; otherwise returns + \c{false}. - The base class implementation does nothing and returns false. + The base class implementation does nothing and returns \c{false}. If you implement your own model, you can reimplement this function if you want to support insertions. Alternatively, you can provide your own API for @@ -2013,10 +2031,10 @@ bool QAbstractItemModel::insertColumns(int, int, const QModelIndex &) On models that support this, removes \a count rows starting with the given \a row under parent \a parent from the model. - Returns true if the rows were successfully removed; otherwise returns - false. + Returns \c{true} if the rows were successfully removed; otherwise returns + \c{false}. - The base class implementation does nothing and returns false. + The base class implementation does nothing and returns \c{false}. If you implement your own model, you can reimplement this function if you want to support removing. Alternatively, you can provide your own API for @@ -2034,10 +2052,10 @@ bool QAbstractItemModel::removeRows(int, int, const QModelIndex &) On models that support this, removes \a count columns starting with the given \a column under parent \a parent from the model. - Returns true if the columns were successfully removed; otherwise returns - false. + Returns \c{true} if the columns were successfully removed; otherwise returns + \c{false}. - The base class implementation does nothing and returns false. + The base class implementation does nothing and returns \c{false}. If you implement your own model, you can reimplement this function if you want to support removing. Alternatively, you can provide your own API for @@ -2056,10 +2074,10 @@ bool QAbstractItemModel::removeColumns(int, int, const QModelIndex &) \a sourceRow under parent \a sourceParent to row \a destinationChild under parent \a destinationParent. - Returns true if the rows were successfully moved; otherwise returns - false. + Returns \c{true} if the rows were successfully moved; otherwise returns + \c{false}. - The base class implementation does nothing and returns false. + The base class implementation does nothing and returns \c{false}. If you implement your own model, you can reimplement this function if you want to support moving. Alternatively, you can provide your own API for @@ -2077,10 +2095,10 @@ bool QAbstractItemModel::moveRows(const QModelIndex &, int , int , const QModelI \a sourceColumn under parent \a sourceParent to column \a destinationChild under parent \a destinationParent. - Returns true if the columns were successfully moved; otherwise returns - false. + Returns \c{true} if the columns were successfully moved; otherwise returns + \c{false}. - The base class implementation does nothing and returns false. + The base class implementation does nothing and returns \c{false}. If you implement your own model, you can reimplement this function if you want to support moving. Alternatively, you can provide your own API for @@ -2109,10 +2127,10 @@ void QAbstractItemModel::fetchMore(const QModelIndex &) } /*! - Returns true if there is more data available for \a parent; otherwise - returns false. + Returns \c{true} if there is more data available for \a parent; otherwise + returns \c{false}. - The default implementation always returns false. + The default implementation always returns \c{false}. If canFetchMore() returns true, the fetchMore() function should be called. This is the behavior of QAbstractItemView, for example. @@ -2310,7 +2328,7 @@ QHash<int,QByteArray> QAbstractItemModel::roleNames() const Lets the model know that it should submit cached information to permanent storage. This function is typically used for row editing. - Returns true if there is no error; otherwise returns false. + Returns \c{true} if there is no error; otherwise returns \c{false}. \sa revert() */ @@ -2355,7 +2373,7 @@ QVariant QAbstractItemModel::headerData(int section, Qt::Orientation orientation Sets the data for the given \a role and \a section in the header with the specified \a orientation to the \a value supplied. - Returns true if the header's data was updated; otherwise returns false. + Returns \c{true} if the header's data was updated; otherwise returns \c{false}. When reimplementing this function, the headerDataChanged() signal must be emitted explicitly. @@ -2682,7 +2700,7 @@ bool QAbstractItemModelPrivate::allowMove(const QModelIndex &srcParent, int star you must ensure that the \a destinationChild is not within the range of \a sourceFirst and \a sourceLast + 1. You must also ensure that you do not attempt to move a row to one of its own children or ancestors. - This method returns false if either condition is true, in which case you + This method returns \c{false} if either condition is true, in which case you should abort your move operation. \table 80% @@ -2949,7 +2967,7 @@ void QAbstractItemModel::endRemoveColumns() you must ensure that the \a destinationChild is not within the range of \a sourceFirst and \a sourceLast + 1. You must also ensure that you do not attempt to move a column to one of its own children or ancestors. - This method returns false if either condition is true, in which case you + This method returns \c{false} if either condition is true, in which case you should abort your move operation. \sa endMoveColumns() @@ -3596,8 +3614,8 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti \fn bool QModelIndex::operator<(const QModelIndex &other) const \since 4.1 - Returns true if this model index is smaller than the \a other - model index; otherwise returns false. + Returns \c{true} if this model index is smaller than the \a other + model index; otherwise returns \c{false}. The less than calculation is not directly useful to developers - the way that indexes with different parents compare is not defined. This operator only exists so that the diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h index f3bf2c1019..ac98476492 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.h +++ b/src/corelib/itemmodels/qabstractitemmodel.h @@ -113,6 +113,11 @@ public: inline bool operator!=(const QPersistentModelIndex &other) const { return !operator==(other); } QPersistentModelIndex &operator=(const QPersistentModelIndex &other); +#ifdef Q_COMPILER_RVALUE_REFS + inline QPersistentModelIndex(QPersistentModelIndex &&other) : d(other.d) { other.d = 0; } + inline QPersistentModelIndex &operator=(QPersistentModelIndex &&other) + { qSwap(d, other.d); return *this; } +#endif inline void swap(QPersistentModelIndex &other) { qSwap(d, other.d); } bool operator==(const QModelIndex &other) const; bool operator!=(const QModelIndex &other) const; diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h index 06885ad972..7d0162938d 100644 --- a/src/corelib/json/qjson_p.h +++ b/src/corelib/json/qjson_p.h @@ -60,8 +60,10 @@ #include <qatomic.h> #include <qstring.h> #include <qendian.h> +#include <qnumeric.h> #include <limits.h> +#include <limits> QT_BEGIN_NAMESPACE diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp index 3fbc811948..3aba6124b8 100644 --- a/src/corelib/json/qjsonvalue.cpp +++ b/src/corelib/json/qjsonvalue.cpp @@ -156,6 +156,18 @@ QJsonValue::QJsonValue(int n) } /*! + \overload + Creates a value of type Double, with value \a n. + NOTE: the integer limits for IEEE 754 double precision data is 2^53 (-9007199254740992 to +9007199254740992). + If you pass in values outside this range expect a loss of precision to occur. + */ +QJsonValue::QJsonValue(qint64 n) + : d(0), t(Double) +{ + this->dbl = n; +} + +/*! Creates a value of type String, with value \a s. */ QJsonValue::QJsonValue(const QString &s) diff --git a/src/corelib/json/qjsonvalue.h b/src/corelib/json/qjsonvalue.h index b8bdf55aa3..c8efab5d5f 100644 --- a/src/corelib/json/qjsonvalue.h +++ b/src/corelib/json/qjsonvalue.h @@ -79,6 +79,7 @@ public: QJsonValue(bool b); QJsonValue(double n); QJsonValue(int n); + QJsonValue(qint64 n); QJsonValue(const QString &s); QJsonValue(QLatin1String s); QJsonValue(const QJsonArray &a); diff --git a/src/corelib/json/qjsonwriter.cpp b/src/corelib/json/qjsonwriter.cpp index 3ac16c6fd1..8426b351f6 100644 --- a/src/corelib/json/qjsonwriter.cpp +++ b/src/corelib/json/qjsonwriter.cpp @@ -169,9 +169,14 @@ static void valueToJson(const QJsonPrivate::Base *b, const QJsonPrivate::Value & case QJsonValue::Bool: json += v.toBoolean() ? "true" : "false"; break; - case QJsonValue::Double: - json += QByteArray::number(v.toDouble(b), 'g', 17); + case QJsonValue::Double: { + const double d = v.toDouble(b); + if (qIsFinite(d)) // +2 to format to ensure the expected precision + json += QByteArray::number(d, 'g', std::numeric_limits<double>::digits10 + 2); // ::digits10 is 15 + else + json += "null"; // +INF || -INF || NaN (see RFC4627#section2.4) break; + } case QJsonValue::String: json += '"'; json += escapedString(v.toString(b)); diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index f0899c6dee..fa911fb967 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -75,6 +75,12 @@ #include "qstring.h" +#if defined( __OBJC__) && defined(QT_NAMESPACE) +#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__) +#else +#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) +#endif + QT_BEGIN_NAMESPACE /* diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index a7b14b22b5..3460b9e228 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1950,7 +1950,6 @@ QString QCoreApplication::applicationFilePath() char buff[maximum_path+1]; if (_cmdname(buff)) { d->cachedApplicationFilePath = QDir::cleanPath(QString::fromLocal8Bit(buff)); - return d->cachedApplicationFilePath; } else { qWarning("QCoreApplication::applicationFilePath: _cmdname() failed"); // _cmdname() won't fail, but just in case, fallback to the old method @@ -1959,11 +1958,11 @@ QString QCoreApplication::applicationFilePath() if (!executables.empty()) { //We assume that there is only one executable in the folder d->cachedApplicationFilePath = dir.absoluteFilePath(executables.first()); - return d->cachedApplicationFilePath; } else { - return QString(); + d->cachedApplicationFilePath = QString(); } } + return d->cachedApplicationFilePath; #elif defined(Q_OS_MAC) QString qAppFileName_str = qAppFileName(); if(!qAppFileName_str.isEmpty()) { @@ -1982,34 +1981,38 @@ QString QCoreApplication::applicationFilePath() return d->cachedApplicationFilePath; } # endif + if (!arguments().isEmpty()) { + QString argv0 = QFile::decodeName(arguments().at(0).toLocal8Bit()); + QString absPath; + + if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) { + /* + If argv0 starts with a slash, it is already an absolute + file path. + */ + absPath = argv0; + } else if (argv0.contains(QLatin1Char('/'))) { + /* + If argv0 contains one or more slashes, it is a file path + relative to the current directory. + */ + absPath = QDir::current().absoluteFilePath(argv0); + } else { + /* + Otherwise, the file path has to be determined using the + PATH environment variable. + */ + absPath = QStandardPaths::findExecutable(argv0); + } + + absPath = QDir::cleanPath(absPath); - QString argv0 = QFile::decodeName(arguments().at(0).toLocal8Bit()); - QString absPath; - - if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) { - /* - If argv0 starts with a slash, it is already an absolute - file path. - */ - absPath = argv0; - } else if (argv0.contains(QLatin1Char('/'))) { - /* - If argv0 contains one or more slashes, it is a file path - relative to the current directory. - */ - absPath = QDir::current().absoluteFilePath(argv0); + QFileInfo fi(absPath); + d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString(); } else { - /* - Otherwise, the file path has to be determined using the - PATH environment variable. - */ - absPath = QStandardPaths::findExecutable(argv0); + d->cachedApplicationFilePath = QString(); } - absPath = QDir::cleanPath(absPath); - - QFileInfo fi(absPath); - d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString(); return d->cachedApplicationFilePath; #endif } diff --git a/src/corelib/kernel/qeventdispatcher_blackberry.cpp b/src/corelib/kernel/qeventdispatcher_blackberry.cpp index f90f2e3268..d9e38b68b2 100644 --- a/src/corelib/kernel/qeventdispatcher_blackberry.cpp +++ b/src/corelib/kernel/qeventdispatcher_blackberry.cpp @@ -128,16 +128,16 @@ static int bpsIOHandler(int fd, int io_events, void *data) // create unblock event bps_event_t *event; int result = bps_event_create(&event, bpsUnblockDomain, 0, NULL, NULL); - if (result != BPS_SUCCESS) { - qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_event_create() failed"); + if (Q_UNLIKELY(result != BPS_SUCCESS)) { + qWarning("QEventDispatcherBlackberry: bps_event_create failed"); return BPS_FAILURE; } // post unblock event to our thread; in this callback the bps channel is // guaranteed to be the same that was active when bps_add_fd was called result = bps_push_event(event); - if (result != BPS_SUCCESS) { - qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_push_event() failed"); + if (Q_UNLIKELY(result != BPS_SUCCESS)) { + qWarning("QEventDispatcherBlackberry: bps_push_event failed"); bps_event_destroy(event); return BPS_FAILURE; } @@ -151,16 +151,16 @@ QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberryPrivate() { // prepare to use BPS int result = bps_initialize(); - if (result != BPS_SUCCESS) - qFatal("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_initialize() failed"); + if (Q_UNLIKELY(result != BPS_SUCCESS)) + qFatal("QEventDispatcherBlackberry: bps_initialize failed"); bps_channel = bps_channel_get_active(); // get domain for IO ready and wake up events - ignoring race condition here for now if (bpsUnblockDomain == -1) { bpsUnblockDomain = bps_register_domain(); - if (bpsUnblockDomain == -1) - qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_register_domain() failed"); + if (Q_UNLIKELY(bpsUnblockDomain == -1)) + qWarning("QEventDispatcherBlackberry: bps_register_domain failed"); } } @@ -202,21 +202,26 @@ void QEventDispatcherBlackberry::registerSocketNotifier(QSocketNotifier *notifie Q_ASSERT(notifier); Q_D(QEventDispatcherBlackberry); - BpsChannelScopeSwitcher channelSwitcher(d->bps_channel); - - // Register the fd with bps int sockfd = notifier->socket(); int type = notifier->type(); - qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd; - int io_events = ioEvents(sockfd); + qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd; - if (io_events) - bps_remove_fd(sockfd); + if (Q_UNLIKELY(sockfd >= FD_SETSIZE)) { + qWarning() << "QEventDispatcherBlackberry: cannot register QSocketNotifier (fd too high)" + << sockfd; + return; + } // Call the base Unix implementation. Needed to allow select() to be called correctly QEventDispatcherUNIX::registerSocketNotifier(notifier); + // Register the fd with bps + BpsChannelScopeSwitcher channelSwitcher(d->bps_channel); + int io_events = ioEvents(sockfd); + if (io_events) + bps_remove_fd(sockfd); + switch (type) { case QSocketNotifier::Read: qEventDispatcherDebug << "Registering" << sockfd << "for Reads"; @@ -233,44 +238,41 @@ void QEventDispatcherBlackberry::registerSocketNotifier(QSocketNotifier *notifie break; } - errno = 0; - int result = bps_add_fd(sockfd, io_events, &bpsIOHandler, d->ioData.data()); - - if (result != BPS_SUCCESS) - qWarning() << Q_FUNC_INFO << "bps_add_fd() failed" << strerror(errno) << "code:" << errno; + const int result = bps_add_fd(sockfd, io_events, &bpsIOHandler, d->ioData.data()); + if (Q_UNLIKELY(result != BPS_SUCCESS)) + qWarning() << "QEventDispatcherBlackberry: bps_add_fd failed"; } void QEventDispatcherBlackberry::unregisterSocketNotifier(QSocketNotifier *notifier) { Q_D(QEventDispatcherBlackberry); - BpsChannelScopeSwitcher channelSwitcher(d->bps_channel); + int sockfd = notifier->socket(); + + qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd; + + if (Q_UNLIKELY(sockfd >= FD_SETSIZE)) { + qWarning() << "QEventDispatcherBlackberry: cannot unregister QSocketNotifier" << sockfd; + return; + } // Allow the base Unix implementation to unregister the fd too QEventDispatcherUNIX::unregisterSocketNotifier(notifier); // Unregister the fd with bps - int sockfd = notifier->socket(); - qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd; - + BpsChannelScopeSwitcher channelSwitcher(d->bps_channel); const int io_events = ioEvents(sockfd); - int result = bps_remove_fd(sockfd); - if (result != BPS_SUCCESS) - qWarning() << Q_FUNC_INFO << "bps_remove_fd() failed" << sockfd; - + if (Q_UNLIKELY(result != BPS_SUCCESS)) + qWarning() << "QEventDispatcherBlackberry: bps_remove_fd failed" << sockfd; - /* if no other socket notifier is - * watching sockfd, our job ends here - */ + // if no other socket notifier is watching sockfd, our job ends here if (!io_events) return; - errno = 0; result = bps_add_fd(sockfd, io_events, &bpsIOHandler, d->ioData.data()); - if (result != BPS_SUCCESS) { - qWarning() << Q_FUNC_INFO << "bps_add_fd() failed" << strerror(errno) << "code:" << errno; - } + if (Q_UNLIKELY(result != BPS_SUCCESS)) + qWarning("QEventDispatcherBlackberry: bps_add_fd error"); } static inline int timespecToMillisecs(const timespec &tv) @@ -358,8 +360,8 @@ int QEventDispatcherBlackberry::select(int nfds, fd_set *readfds, fd_set *writef // Wait for event or file to be ready const int result = bps_get_event(&event, timeoutLeft); - if (result != BPS_SUCCESS) - qWarning("QEventDispatcherBlackberry::select: bps_get_event() failed"); + if (Q_UNLIKELY(result != BPS_SUCCESS)) + qWarning("QEventDispatcherBlackberry: bps_get_event failed"); } if (!event) // In case of !event, we break out of the loop to let Qt process the timers @@ -392,13 +394,13 @@ void QEventDispatcherBlackberry::wakeUp() Q_D(QEventDispatcherBlackberry); if (d->wakeUps.testAndSetAcquire(0, 1)) { bps_event_t *event; - if (bps_event_create(&event, bpsUnblockDomain, 0, 0, 0) == BPS_SUCCESS) { - if (bps_channel_push_event(d->bps_channel, event) == BPS_SUCCESS) + if (Q_LIKELY(bps_event_create(&event, bpsUnblockDomain, 0, 0, 0) == BPS_SUCCESS)) { + if (Q_LIKELY(bps_channel_push_event(d->bps_channel, event) == BPS_SUCCESS)) return; else bps_event_destroy(event); } - qWarning("QEventDispatcherBlackberryPrivate::wakeUp failed"); + qWarning("QEventDispatcherBlackberry: wakeUp failed"); } } diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 50f3a1814b..586d6cf29f 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -421,6 +421,56 @@ public: int alias; }; +template<typename T, typename Key> +class QMetaTypeFunctionRegistry +{ +public: + ~QMetaTypeFunctionRegistry() + { + const QWriteLocker locker(&lock); + map.clear(); + } + + bool contains(Key k) const + { + const QReadLocker locker(&lock); + return map.contains(k); + } + + bool insertIfNotContains(Key k, const T *f) + { + const QWriteLocker locker(&lock); + const T* &fun = map[k]; + if (fun != 0) + return false; + fun = f; + return true; + } + + const T *function(Key k) const + { + const QReadLocker locker(&lock); + return map.value(k, 0); + } + + void remove(int from, int to) + { + const Key k(from, to); + const QWriteLocker locker(&lock); + map.remove(k); + } +private: + mutable QReadWriteLock lock; + QHash<Key, const T *> map; +}; + +typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> > +QMetaTypeConverterRegistry; +typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractComparatorFunction,int> +QMetaTypeComparatorRegistry; +typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int> +QMetaTypeDebugStreamRegistry; + namespace { union CheckThatItIsPod @@ -432,6 +482,198 @@ union CheckThatItIsPod Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE); Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes) Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock) +Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry) +Q_GLOBAL_STATIC(QMetaTypeComparatorRegistry, customTypesComparatorRegistry) +Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry) + +/*! + \fn bool QMetaType::registerConverter() + \since 5.2 + Registers the possibility of an implicit conversion from type From to type To in the meta + type system. Returns true if the registration succeeded, otherwise false. +*/ + +/*! + \fn bool QMetaType::registerConverter(MemberFunction function) + \since 5.2 + \overload + Registers a method \a function like To From::function() const as converter from type From + to type To in the meta type system. Returns true if the registration succeeded, otherwise false. +*/ + +/*! + \fn bool QMetaType::registerConverter(MemberFunctionOk function) + \since 5.2 + \overload + Registers a method \a function like To From::function(bool *ok) const as converter from type From + to type To in the meta type system. Returns true if the registration succeeded, otherwise false. +*/ + +/*! + \fn bool QMetaType::registerConverter(UnaryFunction function) + \since 5.2 + \overload + Registers a unary function object \a function as converter from type From + to type To in the meta type system. Returns true if the registration succeeded, otherwise false. +*/ + +/*! + \fn bool QMetaType::registerComparators() + \since 5.2 + Registers comparison operetarors for the user-registered type T. This requires T to have + both an operator== and an operator<. + Returns true if the registration succeeded, otherwise false. +*/ + +#ifndef QT_NO_DEBUG_STREAM +/*! + \fn bool QMetaType::registerDebugStreamOperator() + Registers the debug stream operator for the user-registered type T. This requires T to have + an operator<<(QDebug dbg, T). + Returns true if the registration succeeded, otherwise false. +*/ +#endif + +/*! + Registers function \a f as converter function from type id \a from to \a to. + If there's already a conversion registered, this does nothing but deleting \a f. + Returns true if the registration succeeded, otherwise false. + \since 5.2 + \internal +*/ +bool QMetaType::registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to) +{ + if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) { + qWarning("Type conversion already registered from type %s to type %s", + QMetaType::typeName(from), QMetaType::typeName(to)); + return false; + } + return true; +} + +/*! + \internal + + Invoked automatically when a converter function object is destroyed. + */ +void QMetaType::unregisterConverterFunction(int from, int to) +{ + customTypesConversionRegistry()->remove(from, to); +} + +bool QMetaType::registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type) +{ + if (!customTypesComparatorRegistry()->insertIfNotContains(type, f)) { + qWarning("Comparators already registered for type %s", QMetaType::typeName(type)); + return false; + } + return true; +} + +/*! + \fn bool QMetaType::hasRegisteredComparators() + Returns true, if the meta type system has registered comparators for type T. + \since 5.2 + */ + +/*! + Returns true, if the meta type system has registered comparators for type id \a typeId. + \since 5.2 + */ +bool QMetaType::hasRegisteredComparators(int typeId) +{ + return customTypesComparatorRegistry()->contains(typeId); +} + +#ifndef QT_NO_DEBUG_STREAM +bool QMetaType::registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, + int type) +{ + if (!customTypesDebugStreamRegistry()->insertIfNotContains(type, f)) { + qWarning("Debug stream operator already registered for type %s", QMetaType::typeName(type)); + return false; + } + return true; +} + +/*! + \fn bool QMetaType::hasRegisteredDebugStreamOperator() + Returns true, if the meta type system has a registered debug stream operator for type T. + \since 5.2 + */ + +/*! + Returns true, if the meta type system has a registered debug stream operator for type + id \a typeId. + \since 5.2 +*/ +bool QMetaType::hasRegisteredDebugStreamOperator(int typeId) +{ + return customTypesDebugStreamRegistry()->contains(typeId); +} +#endif + +/*! + Converts the object at \a from from \a fromTypeId to the preallocated space at \a to + typed \a toTypeId. Returns true, if the conversion succeeded, otherwise false. + \since 5.2 +*/ +bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId) +{ + const QtPrivate::AbstractConverterFunction * const f = + customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); + return f && f->convert(f, from, to); +} + +/*! + Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId. + \a result is set to less than, equal to or greater than zero, if \a lhs is less than, equal to + or greater than \a rhs. Returns true, if the comparison succeeded, otherwiess false. + \since 5.2 +*/ +bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* result) +{ + const QtPrivate::AbstractComparatorFunction * const f = + customTypesComparatorRegistry()->function(typeId); + if (!f) + return false; + if (f->equals(f, lhs, rhs)) + *result = 0; + else + *result = f->lessThan(f, lhs, rhs) ? -1 : 1; + return true; +} + +/*! + Streams the object at \a rhs of type \a typeId to the debug stream \a dbg. Returns true + on success, otherwise false. + \since 5.2 +*/ +bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId) +{ + const QtPrivate::AbstractDebugStreamFunction * const f = customTypesDebugStreamRegistry()->function(typeId); + if (!f) + return false; + f->stream(f, dbg, rhs); + return true; +} + +/*! + \fn bool QMetaType::hasRegisteredConverterFunction() + Returns true, if the meta type system has a registered conversion from type From to type To. + \since 5.2 + \overload + */ + +/*! + Returns true, if the meta type system has a registered conversion from meta type id \a fromTypeId + to \a toTypeId + \since 5.2 +*/ +bool QMetaType::hasRegisteredConverterFunction(int fromTypeId, int toTypeId) +{ + return customTypesConversionRegistry()->contains(qMakePair(fromTypeId, toTypeId)); +} #ifndef QT_NO_DATASTREAM /*! @@ -723,11 +965,11 @@ int QMetaType::registerNormalizedTypedef(const NS(QByteArray) &normalizedTypeNam } if (idx != aliasId) { - qFatal("QMetaType::registerTypedef: Binary compatibility break " - "-- Type name '%s' previously registered as typedef of '%s' [%i], " - "now registering as typedef of '%s' [%i].", - normalizedTypeName.constData(), QMetaType::typeName(idx), idx, - QMetaType::typeName(aliasId), aliasId); + qWarning("QMetaType::registerTypedef: " + "-- Type name '%s' previously registered as typedef of '%s' [%i], " + "now registering as typedef of '%s' [%i].", + normalizedTypeName.constData(), QMetaType::typeName(idx), idx, + QMetaType::typeName(aliasId), aliasId); } return idx; } @@ -1841,6 +2083,37 @@ const QMetaObject *QMetaType::metaObjectForType(int type) \sa Q_DECLARE_METATYPE(), QMetaType::type() */ +/*! + \fn bool qRegisterSequentialConverter() + \relates QMetaType + \since 5.2 + + Registers a sequential container so that it can be converted to + a QVariantList. If compilation fails, then you probably forgot to + Q_DECLARE_METATYPE the value type. + + Note that it is not necessary to call this method for Qt containers (QList, + QVector etc) or for std::vector or std::list. Such containers are automatically + registered by Qt. + + \sa QVariant::canConvert() +*/ + +/*! + \fn bool qRegisterAssociativeConverter() + \relates QMetaType + \since 5.2 + + Registers an associative container so that it can be converted to + a QVariantHash or QVariantMap. If the key_type and mapped_type of the container + was not declared with Q_DECLARE_METATYPE(), compilation will fail. + + Note that it is not necessary to call this method for Qt containers (QHash, + QMap etc) or for std::map. Such containers are automatically registered by Qt. + + \sa QVariant::canConvert() +*/ + namespace { class TypeInfo { template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 5763bcc07b..005199080d 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -47,17 +47,27 @@ #include <QtCore/qbytearray.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qisenum.h> +#include <QtCore/qtypetraits.h> #ifndef QT_NO_QOBJECT #include <QtCore/qobjectdefs.h> #endif #include <new> +#include <vector> +#include <list> +#include <map> + #ifdef Bool #error qmetatype.h must be included before any header file that defines Bool #endif QT_BEGIN_NAMESPACE +template <typename T> +struct QMetaTypeId2; + +template <typename T> +inline Q_DECL_CONSTEXPR int qMetaTypeId(); // F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType) #define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\ @@ -183,10 +193,183 @@ QT_BEGIN_NAMESPACE #define QT_DEFINE_METATYPE_ID(TypeName, Id, Name) \ TypeName = Id, +#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \ + F(QList) \ + F(QVector) \ + F(QQueue) \ + F(QStack) \ + F(QSet) \ + F(QLinkedList) + +#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \ + F(QHash, class) \ + F(QMap, class) \ + F(QPair, struct) + class QDataStream; class QMetaTypeInterface; struct QMetaObject; +namespace QtPrivate +{ +/*! + This template is used for implicit conversion from type From to type To. + \internal +*/ +template<typename From, typename To> +To convertImplicit(const From& from) +{ + return from; +} + +#ifndef QT_NO_DEBUG_STREAM +struct AbstractDebugStreamFunction +{ + typedef void (*Stream)(const AbstractDebugStreamFunction *, QDebug&, const void *); + typedef void (*Destroy)(AbstractDebugStreamFunction *); + explicit AbstractDebugStreamFunction(Stream s = 0, Destroy d = 0) + : stream(s), destroy(d) {} + Q_DISABLE_COPY(AbstractDebugStreamFunction) + Stream stream; + Destroy destroy; +}; + +template<typename T> +struct BuiltInDebugStreamFunction : public AbstractDebugStreamFunction +{ + BuiltInDebugStreamFunction() + : AbstractDebugStreamFunction(stream, destroy) {} + static void stream(const AbstractDebugStreamFunction *, QDebug& dbg, const void *r) + { + const T *rhs = static_cast<const T *>(r); + operator<<(dbg, *rhs); + } + + static void destroy(AbstractDebugStreamFunction *_this) + { + delete static_cast<BuiltInDebugStreamFunction *>(_this); + } +}; +#endif + +struct AbstractComparatorFunction +{ + typedef bool (*LessThan)(const AbstractComparatorFunction *, const void *, const void *); + typedef bool (*Equals)(const AbstractComparatorFunction *, const void *, const void *); + typedef void (*Destroy)(AbstractComparatorFunction *); + explicit AbstractComparatorFunction(LessThan lt = 0, Equals e = 0, Destroy d = 0) + : lessThan(lt), equals(e), destroy(d) {} + Q_DISABLE_COPY(AbstractComparatorFunction) + LessThan lessThan; + Equals equals; + Destroy destroy; +}; + +template<typename T> +struct BuiltInComparatorFunction : public AbstractComparatorFunction +{ + BuiltInComparatorFunction() + : AbstractComparatorFunction(lessThan, equals, destroy) {} + static bool lessThan(const AbstractComparatorFunction *, const void *l, const void *r) + { + const T *lhs = static_cast<const T *>(l); + const T *rhs = static_cast<const T *>(r); + return *lhs < *rhs; + } + + static bool equals(const AbstractComparatorFunction *, const void *l, const void *r) + { + const T *lhs = static_cast<const T *>(l); + const T *rhs = static_cast<const T *>(r); + return *lhs == *rhs; + } + + static void destroy(AbstractComparatorFunction *_this) + { + delete static_cast<BuiltInComparatorFunction *>(_this); + } +}; + +struct AbstractConverterFunction +{ + typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*); + explicit AbstractConverterFunction(Converter c = 0) + : convert(c) {} + Q_DISABLE_COPY(AbstractConverterFunction) + Converter convert; +}; + +template<typename From, typename To> +struct ConverterMemberFunction : public AbstractConverterFunction +{ + explicit ConverterMemberFunction(To(From::*function)() const) + : AbstractConverterFunction(convert), + m_function(function) {} + ~ConverterMemberFunction(); + static bool convert(const AbstractConverterFunction *_this, const void *in, void *out) + { + const From *f = static_cast<const From *>(in); + To *t = static_cast<To *>(out); + const ConverterMemberFunction *_typedThis = + static_cast<const ConverterMemberFunction *>(_this); + *t = (f->*_typedThis->m_function)(); + return true; + } + + To(From::* const m_function)() const; +}; + +template<typename From, typename To> +struct ConverterMemberFunctionOk : public AbstractConverterFunction +{ + explicit ConverterMemberFunctionOk(To(From::*function)(bool *) const) + : AbstractConverterFunction(convert), + m_function(function) {} + ~ConverterMemberFunctionOk(); + static bool convert(const AbstractConverterFunction *_this, const void *in, void *out) + { + const From *f = static_cast<const From *>(in); + To *t = static_cast<To *>(out); + bool ok = false; + const ConverterMemberFunctionOk *_typedThis = + static_cast<const ConverterMemberFunctionOk *>(_this); + *t = (f->*_typedThis->m_function)(&ok); + if (!ok) + *t = To(); + return ok; + } + + To(From::* const m_function)(bool*) const; +}; + +template<typename From, typename To, typename UnaryFunction> +struct ConverterFunctor : public AbstractConverterFunction +{ + explicit ConverterFunctor(UnaryFunction function) + : AbstractConverterFunction(convert), + m_function(function) {} + ~ConverterFunctor(); + static bool convert(const AbstractConverterFunction *_this, const void *in, void *out) + { + const From *f = static_cast<const From *>(in); + To *t = static_cast<To *>(out); + const ConverterFunctor *_typedThis = + static_cast<const ConverterFunctor *>(_this); + *t = _typedThis->m_function(*f); + return true; + } + + UnaryFunction m_function; +}; + + template<typename T, bool> + struct ValueTypeIsMetaType; + template<typename T, bool> + struct AssociativeValueTypeIsMetaType; + template<typename T, bool> + struct IsMetaTypePair; +} + class Q_CORE_EXPORT QMetaType { enum ExtensionFlag { NoExtensionFlags, CreateEx = 0x1, DestroyEx = 0x2, @@ -320,6 +503,109 @@ public: inline void destroy(void *data) const; inline void *construct(void *where, const void *copy = 0) const; inline void destruct(void *data) const; + +public: + template<typename T> + static bool registerComparators() + { + Q_STATIC_ASSERT_X((!QMetaTypeId2<T>::IsBuiltIn), + "QMetaType::registerComparators: The type must be a custom type."); + + const int typeId = qMetaTypeId<T>(); + static const QtPrivate::BuiltInComparatorFunction<T> f; + return registerComparatorFunction( &f, typeId); + } + template<typename T> + static bool hasRegisteredComparators() + { + return hasRegisteredComparators(qMetaTypeId<T>()); + } + static bool hasRegisteredComparators(int typeId); + + +#ifndef QT_NO_DEBUG_STREAM + template<typename T> + static bool registerDebugStreamOperator() + { + Q_STATIC_ASSERT_X((!QMetaTypeId2<T>::IsBuiltIn), + "QMetaType::registerDebugStreamOperator: The type must be a custom type."); + + const int typeId = qMetaTypeId<T>(); + static const QtPrivate::BuiltInDebugStreamFunction<T> f; + return registerDebugStreamOperatorFunction(&f, typeId); + } + template<typename T> + static bool hasRegisteredDebugStreamOperator() + { + return hasRegisteredDebugStreamOperator(qMetaTypeId<T>()); + } + static bool hasRegisteredDebugStreamOperator(int typeId); +#endif + + // implicit conversion supported like double -> float + template<typename From, typename To> + static bool registerConverter() + { + return registerConverter<From, To>(QtPrivate::convertImplicit<From, To>); + } + +#ifdef Q_QDOC + static bool registerConverter(MemberFunction function); + static bool registerConverter(MemberFunctionOk function); + static bool registerConverter(UnaryFunction function); +#else + // member function as in "QString QFont::toString() const" + template<typename From, typename To> + static bool registerConverter(To(From::*function)() const) + { + Q_STATIC_ASSERT_X((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn), + "QMetaType::registerConverter: At least one of the types must be a custom type."); + + const int fromTypeId = qMetaTypeId<From>(); + const int toTypeId = qMetaTypeId<To>(); + static const QtPrivate::ConverterMemberFunction<From, To> f(function); + return registerConverterFunction(&f, fromTypeId, toTypeId); + } + + // member function as in "double QString::toDouble(bool *ok = 0) const" + template<typename From, typename To> + static bool registerConverter(To(From::*function)(bool*) const) + { + Q_STATIC_ASSERT_X((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn), + "QMetaType::registerConverter: At least one of the types must be a custom type."); + + const int fromTypeId = qMetaTypeId<From>(); + const int toTypeId = qMetaTypeId<To>(); + static const QtPrivate::ConverterMemberFunctionOk<From, To> f(function); + return registerConverterFunction(&f, fromTypeId, toTypeId); + } + + // functor or function pointer + template<typename From, typename To, typename UnaryFunction> + static bool registerConverter(UnaryFunction function) + { + Q_STATIC_ASSERT_X((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn), + "QMetaType::registerConverter: At least one of the types must be a custom type."); + + const int fromTypeId = qMetaTypeId<From>(); + const int toTypeId = qMetaTypeId<To>(); + static const QtPrivate::ConverterFunctor<From, To, UnaryFunction> f(function); + return registerConverterFunction(&f, fromTypeId, toTypeId); + } +#endif + + static bool convert(const void *from, int fromTypeId, void *to, int toTypeId); + static bool compare(const void *lhs, const void *rhs, int typeId, int* result); + static bool debugStream(QDebug& dbg, const void *rhs, int typeId); + + template<typename From, typename To> + static bool hasRegisteredConverterFunction() + { + return hasRegisteredConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>()); + } + + static bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId); + private: static QMetaType typeInfo(const int type); inline QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info, @@ -348,6 +634,31 @@ private: void *constructExtended(void *where, const void *copy = 0) const; void destructExtended(void *data) const; + static bool registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type); +#ifndef QT_NO_DEBUG_STREAM + static bool registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, int type); +#endif + +#ifndef Q_NO_TEMPLATE_FRIENDS +#ifndef Q_QDOC + template<typename T> + friend bool qRegisterSequentialConverter(); + template<typename, bool> friend struct QtPrivate::ValueTypeIsMetaType; + template<typename, typename> friend struct QtPrivate::ConverterMemberFunction; + template<typename, typename> friend struct QtPrivate::ConverterMemberFunctionOk; + template<typename, typename, typename> friend struct QtPrivate::ConverterFunctor; + template<typename T> + friend bool qRegisterAssociativeConverter(); + template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType; + template<typename, bool> friend struct QtPrivate::IsMetaTypePair; +#endif +#else +public: +#endif + static bool registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to); + static void unregisterConverterFunction(int from, int to); +private: + Creator m_creator; Deleter m_deleter; SaveOperator m_saveOp; @@ -366,6 +677,26 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags) +namespace QtPrivate { + +template<typename From, typename To> +ConverterMemberFunction<From, To>::~ConverterMemberFunction() +{ + QMetaType::unregisterConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>()); +} +template<typename From, typename To> +ConverterMemberFunctionOk<From, To>::~ConverterMemberFunctionOk() +{ + QMetaType::unregisterConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>()); +} +template<typename From, typename To, typename UnaryFunction> +ConverterFunctor<From, To, UnaryFunction>::~ConverterFunctor() +{ + QMetaType::unregisterConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>()); +} + +} + namespace QtMetaTypePrivate { template <typename T, bool Accepted = true> struct QMetaTypeFunctionHelper { @@ -421,6 +752,484 @@ template <> struct QMetaTypeFunctionHelper<void, /* Accepted */ true> : public QMetaTypeFunctionHelper<void, /* Accepted */ false> {}; + +struct VariantData +{ + VariantData(const int metaTypeId_, + const void *data_, + const uint flags_) + : metaTypeId(metaTypeId_) + , data(data_) + , flags(flags_) + { + } + const int metaTypeId; + const void *data; + const uint flags; +}; + +template<typename const_iterator> +struct IteratorOwner +{ + static void assign(void **ptr, const_iterator iterator) + { + *ptr = new const_iterator(iterator); + } + + static void advance(void **iterator, int step) + { + const_iterator &it = *static_cast<const_iterator*>(*iterator); + std::advance(it, step); + } + + static void destroy(void **ptr) + { + delete static_cast<const_iterator*>(*ptr); + } + + static const void *getData(void * const *iterator) + { + return &**static_cast<const_iterator*>(*iterator); + } + + static const void *getData(const_iterator it) + { + return &*it; + } +}; +template<typename const_iterator> +struct IteratorOwner<const const_iterator*> +{ + static void assign(void **ptr, const const_iterator *iterator ) + { + *ptr = const_cast<const_iterator*>(iterator); + } + + static void advance(void **iterator, int step) + { + const_iterator *it = static_cast<const_iterator*>(*iterator); + std::advance(it, step); + *iterator = it; + } + + static void destroy(void **) + { + } + + static const void *getData(void * const *iterator) + { + return *iterator; + } + + static const void *getData(const const_iterator *it) + { + return it; + } +}; + +enum IteratorCapability +{ + ForwardCapability = 1, + BiDirectionalCapability = 2, + RandomAccessCapability = 4 +}; + +template<typename T, typename Category = typename std::iterator_traits<typename T::const_iterator>::iterator_category> +struct CapabilitiesImpl; + +template<typename T> +struct CapabilitiesImpl<T, std::forward_iterator_tag> +{ enum { IteratorCapabilities = ForwardCapability }; }; +template<typename T> +struct CapabilitiesImpl<T, std::bidirectional_iterator_tag> +{ enum { IteratorCapabilities = BiDirectionalCapability | ForwardCapability }; }; +template<typename T> +struct CapabilitiesImpl<T, std::random_access_iterator_tag> +{ enum { IteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability }; }; + +template<typename T> +struct ContainerAPI : CapabilitiesImpl<T> +{ + static int size(const T *t) { return std::distance(t->begin(), t->end()); } +}; + +template<typename T> +struct ContainerAPI<QList<T> > : CapabilitiesImpl<QList<T> > +{ static int size(const QList<T> *t) { return t->size(); } }; + +template<typename T> +struct ContainerAPI<QVector<T> > : CapabilitiesImpl<QVector<T> > +{ static int size(const QVector<T> *t) { return t->size(); } }; + +template<typename T> +struct ContainerAPI<std::vector<T> > : CapabilitiesImpl<std::vector<T> > +{ static int size(const std::vector<T> *t) { return t->size(); } }; + +template<typename T> +struct ContainerAPI<std::list<T> > : CapabilitiesImpl<std::list<T> > +{ static int size(const std::list<T> *t) { return t->size(); } }; + +class QSequentialIterableImpl +{ +public: + const void * _iterable; + void *_iterator; + int _metaType_id; + uint _metaType_flags; + uint _iteratorCapabilities; + typedef int(*sizeFunc)(const void *p); + typedef const void * (*atFunc)(const void *p, int); + typedef void (*moveIteratorFunc)(const void *p, void **); + typedef void (*advanceFunc)(void **p, int); + typedef VariantData (*getFunc)( void * const *p, int metaTypeId, uint flags); + typedef void (*destroyIterFunc)(void **p); + typedef bool (*equalIterFunc)(void * const *p, void * const *other); + + sizeFunc _size; + atFunc _at; + moveIteratorFunc _moveToBegin; + moveIteratorFunc _moveToEnd; + advanceFunc _advance; + getFunc _get; + destroyIterFunc _destroyIter; + equalIterFunc _equalIter; + + template<class T> + static int sizeImpl(const void *p) + { return ContainerAPI<T>::size(static_cast<const T*>(p)); } + + template<class T> + static const void* atImpl(const void *p, int idx) + { + typename T::const_iterator i = static_cast<const T*>(p)->begin(); + std::advance(i, idx); + return IteratorOwner<typename T::const_iterator>::getData(i); + } + + template<class T> + static void advanceImpl(void **p, int step) + { IteratorOwner<typename T::const_iterator>::advance(p, step); } + + template<class T> + static void moveToBeginImpl(const void *container, void **iterator) + { IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->begin()); } + + template<class T> + static void moveToEndImpl(const void *container, void **iterator) + { IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->end()); } + + template<class T> + static void destroyIterImpl(void **iterator) + { IteratorOwner<typename T::const_iterator>::destroy(iterator); } + + template<class T> + static bool equalIterImpl(void * const *iterator, void * const *other) + { return *static_cast<typename T::const_iterator*>(*iterator) == *static_cast<typename T::const_iterator*>(*other); } + + template<class T> + static VariantData getImpl(void * const *iterator, int metaTypeId, uint flags) + { return VariantData(metaTypeId, IteratorOwner<typename T::const_iterator>::getData(iterator), flags); } + +public: + template<class T> QSequentialIterableImpl(const T*p) + : _iterable(p) + , _iterator(0) + , _metaType_id(qMetaTypeId<typename T::value_type>()) + , _metaType_flags(QTypeInfo<typename T::value_type>::isPointer) + , _iteratorCapabilities(ContainerAPI<T>::IteratorCapabilities) + , _size(sizeImpl<T>) + , _at(atImpl<T>) + , _moveToBegin(moveToBeginImpl<T>) + , _moveToEnd(moveToEndImpl<T>) + , _advance(advanceImpl<T>) + , _get(getImpl<T>) + , _destroyIter(destroyIterImpl<T>) + , _equalIter(equalIterImpl<T>) + { + } + + QSequentialIterableImpl() + : _iterable(0) + , _iterator(0) + , _metaType_id(QMetaType::UnknownType) + , _metaType_flags(0) + , _iteratorCapabilities(0) + , _size(0) + , _at(0) + , _moveToBegin(0) + , _moveToEnd(0) + , _advance(0) + , _get(0) + , _destroyIter(0) + , _equalIter(0) + { + } + + inline void moveToBegin() { _moveToBegin(_iterable, &_iterator); } + inline void moveToEnd() { _moveToEnd(_iterable, &_iterator); } + inline bool equal(const QSequentialIterableImpl&other) const { return _equalIter(&_iterator, &other._iterator); } + inline QSequentialIterableImpl &advance(int i) { + Q_ASSERT(i > 0 || _iteratorCapabilities & BiDirectionalCapability); + _advance(&_iterator, i); + return *this; + } + + inline VariantData getCurrent() const { return _get(&_iterator, _metaType_id, _metaType_flags); } + + VariantData at(int idx) const + { return VariantData(_metaType_id, _at(_iterable, idx), _metaType_flags); } + + int size() const { Q_ASSERT(_iterable); return _size(_iterable); } + + inline void destroyIter() { _destroyIter(&_iterator); } +}; + +template<typename From> +struct QSequentialIterableConvertFunctor +{ + QSequentialIterableConvertFunctor() {} + + QSequentialIterableImpl operator()(const From &f) const + { + return QSequentialIterableImpl(&f); + } +}; +} + +namespace QtMetaTypePrivate { +template<typename T, bool = QtPrivate::is_same<typename T::const_iterator::value_type, typename T::mapped_type>::value> +struct AssociativeContainerAccessor +{ + static const typename T::key_type& getKey(const typename T::const_iterator &it) + { + return it.key(); + } + + static const typename T::mapped_type& getValue(const typename T::const_iterator &it) + { + return it.value(); + } +}; + +template<typename T, bool = QtPrivate::is_same<typename T::const_iterator::value_type, std::pair<const typename T::key_type, typename T::mapped_type> >::value> +struct StlStyleAssociativeContainerAccessor; + +template<typename T> +struct StlStyleAssociativeContainerAccessor<T, true> +{ + static const typename T::key_type& getKey(const typename T::const_iterator &it) + { + return it->first; + } + + static const typename T::mapped_type& getValue(const typename T::const_iterator &it) + { + return it->second; + } +}; + +template<typename T> +struct AssociativeContainerAccessor<T, false> : public StlStyleAssociativeContainerAccessor<T> +{ +}; + +class QAssociativeIterableImpl +{ +public: + const void *_iterable; + void *_iterator; + int _metaType_id_key; + uint _metaType_flags_key; + int _metaType_id_value; + uint _metaType_flags_value; + typedef int(*sizeFunc)(const void *p); + typedef void (*findFunc)(const void *container, const void *p, void **iterator); + typedef void (*beginFunc)(const void *p, void **); + typedef void (*advanceFunc)(void **p, int); + typedef VariantData (*getFunc)(void * const *p, int metaTypeId, uint flags); + typedef void (*destroyIterFunc)(void **p); + typedef bool (*equalIterFunc)(void * const *p, void * const *other); + + sizeFunc _size; + findFunc _find; + beginFunc _begin; + beginFunc _end; + advanceFunc _advance; + getFunc _getKey; + getFunc _getValue; + destroyIterFunc _destroyIter; + equalIterFunc _equalIter; + + template<class T> + static int sizeImpl(const void *p) + { return std::distance(static_cast<const T*>(p)->begin(), + static_cast<const T*>(p)->end()); } + + template<class T> + static void findImpl(const void *container, const void *p, void **iterator) + { IteratorOwner<typename T::const_iterator>::assign(iterator, + static_cast<const T*>(container)->find(*static_cast<const typename T::key_type*>(p))); } + + template<class T> + static void advanceImpl(void **p, int step) + { std::advance(*static_cast<typename T::const_iterator*>(*p), step); } + + template<class T> + static void beginImpl(const void *container, void **iterator) + { IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->begin()); } + + template<class T> + static void endImpl(const void *container, void **iterator) + { IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->end()); } + + template<class T> + static VariantData getKeyImpl(void * const *iterator, int metaTypeId, uint flags) + { return VariantData(metaTypeId, &AssociativeContainerAccessor<T>::getKey(*static_cast<typename T::const_iterator*>(*iterator)), flags); } + + template<class T> + static VariantData getValueImpl(void * const *iterator, int metaTypeId, uint flags) + { return VariantData(metaTypeId, &AssociativeContainerAccessor<T>::getValue(*static_cast<typename T::const_iterator*>(*iterator)), flags); } + + template<class T> + static void destroyIterImpl(void **iterator) + { IteratorOwner<typename T::const_iterator>::destroy(iterator); } + + template<class T> + static bool equalIterImpl(void * const *iterator, void * const *other) + { return *static_cast<typename T::const_iterator*>(*iterator) == *static_cast<typename T::const_iterator*>(*other); } + +public: + template<class T> QAssociativeIterableImpl(const T*p) + : _iterable(p) + , _metaType_id_key(qMetaTypeId<typename T::key_type>()) + , _metaType_flags_key(QTypeInfo<typename T::key_type>::isPointer) + , _metaType_id_value(qMetaTypeId<typename T::mapped_type>()) + , _metaType_flags_value(QTypeInfo<typename T::mapped_type>::isPointer) + , _size(sizeImpl<T>) + , _find(findImpl<T>) + , _begin(beginImpl<T>) + , _end(endImpl<T>) + , _advance(advanceImpl<T>) + , _getKey(getKeyImpl<T>) + , _getValue(getValueImpl<T>) + , _destroyIter(destroyIterImpl<T>) + , _equalIter(equalIterImpl<T>) + { + } + + QAssociativeIterableImpl() + : _iterable(0) + , _metaType_id_key(QMetaType::UnknownType) + , _metaType_flags_key(0) + , _metaType_id_value(QMetaType::UnknownType) + , _metaType_flags_value(0) + , _size(0) + , _find(0) + , _begin(0) + , _end(0) + , _advance(0) + , _getKey(0) + , _getValue(0) + , _destroyIter(0) + , _equalIter(0) + { + } + + inline void begin() { _begin(_iterable, &_iterator); } + inline void end() { _end(_iterable, &_iterator); } + inline bool equal(const QAssociativeIterableImpl&other) const { return _equalIter(&_iterator, &other._iterator); } + inline QAssociativeIterableImpl &advance(int i) { _advance(&_iterator, i); return *this; } + + inline void destroyIter() { _destroyIter(&_iterator); } + + inline VariantData getCurrentKey() const { return _getKey(&_iterator, _metaType_id_key, _metaType_flags_value); } + inline VariantData getCurrentValue() const { return _getValue(&_iterator, _metaType_id_value, _metaType_flags_value); } + + inline void find(const VariantData &key) + { _find(_iterable, key.data, &_iterator); } + + int size() const { Q_ASSERT(_iterable); return _size(_iterable); } +}; + +template<typename From> +struct QAssociativeIterableConvertFunctor +{ + QAssociativeIterableConvertFunctor() {} + + QAssociativeIterableImpl operator()(const From& f) const + { + return QAssociativeIterableImpl(&f); + } +}; + +class QPairVariantInterfaceImpl +{ + const void *_pair; + int _metaType_id_first; + uint _metaType_flags_first; + int _metaType_id_second; + uint _metaType_flags_second; + + typedef VariantData (*getFunc)(const void * const *p, int metaTypeId, uint flags); + + getFunc _getFirst; + getFunc _getSecond; + + template<class T> + static VariantData getFirstImpl(const void * const *pair, int metaTypeId, uint flags) + { return VariantData(metaTypeId, &static_cast<const T*>(*pair)->first, flags); } + template<class T> + static VariantData getSecondImpl(const void * const *pair, int metaTypeId, uint flags) + { return VariantData(metaTypeId, &static_cast<const T*>(*pair)->second, flags); } + +public: + template<class T> QPairVariantInterfaceImpl(const T*p) + : _pair(p) + , _metaType_id_first(qMetaTypeId<typename T::first_type>()) + , _metaType_flags_first(QTypeInfo<typename T::first_type>::isPointer) + , _metaType_id_second(qMetaTypeId<typename T::second_type>()) + , _metaType_flags_second(QTypeInfo<typename T::second_type>::isPointer) + , _getFirst(getFirstImpl<T>) + , _getSecond(getSecondImpl<T>) + { + } + + QPairVariantInterfaceImpl() + : _pair(0) + , _getFirst(0) + , _getSecond(0) + { + } + + inline VariantData first() const { return _getFirst(&_pair, _metaType_id_first, _metaType_flags_first); } + inline VariantData second() const { return _getSecond(&_pair, _metaType_id_second, _metaType_flags_second); } +}; + +template<typename From> +struct QPairVariantInterfaceConvertFunctor; + +template<typename T, typename U> +struct QPairVariantInterfaceConvertFunctor<QPair<T, U> > +{ + QPairVariantInterfaceConvertFunctor() {} + + QPairVariantInterfaceImpl operator()(const QPair<T, U>& f) const + { + return QPairVariantInterfaceImpl(&f); + } +}; + +template<typename T, typename U> +struct QPairVariantInterfaceConvertFunctor<std::pair<T, U> > +{ + QPairVariantInterfaceConvertFunctor() {} + + QPairVariantInterfaceImpl operator()(const std::pair<T, U>& f) const + { + return QPairVariantInterfaceImpl(&f); + } +}; + } class QObject; @@ -509,6 +1318,176 @@ namespace QtPrivate enum { Value = true }; }; + template<typename T> + struct IsSequentialContainer + { + enum { Value = false }; + }; + +#define QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(CONTAINER) \ + template<typename T> \ + struct IsSequentialContainer<CONTAINER<T> > \ + { \ + enum { Value = true }; \ + }; + QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE) + QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(std::vector) + QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(std::list) + + template<typename T> + struct IsAssociativeContainer + { + enum { Value = false }; + }; + +#define QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(CONTAINER) \ + template<typename T, typename U> \ + struct IsAssociativeContainer<CONTAINER<T, U> > \ + { \ + enum { Value = true }; \ + }; + QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QHash) + QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QMap) + QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(std::map) + + + template<typename T, bool = QtPrivate::IsSequentialContainer<T>::Value> + struct SequentialContainerConverterHelper + { + static bool registerConverter(int) + { + return false; + } + }; + + template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined> + struct ValueTypeIsMetaType + { + static bool registerConverter(int) + { + return false; + } + }; + + template<typename T> + struct ValueTypeIsMetaType<T, true> + { + static bool registerConverter(int id) + { + const int toId = qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>(); + if (!QMetaType::hasRegisteredConverterFunction(id, toId)) { + static const QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> o; + static const QtPrivate::ConverterFunctor<T, + QtMetaTypePrivate::QSequentialIterableImpl, + QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> > f(o); + return QMetaType::registerConverterFunction(&f, id, toId); + } + return true; + } + }; + + template<typename T> + struct SequentialContainerConverterHelper<T, true> : ValueTypeIsMetaType<T> + { + }; + + template<typename T, bool = QtPrivate::IsAssociativeContainer<T>::Value> + struct AssociativeContainerConverterHelper + { + static bool registerConverter(int) + { + return false; + } + }; + + template<typename T, bool = QMetaTypeId2<typename T::mapped_type>::Defined> + struct AssociativeValueTypeIsMetaType + { + static bool registerConverter(int) + { + return false; + } + }; + + template<typename T> + struct AssociativeValueTypeIsMetaType<T, true> + { + static bool registerConverter(int id) + { + const int toId = qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>(); + if (!QMetaType::hasRegisteredConverterFunction(id, toId)) { + static const QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> o; + static const QtPrivate::ConverterFunctor<T, + QtMetaTypePrivate::QAssociativeIterableImpl, + QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> > f(o); + return QMetaType::registerConverterFunction(&f, id, toId); + } + return true; + } + }; + + template<typename T, bool = QMetaTypeId2<typename T::key_type>::Defined> + struct KeyAndValueTypeIsMetaType + { + static bool registerConverter(int) + { + return false; + } + }; + + template<typename T> + struct KeyAndValueTypeIsMetaType<T, true> : AssociativeValueTypeIsMetaType<T> + { + }; + + template<typename T> + struct AssociativeContainerConverterHelper<T, true> : KeyAndValueTypeIsMetaType<T> + { + }; + + template<typename T, bool = QMetaTypeId2<typename T::first_type>::Defined + && QMetaTypeId2<typename T::second_type>::Defined> + struct IsMetaTypePair + { + static bool registerConverter(int) + { + return false; + } + }; + + template<typename T> + struct IsMetaTypePair<T, true> + { + static bool registerConverter(int id) + { + const int toId = qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>(); + if (!QMetaType::hasRegisteredConverterFunction(id, toId)) { + static const QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o; + static const QtPrivate::ConverterFunctor<T, + QtMetaTypePrivate::QPairVariantInterfaceImpl, + QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> > f(o); + return QMetaType::registerConverterFunction(&f, id, toId); + } + return true; + } + }; + + template<typename T> + struct IsPair + { + static bool registerConverter(int) + { + return false; + } + }; + template<typename T, typename U> + struct IsPair<QPair<T, U> > : IsMetaTypePair<QPair<T, U> > {}; + template<typename T, typename U> + struct IsPair<std::pair<T, U> > : IsMetaTypePair<std::pair<T, U> > {}; + + template<typename T> + struct MetaTypePairHelper : IsPair<T> {}; + Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type); } // namespace QtPrivate @@ -546,11 +1525,16 @@ namespace QtPrivate { { return -1; } }; +#ifndef Q_COMPILER_VARIADIC_TEMPLATES // Function pointers don't derive from QObject template <class Result> struct IsPointerToTypeDerivedFromQObject<Result(*)()> { enum { Value = false }; }; template <class Result, class Arg0> struct IsPointerToTypeDerivedFromQObject<Result(*)(Arg0)> { enum { Value = false }; }; template <class Result, class Arg0, class Arg1> struct IsPointerToTypeDerivedFromQObject<Result(*)(Arg0, Arg1)> { enum { Value = false }; }; template <class Result, class Arg0, class Arg1, class Arg2> struct IsPointerToTypeDerivedFromQObject<Result(*)(Arg0, Arg1, Arg2)> { enum { Value = false }; }; +#else + template <typename Result, typename... Args> + struct IsPointerToTypeDerivedFromQObject<Result(*)(Args...)> { enum { Value = false }; }; +#endif template<typename T> struct QMetaTypeTypeFlags @@ -593,7 +1577,7 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz if (defined) flags |= QMetaType::WasDeclaredAsMetaType; - return QMetaType::registerNormalizedType(normalizedTypeName, + const int id = QMetaType::registerNormalizedType(normalizedTypeName, QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Delete, QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Create, QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct, @@ -601,6 +1585,14 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz int(sizeof(T)), flags, QtPrivate::MetaObjectForType<T>::value()); + + if (id > 0) { + QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id); + QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id); + QtPrivate::MetaTypePairHelper<T>::registerConverter(id); + } + + return id; } template <typename T> @@ -846,19 +1838,6 @@ struct QMetaTypeId< SMART_POINTER<T> > : public QMetaTypeId_ ## SMART_POINTER ## { \ }; -#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \ - F(QList) \ - F(QVector) \ - F(QQueue) \ - F(QStack) \ - F(QSet) \ - F(QLinkedList) - -#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \ - F(QHash, class) \ - F(QMap, class) \ - F(QPair, struct) - #define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F) \ F(QSharedPointer) \ F(QWeakPointer) \ @@ -872,6 +1851,9 @@ QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER) #undef Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER +Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::vector) +Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::list) + #define Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER(TEMPLATENAME, CPPTYPE) \ template <class T1, class T2> CPPTYPE TEMPLATENAME; \ Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME) @@ -880,6 +1862,9 @@ QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER) #undef Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER +Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::pair) +Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::map) + #define Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER(TEMPLATENAME) \ Q_DECLARE_SMART_POINTER_METATYPE(TEMPLATENAME) @@ -987,5 +1972,50 @@ QT_END_NAMESPACE QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE) +Q_DECLARE_METATYPE(QtMetaTypePrivate::QSequentialIterableImpl) +Q_DECLARE_METATYPE(QtMetaTypePrivate::QAssociativeIterableImpl) +Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl) + +QT_BEGIN_NAMESPACE + +#ifndef Q_QDOC +template<typename T> +#endif +bool qRegisterSequentialConverter() +{ + Q_STATIC_ASSERT_X(QMetaTypeId2<typename T::value_type>::Defined, + "The value_type of a sequential container must itself be a metatype."); + const int id = qMetaTypeId<T>(); + const int toId = qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>(); + if (QMetaType::hasRegisteredConverterFunction(id, toId)) + return true; + + static const QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> o; + static const QtPrivate::ConverterFunctor<T, + QtMetaTypePrivate::QSequentialIterableImpl, + QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> > f(o); + return QMetaType::registerConverterFunction(&f, id, toId); +} + +template<typename T> +bool qRegisterAssociativeConverter() +{ + Q_STATIC_ASSERT_X(QMetaTypeId2<typename T::key_type>::Defined + && QMetaTypeId2<typename T::mapped_type>::Defined, + "The key_type and mapped_type of an associative container must themselves be metatypes."); + + const int id = qMetaTypeId<T>(); + const int toId = qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>(); + if (QMetaType::hasRegisteredConverterFunction(id, toId)) + return true; + static const QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> o; + static const QtPrivate::ConverterFunctor<T, + QtMetaTypePrivate::QAssociativeIterableImpl, + QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> > f(o); + + return QMetaType::registerConverterFunction(&f, id, toId); +} + +QT_END_NAMESPACE #endif // QMETATYPE_H diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 33e2adf5ba..f99bcf1532 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4270,7 +4270,7 @@ void qDeleteInEventHandler(QObject *o) must not have an overloaded or templated operator(). */ -/** +/*! \internal Implementation of the template version of connect @@ -4295,12 +4295,13 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject) { - if (!sender || !signal || !slotObj || !senderMetaObject) { + if (!signal) { qWarning("QObject::connect: invalid null parameter"); if (slotObj) slotObj->destroyIfLastRef(); return QMetaObject::Connection(); } + int signal_index = -1; void *args[] = { &signal_index, signal }; for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) { @@ -4314,6 +4315,27 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa return QMetaObject::Connection(0); } signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject); + return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject); +} + +/*! + \internal + + Internal version of connect used by the template version of QObject::connect (called via connectImpl) and + also used by the QObjectPrivate::connect version used by QML. The signal_index is expected to be relative + to the number of signals. + */ +QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index, + const QObject *receiver, void **slot, + QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, + const int *types, const QMetaObject *senderMetaObject) +{ + if (!sender || !slotObj || !senderMetaObject) { + qWarning("QObject::connect: invalid null parameter"); + if (slotObj) + slotObj->destroyIfLastRef(); + return QMetaObject::Connection(); + } QObject *s = const_cast<QObject *>(sender); QObject *r = const_cast<QObject *>(receiver); @@ -4487,6 +4509,40 @@ bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot); } +/*! + \internal + Used by QML to connect a signal by index to a slot implemented in JavaScript (wrapped in a custom QSlotOBjectBase subclass). + + The signal_index is an index relative to the number of methods. + */ +QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type) +{ + if (!sender) { + qWarning("QObject::connect: invalid null parameter"); + if (slotObj) + slotObj->destroyIfLastRef(); + return QMetaObject::Connection(); + } + const QMetaObject *senderMetaObject = sender->metaObject(); + signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index); + + return QObjectPrivate::connectImpl(sender, signal_index, sender, /*slot*/0, slotObj, type, /*types*/0, senderMetaObject); +} + +/*! + \internal + Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) + In the QML case the slot is not a pointer to a pointer to the function to disconnect, but instead it is a pointer to an array of internal values + required for the disconnect. + */ +bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot) +{ + const QMetaObject *senderMetaObject = sender->metaObject(); + signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index); + + return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, sender, -1, slot); +} + /*! \class QMetaObject::Connection \inmodule QtCore Represents a handle to a signal-slot connection. diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index e849ec1599..3c43972ac9 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -207,6 +207,13 @@ public: template <typename Func1, typename Func2> static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot); + + static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, + const QObject *receiver, void **slot, + QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, + const int *types, const QMetaObject *senderMetaObject); + static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); + static bool disconnect(const QObject *sender, int signal_index, void **slot); public: ExtraData *extraData; // extra data set by the user QThreadData *threadData; // id of the thread that owns the object diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index afbe1a5ece..c489344b10 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -456,6 +456,7 @@ class Q_CORE_EXPORT QMetaObject::Connection { void *d_ptr; //QObjectPrivate::Connection* explicit Connection(void *data) : d_ptr(data) { } friend class QObject; + friend class QObjectPrivate; friend struct QMetaObject; public: ~Connection(); diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp index e0c7f171c3..6c88ed4531 100644 --- a/src/corelib/kernel/qsocketnotifier.cpp +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -181,17 +181,16 @@ QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent) : QObject(*new QSocketNotifierPrivate, parent) { Q_D(QSocketNotifier); - if (socket < 0) - qWarning("QSocketNotifier: Invalid socket specified"); d->sockfd = socket; d->sntype = type; d->snenabled = true; - if (!d->threadData->eventDispatcher.load()) { + if (socket < 0) + qWarning("QSocketNotifier: Invalid socket specified"); + else if (!d->threadData->eventDispatcher.load()) qWarning("QSocketNotifier: Can only be used with threads started with QThread"); - } else { + else d->threadData->eventDispatcher.load()->registerSocketNotifier(this); - } } /*! diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 276257ddcf..24bf25baea 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -269,6 +269,16 @@ inline bool qt_convertToBool(const QVariant::Private *const d) /*! \internal + Returns the internal data pointer from \a d. + */ + +static const void *constData(const QVariant::Private &d) +{ + return d.is_shared ? d.data.shared->ptr : reinterpret_cast<const void *>(&d.data.c); +} + +/*! + \internal Converts \a d to type \a t, which is placed in \a result. */ @@ -277,6 +287,14 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) Q_ASSERT(d->type != uint(t)); Q_ASSERT(result); + if (d->type >= QMetaType::User || t >= QMetaType::User) { + const bool isOk = QMetaType::convert(constData(*d), d->type, result, t); + if (ok) + *ok = isOk; + if (isOk) + return true; + } + bool dummy; if (!ok) ok = &dummy; @@ -867,8 +885,15 @@ static bool customCompare(const QVariant::Private *a, const QVariant::Private *b return !memcmp(a_ptr, b_ptr, QMetaType::sizeOf(a->type)); } -static bool customConvert(const QVariant::Private *, int, void *, bool *ok) +static bool customConvert(const QVariant::Private *d, int t, void *result, bool *ok) { + if (d->type >= QMetaType::User || t >= QMetaType::User) { + const bool isOk = QMetaType::convert(constData(*d), d->type, result, t); + if (ok) + *ok = isOk; + return isOk; + } + if (ok) *ok = false; return false; @@ -1958,6 +1983,12 @@ inline T qVariantToHelper(const QVariant::Private &d, const HandlersManager &han return *v_cast<T>(&d); T ret; + if (d.type >= QMetaType::User || targetType >= QMetaType::User) { + const void * const from = constData(d); + if (QMetaType::convert(from, d.type, &ret, targetType)) + return ret; + } + handlerManager[d.type]->convert(&d, targetType, &ret, 0); return ret; } @@ -2374,13 +2405,19 @@ template <typename T> inline T qNumVariantToHelper(const QVariant::Private &d, const HandlersManager &handlerManager, bool *ok, const T& val) { - uint t = qMetaTypeId<T>(); + const uint t = qMetaTypeId<T>(); if (ok) *ok = true; + if (d.type == t) return val; T ret = 0; + if ((d.type >= QMetaType::User || t >= QMetaType::User) + && QMetaType::convert(&val, d.type, &ret, t)) { + return ret; + } + if (!handlerManager[d.type]->convert(&d, t, &ret, ok) && ok) *ok = false; return ret; @@ -2735,10 +2772,52 @@ static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject) function if a qobject_cast to the type described by \a targetTypeId would succeed. Note that this only works for QObject subclasses which use the Q_OBJECT macro. - \sa convert() + A QVariant containing a sequential container will also return true for this + function if the \a targetTypeId is QVariantList. It is possible to iterate over + the contents of the container without extracting it as a (copied) QVariantList: + + \snippet code/src_corelib_kernel_qvariant.cpp 9 + + This requires that the value_type of the container is itself a metatype. + + Similarly, a QVariant containing a sequential container will also return true for this + function the \a targetTypeId is QVariantHash or QVariantMap. It is possible to iterate over + the contents of the container without extracting it as a (copied) QVariantHash or QVariantMap: + + \snippet code/src_corelib_kernel_qvariant.cpp 10 + + \sa convert(), QSequentialIterable, qRegisterSequentialConverter(), QAssociativeIterable, + qRegisterAssociativeConverter() */ bool QVariant::canConvert(int targetTypeId) const { + if (targetTypeId == QMetaType::QVariantList + && (d.type == QMetaType::QVariantList + || d.type == QMetaType::QStringList + || QMetaType::hasRegisteredConverterFunction(d.type, + qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()))) { + return true; + } + + if ((targetTypeId == QMetaType::QVariantHash || targetTypeId == QMetaType::QVariantMap) + && (d.type == QMetaType::QVariantMap + || d.type == QMetaType::QVariantHash + || QMetaType::hasRegisteredConverterFunction(d.type, + qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>()))) { + return true; + } + + if (targetTypeId == qMetaTypeId<QPair<QVariant, QVariant> >() && + QMetaType::hasRegisteredConverterFunction(d.type, + qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>())) { + return true; + } + + if ((d.type >= QMetaType::User || targetTypeId >= QMetaType::User) + && QMetaType::hasRegisteredConverterFunction(d.type, targetTypeId)) { + return true; + } + // TODO Reimplement this function, currently it works but it is a historical mess. uint currentType = ((d.type == QMetaType::Float) ? QVariant::Double : d.type); if (currentType == QMetaType::SChar || currentType == QMetaType::Char) @@ -2886,7 +2965,6 @@ bool QVariant::convert(int targetTypeId) */ bool QVariant::convert(const int type, void *ptr) const { - Q_ASSERT(type < int(QMetaType::User)); return handlerManager[type]->convert(&d, type, ptr, 0); } @@ -2908,8 +2986,9 @@ bool QVariant::convert(const int type, void *ptr) const which means that two values can be equal even if one of them is null and another is not. - \warning This function doesn't support custom types registered - with qRegisterMetaType(). + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). */ /*! \fn bool operator!=(const QVariant &v1, const QVariant &v2) @@ -2918,8 +2997,9 @@ bool QVariant::convert(const int type, void *ptr) const Returns false if \a v1 and \a v2 are equal; otherwise returns true. - \warning This function doesn't support custom types registered - with qRegisterMetaType(). + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). */ /*! \fn bool QVariant::operator==(const QVariant &v) const @@ -2932,8 +3012,9 @@ bool QVariant::convert(const int type, void *ptr) const type is not the same as this variant's type. See canConvert() for a list of possible conversions. - \warning This function doesn't support custom types registered - with qRegisterMetaType(). + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). */ /*! @@ -2942,8 +3023,61 @@ bool QVariant::convert(const int type, void *ptr) const Compares this QVariant with \a v and returns true if they are not equal; otherwise returns false. - \warning This function doesn't support custom types registered - with qRegisterMetaType(). + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). +*/ + +/*! + \fn bool QVariant::operator<(const QVariant &v) const + + Compares this QVariant with \a v and returns true if this is less than \a v. + + \note Comparability might not be availabe for the type stored in this QVariant + or in \a v. + + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). +*/ + +/*! + \fn bool QVariant::operator<=(const QVariant &v) const + + Compares this QVariant with \a v and returns true if this is less or equal than \a v. + + \note Comparability might not be available for the type stored in this QVariant + or in \a v. + + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). +*/ + +/*! + \fn bool QVariant::operator>(const QVariant &v) const + + Compares this QVariant with \a v and returns true if this is larger than \a v. + + \note Comparability might not be available for the type stored in this QVariant + or in \a v. + + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). +*/ + +/*! + \fn bool QVariant::operator>=(const QVariant &v) const + + Compares this QVariant with \a v and returns true if this is larger or equal than \a v. + + \note Comparability might not be available for the type stored in this QVariant + or in \a v. + + \warning To make this function work with a custom type registered with + qRegisterMetaType(), its comparison operator must be registered using + QMetaType::registerComparators(). */ static bool qIsNumericType(uint tp) @@ -2962,6 +3096,7 @@ static bool qIsFloatingPoint(uint tp) */ bool QVariant::cmp(const QVariant &v) const { + QVariant v1 = *this; QVariant v2 = v; if (d.type != v2.d.type) { if (qIsNumericType(d.type) && qIsNumericType(v.d.type)) { @@ -2970,10 +3105,63 @@ bool QVariant::cmp(const QVariant &v) const else return toLongLong() == v.toLongLong(); } - if (!v2.canConvert(d.type) || !v2.convert(d.type)) + if (!v2.canConvert(v1.d.type) || !v2.convert(v1.d.type)) return false; } - return handlerManager[d.type]->compare(&d, &v2.d); + if (v1.d.type >= QMetaType::User) { + int result; + if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result)) + return result == 0; + } + return handlerManager[v1.d.type]->compare(&v1.d, &v2.d); +} + +/*! + \internal + */ +int QVariant::compare(const QVariant &v) const +{ + if (cmp(v)) + return 0; + QVariant v1 = *this; + QVariant v2 = v; + if (v1.d.type != v2.d.type) { + // if both types differ, try to convert + if (v2.canConvert(v1.d.type)) { + QVariant temp = v2; + if (temp.convert(v1.d.type)) + v2 = temp; + } + if (v1.d.type != v2.d.type && v1.canConvert(v2.d.type)) { + QVariant temp = v1; + if (temp.convert(v2.d.type)) + v1 = temp; + } + if (v1.d.type != v2.d.type) { + // if conversion fails, default to toString + return v1.toString().compare(v2.toString(), Qt::CaseInsensitive); + } + } + if (v1.d.type >= QMetaType::User) { + int result; + if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v2.d)), d.type, &result)) + return result; + } + if (qIsNumericType(v1.d.type)) { + if (qIsFloatingPoint(v1.d.type)) + return v1.toReal() < v2.toReal() ? -1 : 1; + else + return v1.toLongLong() < v2.toLongLong() ? -1 : 1; + } + switch (v1.d.type) { + case QVariant::Date: + return v1.toDate() < v2.toDate() ? -1 : 1; + case QVariant::Time: + return v1.toTime() < v2.toTime() ? -1 : 1; + case QVariant::DateTime: + return v1.toDateTime() < v2.toDateTime() ? -1 : 1; + } + return v1.toString().compare(v2.toString(), Qt::CaseInsensitive); } /*! @@ -3022,7 +3210,16 @@ QDebug operator<<(QDebug dbg, const QVariant &v) dbg.nospace() << "QVariant("; if (typeId != QMetaType::UnknownType) { dbg.nospace() << QMetaType::typeName(typeId) << ", "; - handlerManager[typeId]->debugStream(dbg, v); + bool userStream = false; + bool canConvertToString = false; + if (typeId >= QMetaType::User) { + userStream = QMetaType::debugStream(dbg, constData(v.d), typeId); + canConvertToString = v.canConvert<QString>(); + } + if (!userStream && canConvertToString) + dbg << v.toString(); + else if (!userStream) + handlerManager[typeId]->debugStream(dbg, v); } else { dbg.nospace() << "Invalid"; } @@ -3074,7 +3271,12 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p) returned. Note that this only works for QObject subclasses which use the Q_OBJECT macro. - \sa setValue(), fromValue(), canConvert() + If the QVariant contains a sequential container and \c{T} is QVariantList, the + elements of the container will be converted into QVariants and returned as a QVariantList. + + \snippet code/src_corelib_kernel_qvariant.cpp 9 + + \sa setValue(), fromValue(), canConvert(), qRegisterSequentialConverter() */ /*! \fn bool QVariant::canConvert() const @@ -3226,4 +3428,359 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p) \internal */ +/*! + \class QSequentialIterable + + \inmodule QtCore + \brief The QSequentialIterable class is an iterable interface for a container in a QVariant. + + This class allows several methods of accessing the elements of a container held within + a QVariant. An instance of QSequentialIterable can be extracted from a QVariant if it can + be converted to a QVariantList. + + \snippet code/src_corelib_kernel_qvariant.cpp 9 + + The container itself is not copied before iterating over it. + + \sa QVariant +*/ + +/*! \fn QSequentialIterable::QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl) + + \internal +*/ + +/*! \fn QSequentialIterable::const_iterator QSequentialIterable::begin() const + + Returns a QSequentialIterable::const_iterator for the beginning of the container. This + can be used in stl-style iteration. + + \sa end() +*/ + +/*! \fn QSequentialIterable::const_iterator QSequentialIterable::end() const + + Returns a QSequentialIterable::const_iterator for the end of the container. This + can be used in stl-style iteration. + + \sa begin() +*/ + +/*! \fn QVariant QSequentialIterable::at(int idx) const + + Returns the element at position \a idx in the container. +*/ + +/*! \fn int QSequentialIterable::size() const + + Returns the number of elements in the container. +*/ + +/*! \fn bool QSequentialIterable::canReverseIterate() const + + Returns whether it is possible to iterate over the container in reverse. This + corresponds to the std::bidirectional_iterator_tag iterator trait of the + const_iterator of the container. +*/ + +/*! + \class QSequentialIterable::const_iterator + + \inmodule QtCore + \brief The QSequentialIterable::const_iterator allows iteration over a container in a QVariant. + + A QSequentialIterable::const_iterator can only be created by a QSequentialIterable instance, + and can be used in a way similar to other stl-style iterators. + + \snippet code/src_corelib_kernel_qvariant.cpp 9 + + \sa QSequentialIterable +*/ + + +/*! \fn QSequentialIterable::const_iterator::~const_iterator() + + Destroys the QSequentialIterable::const_iterator. +*/ + +/*! \fn QSequentialIterable::const_iterator::const_iterator(const const_iterator &other) + + Creates a copy of \a other. +*/ + +/*! \fn QVariant QSequentialIterable::const_iterator::operator*() const + + Returns the current item, converted to a QVariant. +*/ + +/*! \fn bool QSequentialIterable::const_iterator::operator==(const const_iterator &other) const + + Returns true if \a other points to the same item as this + iterator; otherwise returns false. + + \sa operator!=() +*/ + +/*! \fn bool QSequentialIterable::const_iterator::operator!=(const const_iterator &other) const + + Returns true if \a other points to a different item than this + iterator; otherwise returns false. + + \sa operator==() +*/ + +/*! \fn QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator++() + + The prefix ++ operator (\c{++it}) advances the iterator to the + next item in the container and returns an iterator to the new current + item. + + Calling this function on QSequentialIterable::end() leads to undefined results. + + \sa operator--() +*/ + +/*! \fn QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator++(int) + + \overload + + The postfix ++ operator (\c{it++}) advances the iterator to the + next item in the container and returns an iterator to the previously + current item. +*/ + +/*! \fn QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator--() + + The prefix -- operator (\c{--it}) makes the preceding item + current and returns an iterator to the new current item. + + Calling this function on QSequentialIterable::begin() leads to undefined results. + + If the container in the QVariant does not support bi-directional iteration, calling this function + leads to undefined results. + + \sa operator++(), canReverseIterate() +*/ + +/*! \fn QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator--(int) + + \overload + + The postfix -- operator (\c{it--}) makes the preceding item + current and returns an iterator to the previously current item. + + If the container in the QVariant does not support bi-directional iteration, calling this function + leads to undefined results. + + \sa canReverseIterate() +*/ + +/*! \fn QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator+=(int j) + + Advances the iterator by \a j items. + + \sa operator-=(), operator+() +*/ + +/*! \fn QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator-=(int j) + + Makes the iterator go back by \a j items. + + If the container in the QVariant does not support bi-directional iteration, calling this function + leads to undefined results. + + \sa operator+=(), operator-(), canReverseIterate() +*/ + +/*! \fn QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator+(int j) const + + Returns an iterator to the item at \a j positions forward from + this iterator. + + \sa operator-(), operator+=() +*/ + +/*! \fn QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator-(int j) const + + Returns an iterator to the item at \a j positions backward from + this iterator. + + If the container in the QVariant does not support bi-directional iteration, calling this function + leads to undefined results. + + \sa operator+(), operator-=(), canReverseIterate() +*/ + +/*! + \class QAssociativeIterable + + \inmodule QtCore + \brief The QAssociativeIterable class is an iterable interface for an associative container in a QVariant. + + This class allows several methods of accessing the elements of an associative container held within + a QVariant. An instance of QAssociativeIterable can be extracted from a QVariant if it can + be converted to a QVariantHash or QVariantMap. + + \snippet code/src_corelib_kernel_qvariant.cpp 10 + + The container itself is not copied before iterating over it. + + \sa QVariant +*/ + +/*! \fn QAssociativeIterable::QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl) + + \internal +*/ + +/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::begin() const + + Returns a QAssociativeIterable::const_iterator for the beginning of the container. This + can be used in stl-style iteration. + + \sa end() +*/ + +/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::end() const + + Returns a QAssociativeIterable::const_iterator for the end of the container. This + can be used in stl-style iteration. + + \sa begin() +*/ + +/*! \fn QVariant QAssociativeIterable::value(const QVariant &key) const + + Returns the value for the given \a key in the container, if the types are convertible. +*/ + +/*! \fn int QAssociativeIterable::size() const + + Returns the number of elements in the container. +*/ + +/*! + \class QAssociativeIterable::const_iterator + + \inmodule QtCore + \brief The QAssociativeIterable::const_iterator allows iteration over a container in a QVariant. + + A QAssociativeIterable::const_iterator can only be created by a QAssociativeIterable instance, + and can be used in a way similar to other stl-style iterators. + + \snippet code/src_corelib_kernel_qvariant.cpp 10 + + \sa QAssociativeIterable +*/ + + +/*! \fn QAssociativeIterable::const_iterator::~const_iterator() + + Destroys the QAssociativeIterable::const_iterator. +*/ + +/*! \fn QAssociativeIterable::const_iterator::const_iterator(const const_iterator &other) + + Creates a copy of \a other. +*/ + +/*! \fn QVariant QAssociativeIterable::const_iterator::operator*() const + + Returns the current value, converted to a QVariant. +*/ + +/*! \fn QVariant QAssociativeIterable::const_iterator::key() const + + Returns the current key, converted to a QVariant. +*/ + +/*! \fn QVariant QAssociativeIterable::const_iterator::value() const + + Returns the current value, converted to a QVariant. +*/ + +/*! \fn bool QAssociativeIterable::const_iterator::operator==(const const_iterator &other) const + + Returns true if \a other points to the same item as this + iterator; otherwise returns false. + + \sa operator!=() +*/ + +/*! \fn bool QAssociativeIterable::const_iterator::operator!=(const const_iterator &other) const + + Returns true if \a other points to a different item than this + iterator; otherwise returns false. + + \sa operator==() +*/ + +/*! \fn QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator++() + + The prefix ++ operator (\c{++it}) advances the iterator to the + next item in the container and returns an iterator to the new current + item. + + Calling this function on QAssociativeIterable::end() leads to undefined results. + + \sa operator--() +*/ + +/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator++(int) + + \overload + + The postfix ++ operator (\c{it++}) advances the iterator to the + next item in the container and returns an iterator to the previously + current item. +*/ + +/*! \fn QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator--() + + The prefix -- operator (\c{--it}) makes the preceding item + current and returns an iterator to the new current item. + + Calling this function on QAssociativeIterable::begin() leads to undefined results. + + \sa operator++() +*/ + +/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator--(int) + + \overload + + The postfix -- operator (\c{it--}) makes the preceding item + current and returns an iterator to the previously current item. +*/ + +/*! \fn QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator+=(int j) + + Advances the iterator by \a j items. + + \sa operator-=(), operator+() +*/ + +/*! \fn QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator-=(int j) + + Makes the iterator go back by \a j items. + + \sa operator+=(), operator-() +*/ + +/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator+(int j) const + + Returns an iterator to the item at \a j positions forward from + this iterator. + + \sa operator-(), operator+=() +*/ + +/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator-(int j) const + + Returns an iterator to the item at \a j positions backward from + this iterator. + + \sa operator+(), operator-=() +*/ + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 6f212f5000..d5ea491288 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -49,6 +49,7 @@ #include <QtCore/qmap.h> #include <QtCore/qhash.h> #include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> #include <QtCore/qobject.h> QT_BEGIN_NAMESPACE @@ -432,6 +433,14 @@ class Q_CORE_EXPORT QVariant { return cmp(v); } inline bool operator!=(const QVariant &v) const { return !cmp(v); } + inline bool operator<(const QVariant &v) const + { return compare(v) < 0; } + inline bool operator<=(const QVariant &v) const + { return compare(v) <= 0; } + inline bool operator>(const QVariant &v) const + { return compare(v) > 0; } + inline bool operator>=(const QVariant &v) const + { return compare(v) >= 0; } protected: friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &); @@ -449,6 +458,7 @@ public: Private d; void create(int type, const void *copy); bool cmp(const QVariant &other) const; + int compare(const QVariant &other) const; bool convert(const int t, void *ptr) const; private: @@ -562,6 +572,173 @@ inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2) } #endif +class QSequentialIterable +{ + QtMetaTypePrivate::QSequentialIterableImpl m_impl; +public: + struct const_iterator + { + private: + QtMetaTypePrivate::QSequentialIterableImpl m_impl; + QAtomicInt *ref; + friend class QSequentialIterable; + inline explicit const_iterator(const QSequentialIterable &iter, QAtomicInt *ref_) + : m_impl(iter.m_impl), ref(ref_) { ref->ref(); } + + inline explicit const_iterator(const QtMetaTypePrivate::QSequentialIterableImpl &impl, QAtomicInt *ref_) + : m_impl(impl), ref(ref_) { ref->ref(); } + + inline void begin() { m_impl.moveToBegin(); } + inline void end() { m_impl.moveToEnd(); } + public: + inline ~const_iterator() { + if (!ref->deref()) { + m_impl.destroyIter(); + } + } + + inline const_iterator(const const_iterator &other) : m_impl(other.m_impl), ref(other.ref) { + ref->ref(); + } + + inline const QVariant operator*() const { + const QtMetaTypePrivate::VariantData d = m_impl.getCurrent(); + if (d.metaTypeId == qMetaTypeId<QVariant>()) + return *reinterpret_cast<const QVariant*>(d.data); + return QVariant(d.metaTypeId, d.data, d.flags); + } + inline bool operator==(const const_iterator &o) const { return m_impl.equal(o.m_impl); } + inline bool operator!=(const const_iterator &o) const { return !m_impl.equal(o.m_impl); } + inline const_iterator &operator++() { m_impl.advance(1); return *this; } + inline const_iterator operator++(int) { QtMetaTypePrivate::QSequentialIterableImpl impl = m_impl; m_impl.advance(1); return const_iterator(impl, this->ref); } + inline const_iterator &operator--() { m_impl.advance(-1); return *this; } + inline const_iterator operator--(int) { QtMetaTypePrivate::QSequentialIterableImpl impl = m_impl; m_impl.advance(-1); return const_iterator(impl, this->ref); } + inline const_iterator &operator+=(int j) { m_impl.advance(j); return *this; } + inline const_iterator &operator-=(int j) { m_impl.advance(-j); return *this; } + inline const_iterator operator+(int j) const { QtMetaTypePrivate::QSequentialIterableImpl impl = m_impl; impl.advance(j); return const_iterator(impl, this->ref); } + inline const_iterator operator-(int j) const { QtMetaTypePrivate::QSequentialIterableImpl impl = m_impl; impl.advance(-j); return const_iterator(impl, this->ref); } + }; + + friend struct const_iterator; + + explicit QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl impl) + : m_impl(impl) + { + } + + const_iterator begin() const { const_iterator it(*this, new QAtomicInt(0)); it.begin(); return it; } + const_iterator end() const { const_iterator it(*this, new QAtomicInt(0)); it.end(); return it; } + + QVariant at(int idx) const { + const QtMetaTypePrivate::VariantData d = m_impl.at(idx); + if (d.metaTypeId == qMetaTypeId<QVariant>()) + return *reinterpret_cast<const QVariant*>(d.data); + return QVariant(d.metaTypeId, d.data, d.flags); + } + int size() const { return m_impl.size(); } + + bool canReverseIterate() const + { return m_impl._iteratorCapabilities & QtMetaTypePrivate::BiDirectionalCapability; } +}; + +class QAssociativeIterable +{ + QtMetaTypePrivate::QAssociativeIterableImpl m_impl; +public: + struct const_iterator + { + private: + QtMetaTypePrivate::QAssociativeIterableImpl m_impl; + QAtomicInt *ref; + friend class QAssociativeIterable; + inline explicit const_iterator(const QAssociativeIterable &iter, QAtomicInt *ref_) + : m_impl(iter.m_impl), ref(ref_) { ref->ref(); } + + inline explicit const_iterator(const QtMetaTypePrivate::QAssociativeIterableImpl &impl, QAtomicInt *ref_) + : m_impl(impl), ref(ref_) { ref->ref(); } + + inline void begin() { m_impl.begin(); } + inline void end() { m_impl.end(); } + public: + inline ~const_iterator() { + if (!ref->deref()) { + m_impl.destroyIter(); + } + } + inline const_iterator(const const_iterator &other) : m_impl(other.m_impl), ref(other.ref) { + ref->ref(); + } + + inline const QVariant key() const { + const QtMetaTypePrivate::VariantData d = m_impl.getCurrentKey(); + QVariant v(d.metaTypeId, d.data, d.flags); + if (d.metaTypeId == qMetaTypeId<QVariant>()) + return *reinterpret_cast<const QVariant*>(d.data); + return v; + } + + inline const QVariant value() const { + const QtMetaTypePrivate::VariantData d = m_impl.getCurrentValue(); + QVariant v(d.metaTypeId, d.data, d.flags); + if (d.metaTypeId == qMetaTypeId<QVariant>()) + return *reinterpret_cast<const QVariant*>(d.data); + return v; + } + + inline const QVariant operator*() const { + const QtMetaTypePrivate::VariantData d = m_impl.getCurrentValue(); + QVariant v(d.metaTypeId, d.data, d.flags); + if (d.metaTypeId == qMetaTypeId<QVariant>()) + return *reinterpret_cast<const QVariant*>(d.data); + return v; + } + inline bool operator==(const const_iterator &o) const { return m_impl.equal(o.m_impl); } + inline bool operator!=(const const_iterator &o) const { return !m_impl.equal(o.m_impl); } + inline const_iterator &operator++() { m_impl.advance(1); return *this; } + inline const_iterator operator++(int) { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; m_impl.advance(1); return const_iterator(impl, this->ref); } + inline const_iterator &operator--() { m_impl.advance(-1); return *this; } + inline const_iterator operator--(int) { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; m_impl.advance(-1); return const_iterator(impl, this->ref); } + inline const_iterator &operator+=(int j) { m_impl.advance(j); return *this; } + inline const_iterator &operator-=(int j) { m_impl.advance(-j); return *this; } + inline const_iterator operator+(int j) const { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; impl.advance(j); return const_iterator(impl, this->ref); } + inline const_iterator operator-(int j) const { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; impl.advance(-j); return const_iterator(impl, this->ref); } + }; + + friend struct const_iterator; + + explicit QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl impl) + : m_impl(impl) + { + } + + const_iterator begin() const { const_iterator it(*this, new QAtomicInt(0)); it.begin(); return it; } + const_iterator end() const { const_iterator it(*this, new QAtomicInt(0)); it.end(); return it; } + + QVariant value(const QVariant &key) const + { + QVariant key_ = key; + if (!key_.canConvert(m_impl._metaType_id_key)) + return QVariant(); + if (!key_.convert(m_impl._metaType_id_key)) + return QVariant(); + const QtMetaTypePrivate::VariantData dkey(key_.userType(), key_.constData(), 0 /*key.flags()*/); + QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; + impl.find(dkey); + QtMetaTypePrivate::QAssociativeIterableImpl endIt = m_impl; + endIt.end(); + if (impl.equal(endIt)) + return QVariant(); + const QtMetaTypePrivate::VariantData d = impl.getCurrentValue(); + QVariant v(d.metaTypeId, d.data, d.flags); + if (d.metaTypeId == qMetaTypeId<QVariant>()) + return *reinterpret_cast<const QVariant*>(d.data); + return v; + } + + int size() const { return m_impl.size(); } +}; + +#ifndef QT_MOC namespace QtPrivate { template<typename T> struct QVariantValueHelper : TreatAsQObjectBeforeMetaType<QVariantValueHelper<T>, T, const QVariant &, T> @@ -571,11 +748,9 @@ namespace QtPrivate { const int vid = qMetaTypeId<T>(); if (vid == v.userType()) return *reinterpret_cast<const T *>(v.constData()); - if (vid < int(QMetaType::User)) { - T t; - if (v.convert(vid, &t)) - return t; - } + T t; + if (v.convert(vid, &t)) + return t; return T(); } #ifndef QT_NO_QOBJECT @@ -585,12 +760,118 @@ namespace QtPrivate { } #endif }; + + template<typename T> + struct QVariantValueHelperInterface : QVariantValueHelper<T> + { + }; + + template<> + struct QVariantValueHelperInterface<QSequentialIterable> + { + static QSequentialIterable invoke(const QVariant &v) + { + if (v.userType() == qMetaTypeId<QVariantList>()) { + return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QVariantList*>(v.constData()))); + } + if (v.userType() == qMetaTypeId<QStringList>()) { + return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QStringList*>(v.constData()))); + } + return QSequentialIterable(v.value<QtMetaTypePrivate::QSequentialIterableImpl>()); + } + }; + template<> + struct QVariantValueHelperInterface<QAssociativeIterable> + { + static QAssociativeIterable invoke(const QVariant &v) + { + if (v.userType() == qMetaTypeId<QVariantMap>()) { + return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantMap*>(v.constData()))); + } + if (v.userType() == qMetaTypeId<QVariantHash>()) { + return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantHash*>(v.constData()))); + } + return QAssociativeIterable(v.value<QtMetaTypePrivate::QAssociativeIterableImpl>()); + } + }; + template<> + struct QVariantValueHelperInterface<QVariantList> + { + static QVariantList invoke(const QVariant &v) + { + if (v.userType() == qMetaTypeId<QStringList>() || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) { + QSequentialIterable iter = QVariantValueHelperInterface<QSequentialIterable>::invoke(v); + QVariantList l; + l.reserve(iter.size()); + for (QSequentialIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) + l << *it; + return l; + } + return QVariantValueHelper<QVariantList>::invoke(v); + } + }; + template<> + struct QVariantValueHelperInterface<QVariantHash> + { + static QVariantHash invoke(const QVariant &v) + { + if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) { + QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v); + QVariantHash l; + l.reserve(iter.size()); + for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) + l.insert(it.key().toString(), it.value()); + return l; + } + return QVariantValueHelper<QVariantHash>::invoke(v); + } + }; + template<> + struct QVariantValueHelperInterface<QVariantMap> + { + static QVariantMap invoke(const QVariant &v) + { + if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) { + QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v); + QVariantMap l; + for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) + l.insert(it.key().toString(), it.value()); + return l; + } + return QVariantValueHelper<QVariantMap>::invoke(v); + } + }; + template<> + struct QVariantValueHelperInterface<QPair<QVariant, QVariant> > + { + static QPair<QVariant, QVariant> invoke(const QVariant &v) + { + if (v.userType() == qMetaTypeId<QPair<QVariant, QVariant> >()) + return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v); + + if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>())) { + QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value<QtMetaTypePrivate::QPairVariantInterfaceImpl>(); + + const QtMetaTypePrivate::VariantData d1 = pi.first(); + QVariant v1(d1.metaTypeId, d1.data, d1.flags); + if (d1.metaTypeId == qMetaTypeId<QVariant>()) + v1 = *reinterpret_cast<const QVariant*>(d1.data); + + const QtMetaTypePrivate::VariantData d2 = pi.second(); + QVariant v2(d2.metaTypeId, d2.data, d2.flags); + if (d2.metaTypeId == qMetaTypeId<QVariant>()) + v2 = *reinterpret_cast<const QVariant*>(d2.data); + + return QPair<QVariant, QVariant>(v1, v2); + } + return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v); + } + }; } -#ifndef QT_MOC template<typename T> inline T qvariant_cast(const QVariant &v) { - return QtPrivate::QVariantValueHelper<T>::invoke(v); + return QtPrivate::QVariantValueHelperInterface<T>::invoke(v); } template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v) diff --git a/src/corelib/plugin/plugin.pri b/src/corelib/plugin/plugin.pri index eb7a7f7fa8..338b3d0972 100644 --- a/src/corelib/plugin/plugin.pri +++ b/src/corelib/plugin/plugin.pri @@ -9,14 +9,16 @@ HEADERS += \ plugin/quuid.h \ plugin/qfactoryloader_p.h \ plugin/qsystemlibrary_p.h \ - plugin/qelfparser_p.h + plugin/qelfparser_p.h \ + plugin/qmachparser_p.h SOURCES += \ plugin/qpluginloader.cpp \ plugin/qfactoryloader.cpp \ plugin/quuid.cpp \ plugin/qlibrary.cpp \ - plugin/qelfparser_p.cpp + plugin/qelfparser_p.cpp \ + plugin/qmachparser.cpp win32 { SOURCES += \ diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 3432f9619d..92e60c2216 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -1,7 +1,7 @@ - /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Intel Corporation ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -64,6 +64,7 @@ #include <qjsondocument.h> #include <qjsonvalue.h> #include "qelfparser_p.h" +#include "qmachparser_p.h" QT_BEGIN_NAMESPACE @@ -180,8 +181,6 @@ QT_BEGIN_NAMESPACE */ -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) - static long qt_find_pattern(const char *s, ulong s_len, const char *pattern, ulong p_len) { @@ -228,7 +227,7 @@ static long qt_find_pattern(const char *s, ulong s_len, information could not be read. Returns true if version information is present and successfully read. */ -static bool qt_unix_query(const QString &library, QLibraryPrivate *lib) +static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) { QFile file(library); if (!file.open(QIODevice::ReadOnly)) { @@ -253,7 +252,7 @@ static bool qt_unix_query(const QString &library, QLibraryPrivate *lib) } /* - ELF binaries on GNU, have .qplugin sections. + ELF and Mach-O binaries with GCC have .qplugin sections. */ bool hasMetaData = false; long pos = 0; @@ -274,6 +273,26 @@ static bool qt_unix_query(const QString &library, QLibraryPrivate *lib) pos += rel; hasMetaData = true; } +#elif defined (Q_OF_MACH_O) + { + QString errorString; + int r = QMachOParser::parse(filedata, fdlen, library, &errorString, &pos, &fdlen); + if (r == QMachOParser::NotSuitable) { + if (qt_debug_component()) + qWarning("QMachOParser: %s", qPrintable(errorString)); + if (lib) + lib->errorString = errorString; + return false; + } + // even if the metadata section was not found, the Mach-O parser will + // at least return the boundaries of the right architecture + long rel = qt_find_pattern(filedata + pos, fdlen, pattern, plen); + if (rel < 0) + pos = -1; + else + pos += rel; + hasMetaData = true; + } #else pos = qt_find_pattern(filedata, fdlen, pattern, plen); if (pos > 0) @@ -300,8 +319,6 @@ static bool qt_unix_query(const QString &library, QLibraryPrivate *lib) return ret; } -#endif // Q_OS_UNIX && !Q_OS_MAC - static void installCoverageTool(QLibraryPrivate *libPrivate) { #ifdef __COVERAGESCANNER__ @@ -618,41 +635,18 @@ bool QLibrary::isLibrary(const QString &fileName) } -#if defined (Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_CC_INTEL) -#define QT_USE_MS_STD_EXCEPTION 1 -const char* qt_try_versioninfo(void *pfn, bool *exceptionThrown) -{ - *exceptionThrown = false; - const char *szData = 0; - typedef const char * (*VerificationFunction)(); - VerificationFunction func = reinterpret_cast<VerificationFunction>(pfn); - __try { - if(func) - szData = func(); - } __except(EXCEPTION_EXECUTE_HANDLER) { - *exceptionThrown = true; - } - return szData; -} -#endif - typedef const char * (*QtPluginQueryVerificationDataFunction)(); -bool qt_get_metadata(QtPluginQueryVerificationDataFunction pfn, QLibraryPrivate *priv, bool *exceptionThrown) +static bool qt_get_metadata(QtPluginQueryVerificationDataFunction pfn, QLibraryPrivate *priv) { - *exceptionThrown = false; const char *szData = 0; if (!pfn) return false; -#ifdef QT_USE_MS_STD_EXCEPTION - szData = qt_try_versioninfo((void *)pfn, exceptionThrown); - if (*exceptionThrown) - return false; -#else + szData = pfn(); -#endif if (!szData) return false; + QJsonDocument doc = QLibraryPrivate::fromRawMetaData(szData); if (doc.isNull()) return false; @@ -690,80 +684,15 @@ void QLibraryPrivate::updatePluginState() } #endif -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) if (!pHnd) { - // use unix shortcut to avoid loading the library - success = qt_unix_query(fileName, this); - } else -#endif - { - bool retryLoadLibrary = false; // Only used on Windows with MS compiler.(false in other cases) - do { - bool temporary_load = false; -#ifdef Q_OS_WIN - HMODULE hTempModule = 0; -#endif - if (!pHnd) { -#ifdef Q_OS_WIN - DWORD dwFlags = (retryLoadLibrary) ? 0: DONT_RESOLVE_DLL_REFERENCES; - //avoid 'Bad Image' message box - UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); - hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, dwFlags); - SetErrorMode(oldmode); -#else - temporary_load = load(); -#endif - } - QtPluginQueryVerificationDataFunction getMetaData = NULL; - - bool exceptionThrown = false; - bool ret = false; -#ifdef Q_OS_WIN - if (hTempModule) { - getMetaData = (QtPluginQueryVerificationDataFunction) -#ifdef Q_OS_WINCE - ::GetProcAddress(hTempModule, L"qt_plugin_query_metadata") -#else - ::GetProcAddress(hTempModule, "qt_plugin_query_metadata") -#endif - ; - } else -#endif - { - getMetaData = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_metadata"); - } - - if (getMetaData) - ret = qt_get_metadata(getMetaData, this, &exceptionThrown); - - if (temporary_load) - unload(); - if (!exceptionThrown) { - if (ret) { - success = true; - } - retryLoadLibrary = false; - } -#ifdef QT_USE_MS_STD_EXCEPTION - else { - // An exception was thrown when calling qt_plugin_query_verification_data(). - // This usually happens when plugin is compiled with the /clr compiler flag, - // & will only work if the dependencies are loaded & DLLMain() is called. - // LoadLibrary() will do this, try once with this & if it fails don't load. - retryLoadLibrary = !retryLoadLibrary; - } -#endif -#ifdef Q_OS_WIN - if (hTempModule) { - BOOL ok = ::FreeLibrary(hTempModule); - if (ok) { - hTempModule = 0; - } - - } -#endif - } while (retryLoadLibrary); // Will be 'false' in all cases other than when an - // exception is thrown(will happen only when using a MS compiler) + // scan for the plugin metadata without loading + success = findPatternUnloaded(fileName, this); + } else { + // library is already loaded (probably via QLibrary) + // simply get the target function and call it. + QtPluginQueryVerificationDataFunction getMetaData = NULL; + getMetaData = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_metadata"); + success = qt_get_metadata(getMetaData, this); } if (!success) { diff --git a/src/corelib/plugin/qmachparser.cpp b/src/corelib/plugin/qmachparser.cpp new file mode 100644 index 0000000000..5152a92d1d --- /dev/null +++ b/src/corelib/plugin/qmachparser.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Intel Corporation +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmachparser_p.h" + +#if defined(Q_OF_MACH_O) && !defined(QT_NO_LIBRARY) + +#include <qendian.h> +#include "qlibrary_p.h" + +#include <mach-o/loader.h> +#include <mach-o/fat.h> + +QT_BEGIN_NAMESPACE + +#if defined(Q_PROCESSOR_X86_64) +# define MACHO64 +static const cpu_type_t my_cputype = CPU_TYPE_X86_64; +#elif defined(Q_PROCESSOR_X86_32) +static const cpu_type_t my_cputype = CPU_TYPE_X86; +#elif defined(Q_PROCESSOR_POWER_64) +# define MACHO64 +static const cpu_type_t my_cputype = CPU_TYPE_POWERPC64; +#elif defined(Q_PROCESSOR_POWER_32) +static const cpu_type_t my_cputype = CPU_TYPE_POWERPC; +#elif defined(Q_PROCESSOR_ARM) +static const cpu_type_t my_cputype = CPU_TYPE_ARM; +#else +# error "Unknown CPU type" +#endif + +#ifdef MACHO64 +# undef MACHO64 +typedef mach_header_64 my_mach_header; +typedef segment_command_64 my_segment_command; +typedef section_64 my_section; +static const uint32_t my_magic = MH_MAGIC_64; +#else +typedef mach_header my_mach_header; +typedef segment_command my_segment_command; +typedef section my_section; +static const uint32_t my_magic = MH_MAGIC; +#endif + +static int ns(const QString &reason, const QString &library, QString *errorString) +{ + if (errorString) + *errorString = QLibrary::tr("'%1' is not a valid Mach-O binary (%2)") + .arg(library, reason.isEmpty() ? QLibrary::tr("file is corrupt") : reason); + return QMachOParser::NotSuitable; +} + +int QMachOParser::parse(const char *m_s, ulong fdlen, const QString &library, QString *errorString, long *pos, ulong *sectionlen) +{ + // The minimum size of a Mach-O binary we're interested in. + // It must have a full Mach header, at least one segment and at least one + // section. It's probably useless with just the "qtmetadata" section, but + // it's valid nonetheless. + // A fat binary must have this plus the fat header, of course. + static const size_t MinFileSize = sizeof(my_mach_header) + sizeof(my_segment_command) + sizeof(my_section); + static const size_t MinFatHeaderSize = sizeof(fat_header) + 2 * sizeof(fat_arch); + + if (Q_UNLIKELY(fdlen < MinFileSize)) + return ns(QLibrary::tr("file too small"), library, errorString); + + // find out if this is a fat Mach-O binary first + const my_mach_header *header = 0; + const fat_header *fat = reinterpret_cast<const fat_header *>(m_s); + if (fat->magic == qToBigEndian(FAT_MAGIC)) { + // find our architecture in the binary + const fat_arch *arch = reinterpret_cast<const fat_arch *>(fat + 1); + if (Q_UNLIKELY(fdlen < MinFatHeaderSize)) { + return ns(QLibrary::tr("file too small"), library, errorString); + } + + int count = qFromBigEndian(fat->nfat_arch); + if (Q_UNLIKELY(fdlen < sizeof(*fat) + sizeof(*arch) * count)) + return ns(QString(), library, errorString); + + for (int i = 0; i < count; ++i) { + if (arch[i].cputype == qToBigEndian(my_cputype)) { + // ### should we check the CPU subtype? Maybe on ARM? + uint32_t size = qFromBigEndian(arch[i].size); + uint32_t offset = qFromBigEndian(arch[i].offset); + if (Q_UNLIKELY(size > fdlen) || Q_UNLIKELY(offset > fdlen) + || Q_UNLIKELY(size + offset > fdlen) || Q_UNLIKELY(size < MinFileSize)) + return ns(QString(), library, errorString); + + header = reinterpret_cast<const my_mach_header *>(m_s + offset); + fdlen = size; + break; + } + } + if (!header) + return ns(QLibrary::tr("no suitable architecture in fat binary"), library, errorString); + + // check the magic again + if (Q_UNLIKELY(header->magic != my_magic)) + return ns(QString(), library, errorString); + } else { + header = reinterpret_cast<const my_mach_header *>(m_s); + fat = 0; + + // check magic + if (header->magic != my_magic) + return ns(QLibrary::tr("invalid magic %1").arg(qFromBigEndian(header->magic), 8, 16, QLatin1Char('0')), + library, errorString); + } + + // from this point on, fdlen is specific to this architecture + // from this point on, everything is in host byte order + *pos = reinterpret_cast<const char *>(header) - m_s; + + // (re-)check the CPU type + // ### should we check the CPU subtype? Maybe on ARM? + if (header->cputype != my_cputype) { + if (fat) + return ns(QString(), library, errorString); + return ns(QLibrary::tr("wrong architecture"), library, errorString); + } + + // check the file type + if (Q_UNLIKELY(header->filetype != MH_BUNDLE && header->filetype != MH_DYLIB)) + return ns(QLibrary::tr("not a dynamic library"), library, errorString); + + // find the __TEXT segment, "qtmetadata" section + const my_segment_command *seg = reinterpret_cast<const my_segment_command *>(header + 1); + ulong minsize = sizeof(*header); + + for (uint i = 0; i < header->ncmds; ++i, + seg = reinterpret_cast<const my_segment_command *>(reinterpret_cast<const char *>(seg) + seg->cmdsize)) { + // We're sure that the file size includes at least one load command + // but we have to check anyway if we're past the first + if (Q_UNLIKELY(fdlen < minsize + sizeof(load_command))) + return ns(QString(), library, errorString); + + // cmdsize can't be trusted until validated + // so check it against fdlen anyway + // (these are unsigned operations, with overflow behavior specified in the standard) + minsize += seg->cmdsize; + if (Q_UNLIKELY(fdlen < minsize) || Q_UNLIKELY(fdlen < seg->cmdsize)) + return ns(QString(), library, errorString); + + const uint32_t MyLoadCommand = sizeof(void *) > 4 ? LC_SEGMENT_64 : LC_SEGMENT; + if (seg->cmd != MyLoadCommand) + continue; + + // is this the __TEXT segment? + if (strcmp(seg->segname, "__TEXT") == 0) { + const my_section *sect = reinterpret_cast<const my_section *>(seg + 1); + for (uint j = 0; j < seg->nsects; ++j) { + // is this the "qtmetadata" section? + if (strcmp(sect[j].sectname, "qtmetadata") != 0) + continue; + + // found it! + if (Q_UNLIKELY(fdlen < sect[j].offset) || Q_UNLIKELY(fdlen < sect[j].size) + || Q_UNLIKELY(fdlen < sect[j].offset + sect[j].size)) + return ns(QString(), library, errorString); + + *pos += sect[j].offset; + *sectionlen = sect[j].size; + return QtMetaDataSection; + } + } + + // other type of segment + seg = reinterpret_cast<const my_segment_command *>(reinterpret_cast<const char *>(seg) + seg->cmdsize); + } + +// // No Qt section was found, but at least we know that where the proper architecture's boundaries are +// return NoQtSection; + if (errorString) + *errorString = QLibrary::tr("'%1' is not a Qt plugin").arg(library); + return NotSuitable; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/plugin/qmachparser_p.h b/src/corelib/plugin/qmachparser_p.h new file mode 100644 index 0000000000..6b2774dab6 --- /dev/null +++ b/src/corelib/plugin/qmachparser_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Intel Corporation +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACHPARSER_P_H +#define QMACHPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qendian.h> +#include <qglobal.h> + +#ifndef QT_NO_LIBRARY +#if defined(Q_OF_MACH_O) + +QT_BEGIN_NAMESPACE + +class QString; +class QLibraryPrivate; + +class Q_AUTOTEST_EXPORT QMachOParser +{ +public: + enum { QtMetaDataSection, NoQtSection, NotSuitable }; + static int parse(const char *m_s, ulong fdlen, const QString &library, QString *errorString, long *pos, ulong *sectionlen); +}; + +QT_END_NAMESPACE + +#endif // defined(Q_OF_ELF) && defined(Q_CC_GNU) +#endif // QT_NO_LIBRARY + +#endif // QMACHPARSER_P_H diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h index e3b76886f1..8337afcb9d 100644 --- a/src/corelib/tools/qalgorithms.h +++ b/src/corelib/tools/qalgorithms.h @@ -516,6 +516,73 @@ Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator } //namespace QAlgorithmsPrivate + +// Use __builtin_popcount on gcc. Clang claims to be gcc +// but has a bug where __builtin_popcount is not marked as +// constexpr. +#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) +#define QALGORITHMS_USE_BUILTIN_POPCOUNT +#endif + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint32 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcount(v); +#else + // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint8 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcount(v); +#else + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint16 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcount(v); +#else + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint64 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcountll(v); +#else + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 36) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 48) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 60) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(long unsigned int v) +{ + return qPopulationCount(static_cast<quint64>(v)); +} + +#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) +#undef QALGORITHMS_USE_BUILTIN_POPCOUNT +#endif + + QT_END_NAMESPACE #endif // QALGORITHMS_H diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc index ad6c3d913c..f3dfddec77 100644 --- a/src/corelib/tools/qalgorithms.qdoc +++ b/src/corelib/tools/qalgorithms.qdoc @@ -635,3 +635,34 @@ of \a value in the variable passed as a reference in argument \a n. \sa {qLess()}{qLess<T>()} */ + + +/*! + \fn uint qPopulationCount(quint8 v) + \relates <QtAlgorithms> + \since 5.2 + + Returns the number of bits set in \a v. This number also called + the Hamming Weight of \a v. + */ + +/*! + \fn uint qPopulationCount(quint16 v) + \relates <QtAlgorithms> + \since 5.2 + \overload + */ + +/*! + \fn uint qPopulationCount(quint32 v) + \relates <QtAlgorithms> + \since 5.2 + \overload + */ + +/*! + \fn uint qPopulationCount(quint64 v) + \relates <QtAlgorithms> + \since 5.2 + \overload + */ diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp index b04c4f9c3d..54c1ff8843 100644 --- a/src/corelib/tools/qbitarray.cpp +++ b/src/corelib/tools/qbitarray.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qbitarray.h" +#include <qalgorithms.h> #include <qdatastream.h> #include <qdebug.h> #include <string.h> @@ -160,24 +161,18 @@ int QBitArray::count(bool on) const for (int i = 0; i < len; ++i) numBits += testBit(i); #else - // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel const quint8 *bits = reinterpret_cast<const quint8 *>(d.data()) + 1; while (len >= 32) { quint32 v = quint32(bits[0]) | (quint32(bits[1]) << 8) | (quint32(bits[2]) << 16) | (quint32(bits[3]) << 24); - quint32 c = ((v & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; - c += (((v & 0xfff000) >> 12) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; - c += ((v >> 24) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; len -= 32; bits += 4; - numBits += int(c); + numBits += int(qPopulationCount(v)); } while (len >= 24) { quint32 v = quint32(bits[0]) | (quint32(bits[1]) << 8) | (quint32(bits[2]) << 16); - quint32 c = ((v & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; - c += (((v & 0xfff000) >> 12) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; len -= 24; bits += 3; - numBits += int(c); + numBits += int(qPopulationCount(v)); } while (len >= 0) { if (bits[len / 8] & (1 << ((len - 1) & 7))) diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h index 1103712627..eaf9b2ff25 100644 --- a/src/corelib/tools/qbitarray.h +++ b/src/corelib/tools/qbitarray.h @@ -61,6 +61,7 @@ public: QBitArray(const QBitArray &other) : d(other.d) {} inline QBitArray &operator=(const QBitArray &other) { d = other.d; return *this; } #ifdef Q_COMPILER_RVALUE_REFS + inline QBitArray(QBitArray &&other) : d(std::move(other.d)) {} inline QBitArray &operator=(QBitArray &&other) { qSwap(d, other.d); return *this; } #endif diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 6ce17e5e13..a2d3891f00 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -556,6 +556,7 @@ QByteArray qUncompress(const uchar* data, int nbytes) d.take(); // realloc was successful d.reset(p); d->offset = sizeof(QByteArrayData); + d->size = 0; // Shut up valgrind "uninitialized variable" warning int res = ::uncompress((uchar*)d->data(), &len, (uchar*)data+4, nbytes-4); diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index d8e3a78cdf..7b99aa1e06 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -158,9 +158,19 @@ static const char monthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, static const char * const qt_shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +int qt_monthNumberFromShortName(const QString &shortName) +{ + for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) { + if (shortName == QLatin1String(qt_shortMonthNames[i])) + return i + 1; + } + return -1; +} #endif #ifndef QT_NO_DATESTRING static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* dd = 0); +static void rfcDateImpl(const QString &s, QDate *dd = 0, QTime *dt = 0, int *utfcOffset = 0); #endif /***************************************************************************** @@ -735,6 +745,10 @@ QString QDate::longDayName(int weekday, MonthNameType type) QLocale::ShortFormat) or QLocale().toString(date, QLocale::LongFormat). + If the \a format is Qt::RFC2822Date, the string is formatted in + an \l{RFC 2822} compatible way. An example of this formatting is + "20 May 1995". + If the date is invalid, an empty string will be returned. \warning The Qt::ISODate format is only valid for years in the @@ -771,6 +785,8 @@ QString QDate::toString(Qt::DateFormat f) const .arg(y); } #endif + case Qt::RFC2822Date: + return toString(QStringLiteral("dd MMM yyyy")); case Qt::ISODate: { if (year() < 0 || year() > 9999) @@ -1124,6 +1140,11 @@ QDate QDate::fromString(const QString& s, Qt::DateFormat f) case Qt::DefaultLocaleLongDate: return fromString(s, QLocale().dateFormat(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat : QLocale::ShortFormat)); + case Qt::RFC2822Date: { + QDate date; + rfcDateImpl(s, &date); + return date; + } default: #ifndef QT_NO_TEXTDATE case Qt::TextDate: { @@ -1474,15 +1495,15 @@ int QTime::msec() const /*! \overload - Returns the time as a string. Milliseconds are not included. The - \a format parameter determines the format of the string. + Returns the time as a string. The \a format parameter determines + the format of the string. - If \a format is Qt::TextDate, the string format is HH:MM:SS; e.g. 1 - second before midnight would be "23:59:59". + If \a format is Qt::TextDate, the string format is HH:MM:SS.zzz; + e.g. 1 second before midnight would be "23:59:59.000". If \a format is Qt::ISODate, the string format corresponds to the - ISO 8601 extended specification for representations of dates, - which is also HH:MM:SS. + ISO 8601 extended specification (with decimal fractions) for + representations of dates; also HH:MM:SS.zzz. If the \a format is Qt::SystemLocaleShortDate or Qt::SystemLocaleLongDate, the string format depends on the locale @@ -1498,6 +1519,10 @@ int QTime::msec() const QLocale::ShortFormat) or QLocale().toString(time, QLocale::LongFormat). + If the \a format is Qt::RFC2822Date, the string is formatted in + an \l{RFC 2822} compatible way. An example of this formatting is + "23:59:20". + If the time is invalid, an empty string will be returned. */ @@ -1518,13 +1543,19 @@ QString QTime::toString(Qt::DateFormat format) const return QLocale().toString(*this, format == Qt::DefaultLocaleLongDate ? QLocale::LongFormat : QLocale::ShortFormat); + case Qt::RFC2822Date: + return QString::fromLatin1("%1:%2:%3") + .arg(hour(), 2, 10, QLatin1Char('0')) + .arg(minute(), 2, 10, QLatin1Char('0')) + .arg(second(), 2, 10, QLatin1Char('0')); default: case Qt::ISODate: case Qt::TextDate: - return QString::fromLatin1("%1:%2:%3") + return QString::fromLatin1("%1:%2:%3.%4") .arg(hour(), 2, 10, QLatin1Char('0')) .arg(minute(), 2, 10, QLatin1Char('0')) - .arg(second(), 2, 10, QLatin1Char('0')); + .arg(second(), 2, 10, QLatin1Char('0')) + .arg(msec(), 3, 10, QLatin1Char('0')); } } @@ -1789,6 +1820,11 @@ QTime fromStringImpl(const QString &s, Qt::DateFormat f, bool &isMidnight24) QLocale::FormatType formatType(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat : QLocale::ShortFormat); return QTime::fromString(s, QLocale().timeFormat(formatType)); } + case Qt::RFC2822Date: { + QTime time; + rfcDateImpl(s, 0, &time); + return time; + } case Qt::TextDate: case Qt::ISODate: { @@ -2465,15 +2501,15 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) the default way. QDate::shortDayName(), QDate::shortMonthName(), and QTime::toString() are used to generate the string, so the day and month names will be localized names. An example of this - formatting is "Wed May 20 03:40:13 1998". + formatting is "Wed May 20 03:40:13.456 1998". If the \a format is Qt::ISODate, the string format corresponds - to the ISO 8601 extended specification for representations of - dates and times, taking the form YYYY-MM-DDTHH:MM:SS[Z|[+|-]HH:MM], - depending on the timeSpec() of the QDateTime. If the timeSpec() - is Qt::UTC, Z will be appended to the string; if the timeSpec() is - Qt::OffsetFromUTC, the offset in hours and minutes from UTC will - be appended to the string. + to the ISO 8601 extended specification (with decimal fractions) for + representations of dates and times, taking the form + YYYY-MM-DDTHH:MM:SS.zzz[Z|[+|-]HH:MM], depending on the timeSpec() + of the QDateTime. If the timeSpec() is Qt::UTC, Z will be appended + to the string; if the timeSpec() is Qt::OffsetFromUTC, the offset + in hours and minutes from UTC will be appended to the string. If the \a format is Qt::SystemLocaleShortDate or Qt::SystemLocaleLongDate, the string format depends on the locale @@ -2489,6 +2525,9 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) QLocale::ShortFormat) or QLocale().toString(datetime, QLocale::LongFormat). + If the \a format is Qt::RFC2822Date, the string is formatted + following \l{RFC 2822}. + If the datetime is invalid, an empty string will be returned. \warning The Qt::ISODate format is only valid for years in the @@ -2525,6 +2564,28 @@ QString QDateTime::toString(Qt::DateFormat f) const default: break; } + } else if (f == Qt::RFC2822Date) { + buf = toString(QStringLiteral("dd MMM yyyy hh:mm:ss ")); + + int utcOffset = d->utcOffset; + if (timeSpec() == Qt::LocalTime) { + QDateTime utc = toUTC(); + utc.setTimeSpec(timeSpec()); + utcOffset = utc.secsTo(*this); + } + + const int offset = qAbs(utcOffset); + buf += QLatin1Char((offset == utcOffset) ? '+' : '-'); + + const int hour = offset / 3600; + if (hour < 10) + buf += QLatin1Char('0'); + buf += QString::number(hour); + + const int min = (offset - (hour * 3600)) / 60; + if (min < 10) + buf += QLatin1Char('0'); + buf += QString::number(min); } #ifndef QT_NO_TEXTDATE else if (f == Qt::TextDate) { @@ -3332,6 +3393,19 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) return QDateTime(date, time, ts); } + case Qt::RFC2822Date: { + QDate date; + QTime time; + int utcOffset = 0; + rfcDateImpl(s, &date, &time, &utcOffset); + + if (!date.isValid() || !time.isValid()) + return QDateTime(); + + QDateTime dateTime(date, time, Qt::UTC); + dateTime.setUtcOffset(utcOffset); + return dateTime; + } case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: case Qt::SystemLocaleLongDate: @@ -3408,13 +3482,29 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) return QDateTime(); } - int second = (timeParts.count() > 2) ? timeParts.at(2).toInt(&ok) : 0; - if (!ok) { - return QDateTime(); + int second = 0; + int millisecond = 0; + if (timeParts.count() > 2) { + QStringList secondParts = timeParts.at(2).split(QLatin1Char('.')); + if (secondParts.size() > 2) { + return QDateTime(); + } + + second = secondParts.first().toInt(&ok); + if (!ok) { + return QDateTime(); + } + + if (secondParts.size() > 1) { + millisecond = secondParts.last().toInt(&ok); + if (!ok) { + return QDateTime(); + } + } } QDate date(year, month, day); - QTime time(hour, minute, second); + QTime time(hour, minute, second, millisecond); if (parts.count() == 5) return QDateTime(date, time, Qt::LocalTime); @@ -3936,6 +4026,68 @@ static QString fmtDateTime(const QString& f, const QTime* dt, const QDate* dd) return buf; } + +static void rfcDateImpl(const QString &s, QDate *dd, QTime *dt, int *utcOffset) +{ + int day = -1; + int month = -1; + int year = -1; + int hour = -1; + int min = -1; + int sec = -1; + int hourOffset = 0; + int minOffset = 0; + bool positiveOffset = false; + + // Matches "Wdy, DD Mon YYYY HH:MM:SS ±hhmm" (Wdy, being optional) + QRegExp rex(QStringLiteral("^(?:[A-Z][a-z]+,)?[ \\t]*(\\d{1,2})[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d)(?::(\\d\\d))?)?[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?")); + if (s.indexOf(rex) == 0) { + if (dd) { + day = rex.cap(1).toInt(); + month = qt_monthNumberFromShortName(rex.cap(2)); + year = rex.cap(3).toInt(); + } + if (dt) { + if (!rex.cap(4).isEmpty()) { + hour = rex.cap(4).toInt(); + min = rex.cap(5).toInt(); + sec = rex.cap(6).toInt(); + } + positiveOffset = (rex.cap(7) == QStringLiteral("+")); + hourOffset = rex.cap(8).toInt(); + minOffset = rex.cap(9).toInt(); + } + if (utcOffset) + *utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60)); + } else { + // Matches "Wdy Mon DD HH:MM:SS YYYY" + QRegExp rex(QStringLiteral("^[A-Z][a-z]+[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d):(\\d\\d))?[ \\t]+(\\d\\d\\d\\d)[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?")); + if (s.indexOf(rex) == 0) { + if (dd) { + month = qt_monthNumberFromShortName(rex.cap(1)); + day = rex.cap(2).toInt(); + year = rex.cap(6).toInt(); + } + if (dt) { + if (!rex.cap(3).isEmpty()) { + hour = rex.cap(3).toInt(); + min = rex.cap(4).toInt(); + sec = rex.cap(5).toInt(); + } + positiveOffset = (rex.cap(7) == QStringLiteral("+")); + hourOffset = rex.cap(8).toInt(); + minOffset = rex.cap(9).toInt(); + } + if (utcOffset) + *utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60)); + } + } + + if (dd) + *dd = QDate(year, month, day); + if (dt) + *dt = QTime(hour, min, sec); +} #endif // QT_NO_DATESTRING #ifdef Q_OS_WIN diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index 5c1668033c..e5c1e104a2 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -217,11 +217,13 @@ public: QTime time() const; Qt::TimeSpec timeSpec() const; qint64 toMSecsSinceEpoch() const; + // ### Qt 6: use quint64 instead of uint uint toTime_t() const; void setDate(const QDate &date); void setTime(const QTime &time); void setTimeSpec(Qt::TimeSpec spec); void setMSecsSinceEpoch(qint64 msecs); + // ### Qt 6: use quint64 instead of uint void setTime_t(uint secsSince1Jan1970UTC); #ifndef QT_NO_DATESTRING QString toString(Qt::DateFormat f = Qt::TextDate) const; @@ -255,6 +257,7 @@ public: static QDateTime fromString(const QString &s, Qt::DateFormat f = Qt::TextDate); static QDateTime fromString(const QString &s, const QString &format); #endif + // ### Qt 6: use quint64 instead of uint static QDateTime fromTime_t(uint secsSince1Jan1970UTC); static QDateTime fromMSecsSinceEpoch(qint64 msecs); static qint64 currentMSecsSinceEpoch() Q_DECL_NOTHROW; diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index bc0a14ea72..67e0711796 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -608,14 +608,16 @@ struct BezierEase : public QEasingCurveFunction sign = -1; d = d * sign; - qreal t_i = _fast_cbrt(d); + qreal t = _fast_cbrt(d); //one step of Halley's Method to get a better approximation - const qreal t_i_cubic = t_i * t_i * t_i; - qreal t = t_i * (t_i_cubic + d + d) / (t_i_cubic + t_i_cubic + d); + const qreal t_cubic = t * t * t; + const qreal f = t_cubic + t_cubic + d; + if (f != qreal(0.0)) + t = t * (t_cubic + d + d) / f; //another step - /*t_i = t; + /*qreal t_i = t; t_i_cubic = pow(t_i, 3); t = t_i * (t_i_cubic + d + d) / (t_i_cubic + t_i_cubic + d);*/ diff --git a/src/corelib/tools/qharfbuzz_p.h b/src/corelib/tools/qharfbuzz_p.h index 27ddb44e91..1471fd5712 100644 --- a/src/corelib/tools/qharfbuzz_p.h +++ b/src/corelib/tools/qharfbuzz_p.h @@ -140,20 +140,6 @@ typedef enum { HB_ScriptCount = HB_Script_Inherited } HB_Script; -typedef enum { - HB_NoJustification= 0, /* Justification can't be applied after this glyph */ - HB_Arabic_Space = 1, /* This glyph represents a space inside arabic text */ - HB_Character = 2, /* Inter-character justification point follows this glyph */ - HB_Space = 4, /* This glyph represents a blank outside an Arabic run */ - HB_Arabic_Normal = 7, /* Normal Middle-Of-Word glyph that connects to the right (begin) */ - HB_Arabic_Waw = 8, /* Next character is final form of Waw/Ain/Qaf/Fa */ - HB_Arabic_BaRa = 9, /* Next two chars are Ba + Ra/Ya/AlefMaksura */ - HB_Arabic_Alef = 10, /* Next character is final form of Alef/Tah/Lam/Kaf/Gaf */ - HB_Arabic_HaaDal = 11, /* Next character is final form of Haa/Dal/Taa Marbutah */ - HB_Arabic_Seen = 12, /* Initial or Medial form Of Seen/Sad */ - HB_Arabic_Kashida = 13 /* Kashida(U+640) in middle of word */ -} HB_JustificationClass; - #ifdef __xlC__ typedef unsigned hb_bitfield; #else diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index e99a67d1e3..25029afe1f 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -509,6 +509,25 @@ private: static void deleteNode2(QHashData::Node *node); static void duplicateNode(QHashData::Node *originalNode, void *newNode); + + bool isValidIterator(const iterator &it) const + { +#if defined(QT_DEBUG) && !defined(Q_HASH_NO_ITERATOR_DEBUG) + union { + QHashData *iteratorHashData; + QHashData::Node *node; + }; + node = it.i; + while (node->next) + node = node->next; + + return (iteratorHashData == d); +#else + Q_UNUSED(it); + return true; +#endif + } + friend class QSet<Key>; }; @@ -831,6 +850,8 @@ Q_OUTOFLINE_TEMPLATE T QHash<Key, T>::take(const Key &akey) template <class Key, class T> Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::erase(iterator it) { + Q_ASSERT_X(isValidIterator(it), "QHash::erase", "The specified const_iterator argument 'it' is invalid"); + if (it == iterator(e)) return it; diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 72e1403e76..28d35745a5 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -346,6 +346,11 @@ private: void node_destruct(Node *n); void node_copy(Node *from, Node *to, Node *src); void node_destruct(Node *from, Node *to); + + bool isValidIterator(const iterator &i) const + { + return (constBegin().i <= i.i) && (i.i <= constEnd().i); + } }; #if defined(Q_CC_BOR) @@ -433,6 +438,8 @@ Q_INLINE_TEMPLATE QList<T> &QList<T>::operator=(const QList<T> &l) template <typename T> inline typename QList<T>::iterator QList<T>::insert(iterator before, const T &t) { + Q_ASSERT_X(isValidIterator(before), "QList::insert", "The specified iterator argument 'before' is invalid"); + int iBefore = int(before.i - reinterpret_cast<Node *>(p.begin())); Node *n = reinterpret_cast<Node *>(p.insert(iBefore)); QT_TRY { @@ -445,8 +452,11 @@ inline typename QList<T>::iterator QList<T>::insert(iterator before, const T &t) } template <typename T> inline typename QList<T>::iterator QList<T>::erase(iterator it) -{ node_destruct(it.i); - return reinterpret_cast<Node *>(p.erase(reinterpret_cast<void**>(it.i))); } +{ + Q_ASSERT_X(isValidIterator(it), "QList::erase", "The specified iterator argument 'it' is invalid"); + node_destruct(it.i); + return reinterpret_cast<Node *>(p.erase(reinterpret_cast<void**>(it.i))); +} template <typename T> inline const T &QList<T>::at(int i) const { Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::at", "index out of range"); @@ -807,6 +817,9 @@ template <typename T> Q_OUTOFLINE_TEMPLATE typename QList<T>::iterator QList<T>::erase(typename QList<T>::iterator afirst, typename QList<T>::iterator alast) { + Q_ASSERT_X(isValidIterator(afirst), "QList::erase", "The specified iterator argument 'afirst' is invalid"); + Q_ASSERT_X(isValidIterator(alast), "QList::erase", "The specified iterator argument 'alast' is invalid"); + for (Node *n = afirst.i; n < alast.i; ++n) node_destruct(n); int idx = afirst - begin(); diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h index 78fa336b7c..0fc3f87726 100644 --- a/src/corelib/tools/qlocale.h +++ b/src/corelib/tools/qlocale.h @@ -775,13 +775,14 @@ public: SouthSudan = 254, Bonaire = 255, SintMaarten = 256, + Kosovo = 257, DemocraticRepublicOfCongo = CongoKinshasa, PeoplesRepublicOfCongo = CongoBrazzaville, DemocraticRepublicOfKorea = NorthKorea, RepublicOfKorea = SouthKorea, RussianFederation = Russia, SyrianArabRepublic = Syria, - LastCountry = SintMaarten + LastCountry = Kosovo }; // GENERATED PART ENDS HERE diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc index 150e4a18ce..a3b38c41f4 100644 --- a/src/corelib/tools/qlocale.qdoc +++ b/src/corelib/tools/qlocale.qdoc @@ -92,7 +92,7 @@ \note For the current keyboard input locale take a look at QInputMethod::locale(). - QLocale's data is based on Common Locale Data Repository v23. + QLocale's data is based on Common Locale Data Repository v23.1. The double-to-string and string-to-double conversion functions are covered by the following licenses: @@ -584,6 +584,7 @@ \value SouthKorea \value DemocraticRepublicOfKorea Obsolete, please use NorthKorea \value RepublicOfKorea Obsolete, please use SouthKorea + \value Kosovo \value Kuwait \value Kyrgyzstan \value Laos diff --git a/src/corelib/tools/qlocale_data_p.h b/src/corelib/tools/qlocale_data_p.h index 6642f824ea..46b3eef658 100644 --- a/src/corelib/tools/qlocale_data_p.h +++ b/src/corelib/tools/qlocale_data_p.h @@ -77,8 +77,8 @@ static const int ImperialMeasurementSystemsCount = // GENERATED PART STARTS HERE /* - This part of the file was generated on 2013-03-16 from the - Common Locale Data Repository v23 + This part of the file was generated on 2013-08-10 from the + Common Locale Data Repository v23.1 http://www.unicode.org/cldr/ @@ -771,215 +771,215 @@ static const quint16 locale_index[] = { 3, // Afar 6, // Afrikaans 8, // Albanian - 10, // Amharic - 11, // Arabic - 37, // Armenian - 38, // Assamese + 11, // Amharic + 12, // Arabic + 38, // Armenian + 39, // Assamese 0, // Aymara - 39, // Azerbaijani + 40, // Azerbaijani 0, // Bashkir - 41, // Basque - 42, // Bengali - 44, // Dzongkha + 42, // Basque + 43, // Bengali + 45, // Dzongkha 0, // Bihari 0, // Bislama - 45, // Breton - 46, // Bulgarian - 47, // Burmese - 48, // Belarusian - 49, // Khmer - 50, // Catalan - 52, // Chinese + 46, // Breton + 47, // Bulgarian + 48, // Burmese + 49, // Belarusian + 50, // Khmer + 51, // Catalan + 53, // Chinese 0, // Corsican - 59, // Croatian - 61, // Czech - 62, // Danish - 63, // Dutch - 69, // English + 60, // Croatian + 62, // Czech + 63, // Danish + 64, // Dutch + 70, // English 0, // Esperanto - 140, // Estonian - 141, // Faroese + 141, // Estonian + 142, // Faroese 0, // Fijian - 142, // Finnish - 143, // French + 143, // Finnish + 144, // French 0, // Western Frisian - 187, // Gaelic - 188, // Galician - 189, // Georgian - 190, // German - 196, // Greek - 198, // Greenlandic + 188, // Gaelic + 189, // Galician + 190, // Georgian + 191, // German + 197, // Greek + 199, // Greenlandic 0, // Guarani - 199, // Gujarati - 200, // Hausa - 203, // Hebrew - 204, // Hindi - 205, // Hungarian - 206, // Icelandic - 207, // Indonesian - 208, // Interlingua + 200, // Gujarati + 201, // Hausa + 204, // Hebrew + 205, // Hindi + 206, // Hungarian + 207, // Icelandic + 208, // Indonesian + 209, // Interlingua 0, // Interlingue 0, // Inuktitut 0, // Inupiak - 209, // Irish - 210, // Italian - 213, // Japanese + 210, // Irish + 211, // Italian + 214, // Japanese 0, // Javanese - 214, // Kannada - 215, // Kashmiri - 216, // Kazakh - 217, // Kinyarwanda - 218, // Kirghiz - 219, // Korean + 215, // Kannada + 216, // Kashmiri + 217, // Kazakh + 218, // Kinyarwanda + 219, // Kirghiz + 220, // Korean 0, // Kurdish - 221, // Rundi - 222, // Lao + 222, // Rundi + 223, // Lao 0, // Latin - 223, // Latvian - 224, // Lingala - 228, // Lithuanian - 229, // Macedonian - 230, // Malagasy - 231, // Malay - 234, // Malayalam - 235, // Maltese + 224, // Latvian + 225, // Lingala + 229, // Lithuanian + 230, // Macedonian + 231, // Malagasy + 232, // Malay + 235, // Malayalam + 236, // Maltese 0, // Maori - 236, // Marathi + 237, // Marathi 0, // Marshallese - 237, // Mongolian + 238, // Mongolian 0, // Nauru - 238, // Nepali - 240, // NorwegianBokmal + 239, // Nepali + 241, // NorwegianBokmal 0, // Occitan - 241, // Oriya - 242, // Pashto - 243, // Persian - 245, // Polish - 246, // Portuguese - 255, // Punjabi + 242, // Oriya + 243, // Pashto + 244, // Persian + 246, // Polish + 247, // Portuguese + 256, // Punjabi 0, // Quechua - 257, // Romansh - 258, // Romanian - 260, // Russian + 258, // Romansh + 259, // Romanian + 261, // Russian 0, // Samoan - 266, // Sango + 267, // Sango 0, // Sanskrit - 267, // Serbian - 273, // Ossetic - 275, // Southern Sotho - 277, // Tswana - 279, // Shona + 268, // Serbian + 276, // Ossetic + 278, // Southern Sotho + 280, // Tswana + 282, // Shona 0, // Sindhi - 280, // Sinhala - 281, // Swati - 283, // Slovak - 284, // Slovenian - 285, // Somali - 289, // Spanish + 283, // Sinhala + 284, // Swati + 286, // Slovak + 287, // Slovenian + 288, // Somali + 292, // Spanish 0, // Sundanese - 315, // Swahili - 318, // Swedish + 318, // Swahili + 321, // Swedish 0, // Sardinian - 321, // Tajik - 322, // Tamil + 324, // Tajik + 325, // Tamil 0, // Tatar - 326, // Telugu - 327, // Thai - 328, // Tibetan - 330, // Tigrinya - 332, // Tongan - 333, // Tsonga - 334, // Turkish + 329, // Telugu + 330, // Thai + 331, // Tibetan + 333, // Tigrinya + 335, // Tongan + 336, // Tsonga + 337, // Turkish 0, // Turkmen 0, // Tahitian 0, // Uighur - 336, // Ukrainian - 337, // Urdu - 339, // Uzbek - 342, // Vietnamese + 339, // Ukrainian + 340, // Urdu + 342, // Uzbek + 345, // Vietnamese 0, // Volapuk - 343, // Welsh + 346, // Welsh 0, // Wolof - 344, // Xhosa + 347, // Xhosa 0, // Yiddish - 345, // Yoruba + 348, // Yoruba 0, // Zhuang - 346, // Zulu - 347, // NorwegianNynorsk - 348, // Bosnian + 349, // Zulu + 350, // NorwegianNynorsk + 351, // Bosnian 0, // Divehi - 350, // Manx - 351, // Cornish - 352, // Akan - 353, // Konkani + 353, // Manx + 354, // Cornish + 355, // Akan + 356, // Konkani 0, // Ga - 354, // Igbo - 355, // Kamba + 357, // Igbo + 358, // Kamba 0, // Syriac - 356, // Blin + 359, // Blin 0, // Geez 0, // Koro 0, // Sidamo 0, // Atsam - 357, // Tigre + 360, // Tigre 0, // Jju - 358, // Friulian - 359, // Venda - 360, // Ewe - 362, // Walamo - 363, // Hawaiian + 361, // Friulian + 362, // Venda + 363, // Ewe + 365, // Walamo + 366, // Hawaiian 0, // Tyap 0, // Nyanja - 364, // Filipino - 365, // Swiss German - 366, // Sichuan Yi + 367, // Filipino + 368, // Swiss German + 369, // Sichuan Yi 0, // Kpelle 0, // Low German - 367, // South Ndebele - 368, // Northern Sotho - 369, // Northern Sami + 370, // South Ndebele + 371, // Northern Sotho + 372, // Northern Sami 0, // Taroko - 371, // Gusii - 372, // Taita - 373, // Fulah - 374, // Kikuyu - 375, // Samburu - 376, // Sena - 377, // North Ndebele - 378, // Rombo - 379, // Tachelhit - 381, // Kabyle - 382, // Nyankole - 383, // Bena - 384, // Vunjo - 385, // Bambara - 386, // Embu - 387, // Cherokee - 388, // Morisyen - 389, // Makonde - 390, // Langi - 391, // Ganda - 392, // Bemba - 393, // Kabuverdianu - 394, // Meru - 395, // Kalenjin - 396, // Nama - 397, // Machame - 398, // Colognian - 399, // Masai - 401, // Soga - 402, // Luyia - 403, // Asu - 404, // Teso - 406, // Saho - 407, // Koyra Chiini - 408, // Rwa - 409, // Luo - 410, // Chiga - 411, // Central Morocco Tamazight - 412, // Koyraboro Senni - 413, // Shambala - 414, // Bodo + 374, // Gusii + 375, // Taita + 376, // Fulah + 377, // Kikuyu + 378, // Samburu + 379, // Sena + 380, // North Ndebele + 381, // Rombo + 382, // Tachelhit + 384, // Kabyle + 385, // Nyankole + 386, // Bena + 387, // Vunjo + 388, // Bambara + 389, // Embu + 390, // Cherokee + 391, // Morisyen + 392, // Makonde + 393, // Langi + 394, // Ganda + 395, // Bemba + 396, // Kabuverdianu + 397, // Meru + 398, // Kalenjin + 399, // Nama + 400, // Machame + 401, // Colognian + 402, // Masai + 404, // Soga + 405, // Luyia + 406, // Asu + 407, // Teso + 409, // Saho + 410, // Koyra Chiini + 411, // Rwa + 412, // Luo + 413, // Chiga + 414, // Central Morocco Tamazight + 415, // Koyraboro Senni + 416, // Shambala + 417, // Bodo 0, // Avaric 0, // Chamorro 0, // Chechen @@ -994,37 +994,37 @@ static const quint16 locale_index[] = { 0, // Kongo 0, // Kwanyama 0, // Limburgish - 415, // LubaKatanga + 418, // LubaKatanga 0, // Luxembourgish 0, // Navaho 0, // Ndonga 0, // Ojibwa 0, // Pali 0, // Walloon - 416, // Aghem - 417, // Basaa - 418, // Zarma - 419, // Duala - 420, // JolaFonyi - 421, // Ewondo - 422, // Bafia - 423, // MakhuwaMeetto - 424, // Mundang - 425, // Kwasio - 426, // Nuer - 427, // Sakha - 428, // Sangu - 429, // Congo Swahili - 430, // Tasawaq - 431, // Vai - 433, // Walser - 434, // Yangben + 419, // Aghem + 420, // Basaa + 421, // Zarma + 422, // Duala + 423, // JolaFonyi + 424, // Ewondo + 425, // Bafia + 426, // MakhuwaMeetto + 427, // Mundang + 428, // Kwasio + 429, // Nuer + 430, // Sakha + 431, // Sangu + 432, // Congo Swahili + 433, // Tasawaq + 434, // Vai + 436, // Walser + 437, // Yangben 0, // Avestan - 435, // Asturian - 436, // Ngomba - 437, // Kako - 438, // Meta - 439, // Ngiemboon + 438, // Asturian + 439, // Ngomba + 440, // Kako + 441, // Meta + 442, // Ngiemboon 0, // Aragonese 0, // Akkadian 0, // AncientEgyptian @@ -1091,436 +1091,439 @@ static const QLocaleData locale_data[] = { { 5, 7, 148, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 72,10 , 99,16 , 37,5 , 8,10 , 653,48 , 701,92 , 134,24 , 653,48 , 701,92 , 134,24 , 290,21 , 311,58 , 369,14 , 290,21 , 311,58 , 369,14 , 4,3 , 4,3 , {78,65,68}, 12,1 , 58,23 , 14,5 , 4,0 , 50,9 , 70,7 , 2, 1, 1, 6, 7 }, // Afrikaans/Latin/Namibia { 6, 7, 2, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 0,6 , 0,6 , 115,8 , 123,18 , 42,7 , 49,12 , 793,48 , 841,78 , 919,24 , 793,48 , 841,78 , 919,24 , 383,28 , 411,58 , 469,14 , 383,28 , 411,58 , 469,14 , 7,2 , 7,2 , {65,76,76}, 13,3 , 0,7 , 4,4 , 4,0 , 77,5 , 82,9 , 0, 0, 1, 6, 7 }, // Albanian/Latin/Albania { 6, 7, 127, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 0,6 , 0,6 , 115,8 , 123,18 , 42,7 , 49,12 , 793,48 , 841,78 , 919,24 , 793,48 , 841,78 , 919,24 , 383,28 , 411,58 , 469,14 , 383,28 , 411,58 , 469,14 , 7,2 , 7,2 , {77,75,68}, 16,3 , 0,7 , 4,4 , 4,0 , 77,5 , 91,8 , 2, 1, 1, 6, 7 }, // Albanian/Latin/Macedonia - { 7, 14, 69, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 14,6 , 14,6 , 20,9 , 29,8 , 141,10 , 10,17 , 18,7 , 25,12 , 943,46 , 989,61 , 1050,24 , 1074,46 , 1120,62 , 1050,24 , 483,27 , 510,28 , 538,14 , 483,27 , 510,28 , 538,14 , 9,3 , 9,4 , {69,84,66}, 19,2 , 81,34 , 4,4 , 8,6 , 99,4 , 103,5 , 2, 1, 7, 6, 7 }, // Amharic/Ethiopic/Ethiopia - { 8, 1, 64, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {69,71,80}, 21,5 , 115,70 , 14,5 , 19,6 , 108,7 , 115,3 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Egypt - { 8, 1, 3, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 179,8 , 161,18 , 18,7 , 25,12 , 1281,71 , 1281,71 , 1352,24 , 1281,71 , 1281,71 , 1352,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {68,90,68}, 26,5 , 185,91 , 14,5 , 19,6 , 108,7 , 118,7 , 2, 1, 6, 4, 5 }, // Arabic/Arabic/Algeria - { 8, 1, 17, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {66,72,68}, 31,5 , 276,91 , 14,5 , 19,6 , 108,7 , 125,7 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Bahrain - { 8, 1, 42, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {88,65,70}, 36,4 , 367,84 , 14,5 , 19,6 , 108,7 , 132,4 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Chad - { 8, 1, 48, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {75,77,70}, 40,7 , 451,105 , 14,5 , 19,6 , 108,7 , 136,9 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Comoros - { 8, 1, 59, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {68,74,70}, 5,3 , 556,84 , 14,5 , 19,6 , 108,7 , 145,6 , 0, 0, 6, 6, 7 }, // Arabic/Arabic/Djibouti - { 8, 1, 67, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {69,82,78}, 8,3 , 640,91 , 14,5 , 19,6 , 108,7 , 151,7 , 2, 1, 1, 6, 7 }, // Arabic/Arabic/Eritrea - { 8, 1, 103, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1376,92 , 1376,92 , 1468,24 , 1492,92 , 1376,92 , 1468,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {73,81,68}, 47,5 , 731,84 , 14,5 , 19,6 , 108,7 , 158,6 , 0, 0, 6, 5, 6 }, // Arabic/Arabic/Iraq - { 8, 1, 105, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {73,76,83}, 52,1 , 815,133 , 14,5 , 19,6 , 108,7 , 164,7 , 2, 1, 7, 5, 6 }, // Arabic/Arabic/Israel - { 8, 1, 109, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1376,92 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {74,79,68}, 53,5 , 948,84 , 14,5 , 19,6 , 108,7 , 171,6 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Jordan - { 8, 1, 115, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {75,87,68}, 58,5 , 1032,84 , 14,5 , 19,6 , 108,7 , 177,6 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Kuwait - { 8, 1, 119, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1376,92 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {76,66,80}, 63,5 , 1116,84 , 14,5 , 19,6 , 108,7 , 183,5 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Lebanon - { 8, 1, 122, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {76,89,68}, 68,5 , 1200,77 , 14,5 , 19,6 , 108,7 , 188,5 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Libya - { 8, 1, 136, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {77,82,79}, 73,5 , 1277,112 , 14,5 , 19,6 , 108,7 , 193,9 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Mauritania - { 8, 1, 145, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 179,8 , 161,18 , 18,7 , 25,12 , 1584,71 , 1655,71 , 1726,24 , 1655,71 , 1750,71 , 1821,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {77,65,68}, 78,5 , 1389,77 , 14,5 , 19,6 , 108,7 , 202,6 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Morocco - { 8, 1, 162, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {79,77,82}, 83,5 , 1466,77 , 14,5 , 19,6 , 108,7 , 208,5 , 3, 0, 6, 4, 5 }, // Arabic/Arabic/Oman - { 8, 1, 165, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {73,76,83}, 52,1 , 815,133 , 14,5 , 19,6 , 108,7 , 213,6 , 2, 1, 1, 6, 7 }, // Arabic/Arabic/PalestinianTerritories - { 8, 1, 175, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {81,65,82}, 88,5 , 1543,70 , 4,4 , 4,0 , 108,7 , 219,3 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Qatar - { 8, 1, 186, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,65,82}, 93,5 , 1613,77 , 4,4 , 4,0 , 108,7 , 222,24 , 2, 1, 6, 4, 5 }, // Arabic/Arabic/SaudiArabia - { 8, 1, 194, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,79,83}, 98,1 , 1690,77 , 14,5 , 19,6 , 108,7 , 246,7 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Somalia - { 8, 1, 201, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,68,71}, 0,0 , 1767,84 , 14,5 , 19,6 , 108,7 , 253,7 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Sudan - { 8, 1, 207, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1376,92 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,89,80}, 99,5 , 1851,77 , 4,4 , 4,0 , 108,7 , 260,5 , 0, 0, 6, 5, 6 }, // Arabic/Arabic/Syria - { 8, 1, 216, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 179,8 , 161,18 , 18,7 , 25,12 , 1281,71 , 1281,71 , 1352,24 , 1281,71 , 1281,71 , 1352,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {84,78,68}, 104,5 , 1928,77 , 4,4 , 4,0 , 108,7 , 265,4 , 3, 0, 7, 5, 6 }, // Arabic/Arabic/Tunisia - { 8, 1, 223, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {65,69,68}, 109,5 , 2005,91 , 14,5 , 19,6 , 108,7 , 269,24 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/UnitedArabEmirates - { 8, 1, 236, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {77,65,68}, 78,5 , 1389,77 , 14,5 , 19,6 , 108,7 , 293,15 , 2, 1, 1, 6, 7 }, // Arabic/Arabic/WesternSahara - { 8, 1, 237, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {89,69,82}, 114,5 , 2096,70 , 4,4 , 4,0 , 108,7 , 308,5 , 0, 0, 6, 4, 5 }, // Arabic/Arabic/Yemen - { 9, 10, 11, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 58,7 , 58,7 , 187,8 , 195,21 , 61,4 , 65,10 , 1845,48 , 1893,106 , 1999,24 , 1845,48 , 1893,106 , 1999,24 , 618,28 , 646,62 , 708,15 , 618,28 , 646,62 , 708,15 , 13,12 , 14,12 , {65,77,68}, 119,3 , 2166,46 , 25,5 , 4,0 , 313,7 , 320,8 , 0, 0, 1, 6, 7 }, // Armenian/Armenian/Armenia - { 10, 11, 100, 46, 44, 59, 37, 2534, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 216,8 , 224,18 , 75,8 , 83,12 , 2023,62 , 2085,88 , 158,27 , 2023,62 , 2085,88 , 158,27 , 723,37 , 760,58 , 85,14 , 723,37 , 760,58 , 85,14 , 25,9 , 26,7 , {73,78,82}, 122,1 , 0,7 , 14,5 , 4,0 , 328,7 , 335,4 , 2, 1, 7, 7, 7 }, // Assamese/Bengali/India - { 12, 7, 15, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 250,19 , 37,5 , 8,10 , 2173,48 , 2221,77 , 158,27 , 2173,48 , 2221,77 , 158,27 , 818,26 , 844,67 , 99,14 , 818,26 , 844,67 , 99,14 , 0,2 , 0,2 , {65,90,78}, 123,4 , 2212,41 , 14,5 , 4,0 , 339,12 , 351,10 , 2, 1, 1, 6, 7 }, // Azerbaijani/Latin/Azerbaijan - { 12, 2, 15, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 250,19 , 37,5 , 8,10 , 2298,77 , 2298,77 , 158,27 , 2298,77 , 2298,77 , 158,27 , 911,67 , 911,67 , 99,14 , 911,67 , 911,67 , 99,14 , 0,2 , 0,2 , {65,90,78}, 127,4 , 2253,12 , 14,5 , 4,0 , 361,10 , 361,10 , 2, 1, 1, 6, 7 }, // Azerbaijani/Cyrillic/Azerbaijan - { 14, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 65,9 , 65,9 , 72,10 , 269,18 , 37,5 , 8,10 , 2375,48 , 2423,93 , 2516,24 , 2375,48 , 2423,93 , 2516,24 , 978,21 , 999,68 , 1067,14 , 978,21 , 999,68 , 1081,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2265,12 , 25,5 , 30,7 , 371,7 , 378,8 , 2, 1, 1, 6, 7 }, // Basque/Latin/Spain - { 15, 11, 18, 46, 44, 59, 37, 2534, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 74,10 , 84,9 , 287,6 , 224,18 , 18,7 , 25,12 , 2540,90 , 2540,90 , 2630,33 , 2540,90 , 2540,90 , 2630,33 , 1095,37 , 1132,58 , 1190,18 , 1095,37 , 1132,58 , 1190,18 , 34,9 , 33,7 , {66,68,84}, 132,1 , 2277,21 , 0,4 , 37,6 , 386,5 , 391,8 , 2, 1, 5, 6, 7 }, // Bengali/Bengali/Bangladesh - { 15, 11, 100, 46, 44, 59, 37, 2534, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 74,10 , 84,9 , 287,6 , 224,18 , 18,7 , 25,12 , 2540,90 , 2540,90 , 2630,33 , 2540,90 , 2540,90 , 2630,33 , 1095,37 , 1132,58 , 1190,18 , 1095,37 , 1132,58 , 1190,18 , 34,9 , 33,7 , {73,78,82}, 122,1 , 2298,19 , 0,4 , 37,6 , 386,5 , 399,4 , 2, 1, 7, 7, 7 }, // Bengali/Bengali/India - { 16, 31, 25, 46, 44, 59, 37, 3872, 45, 43, 101, 8220, 8221, 8216, 8217, 93,9 , 93,9 , 93,9 , 93,9 , 72,10 , 293,30 , 95,22 , 117,27 , 2663,63 , 2726,191 , 2917,27 , 2944,27 , 2971,132 , 3103,27 , 1208,34 , 1242,79 , 1321,27 , 1208,34 , 1242,79 , 1321,27 , 43,5 , 40,6 , {66,84,78}, 133,3 , 2317,15 , 4,4 , 4,0 , 403,6 , 409,5 , 2, 1, 7, 6, 7 }, // Dzongkha/Tibetan/Bhutan - { 19, 7, 74, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 3130,55 , 3185,78 , 158,27 , 3130,55 , 3185,78 , 158,27 , 1348,33 , 1381,43 , 1424,21 , 1348,33 , 1381,43 , 1424,21 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2332,11 , 14,5 , 4,0 , 414,9 , 423,5 , 2, 1, 1, 6, 7 }, // Breton/Latin/France - { 20, 2, 33, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 340,18 , 37,5 , 8,10 , 3263,59 , 3322,82 , 3404,24 , 3263,59 , 3322,82 , 3404,24 , 1445,21 , 1466,55 , 1521,14 , 1445,21 , 1466,55 , 1521,14 , 48,7 , 46,7 , {66,71,78}, 136,3 , 2343,47 , 25,5 , 4,0 , 428,9 , 437,8 , 2, 1, 1, 6, 7 }, // Bulgarian/Cyrillic/Bulgaria - { 21, 25, 147, 46, 44, 4170, 37, 4160, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 3428,43 , 3471,88 , 3559,24 , 3428,43 , 3471,88 , 3559,24 , 1535,25 , 1560,54 , 1614,14 , 1535,25 , 1560,54 , 1614,14 , 55,5 , 53,3 , {77,77,75}, 139,1 , 2390,18 , 14,5 , 4,0 , 445,3 , 448,6 , 0, 0, 7, 6, 7 }, // Burmese/Myanmar/Myanmar - { 22, 2, 20, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 358,6 , 10,17 , 144,5 , 149,10 , 3583,48 , 3631,99 , 3730,24 , 3754,48 , 3802,95 , 3897,24 , 1628,21 , 1649,56 , 1705,14 , 1628,21 , 1649,56 , 1705,14 , 60,10 , 56,13 , {66,89,82}, 140,2 , 2408,23 , 4,4 , 4,0 , 454,10 , 464,8 , 0, 0, 7, 6, 7 }, // Belarusian/Cyrillic/Belarus - { 23, 20, 36, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 109,9 , 364,8 , 10,17 , 18,7 , 25,12 , 3921,71 , 3921,71 , 158,27 , 3921,71 , 3921,71 , 158,27 , 1719,46 , 1719,46 , 1765,14 , 1719,46 , 1719,46 , 1765,14 , 70,5 , 69,5 , {75,72,82}, 142,1 , 2431,18 , 4,4 , 8,6 , 472,5 , 477,7 , 2, 1, 7, 6, 7 }, // Khmer/Khmer/Cambodia - { 24, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 118,7 , 118,7 , 27,8 , 372,21 , 159,4 , 163,9 , 3992,60 , 4052,82 , 4134,24 , 4158,93 , 4251,115 , 4366,24 , 1779,21 , 1800,60 , 1779,21 , 1860,28 , 1888,60 , 1779,21 , 75,4 , 74,4 , {69,85,82}, 131,1 , 2449,20 , 4,4 , 8,6 , 484,6 , 490,7 , 2, 1, 1, 6, 7 }, // Catalan/Latin/Spain - { 24, 7, 5, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 118,7 , 118,7 , 27,8 , 372,21 , 159,4 , 163,9 , 3992,60 , 4052,82 , 4134,24 , 4158,93 , 4251,115 , 4366,24 , 1779,21 , 1800,60 , 1779,21 , 1860,28 , 1888,60 , 1779,21 , 75,4 , 74,4 , {69,85,82}, 131,1 , 2449,20 , 4,4 , 8,6 , 484,6 , 497,7 , 2, 1, 1, 6, 7 }, // Catalan/Latin/Andorra - { 25, 5, 44, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 393,6 , 399,13 , 172,6 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {67,78,89}, 143,1 , 2469,10 , 4,4 , 8,6 , 504,4 , 508,2 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/China - { 25, 5, 97, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 287,6 , 399,13 , 172,6 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {72,75,68}, 12,1 , 2479,9 , 4,4 , 4,0 , 504,4 , 510,9 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/HongKong - { 25, 5, 126, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 287,6 , 399,13 , 172,6 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {77,79,80}, 144,4 , 2488,10 , 4,4 , 4,0 , 504,4 , 519,9 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/Macau - { 25, 5, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 27,8 , 399,13 , 188,7 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {83,71,68}, 12,1 , 2498,11 , 4,4 , 4,0 , 504,4 , 528,3 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/Singapore - { 25, 6, 97, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 130,5 , 130,5 , 287,6 , 399,13 , 172,6 , 195,13 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 2011,21 , 1969,28 , 1997,14 , 2011,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {72,75,68}, 12,1 , 2479,9 , 4,4 , 8,6 , 531,4 , 535,14 , 2, 1, 7, 6, 7 }, // Chinese/Traditional Han/HongKong - { 25, 6, 126, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 130,5 , 130,5 , 412,7 , 419,15 , 172,6 , 195,13 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 2011,21 , 1969,28 , 1997,14 , 2011,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {77,79,80}, 144,4 , 2509,10 , 4,4 , 4,0 , 531,4 , 549,14 , 2, 1, 7, 6, 7 }, // Chinese/Traditional Han/Macau - { 25, 6, 208, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 130,5 , 130,5 , 179,8 , 399,13 , 172,6 , 208,11 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 2011,21 , 1969,28 , 1997,14 , 2011,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {84,87,68}, 148,3 , 2519,10 , 4,4 , 4,0 , 531,4 , 563,2 , 2, 1, 7, 6, 7 }, // Chinese/Traditional Han/Taiwan - { 27, 7, 54, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 434,9 , 443,19 , 37,5 , 8,10 , 4467,49 , 4516,94 , 4610,39 , 4467,49 , 4649,98 , 4610,39 , 2032,28 , 2060,58 , 2118,14 , 2032,28 , 2060,58 , 2132,14 , 0,2 , 0,2 , {72,82,75}, 151,2 , 2529,74 , 25,5 , 4,0 , 565,8 , 573,8 , 2, 1, 1, 6, 7 }, // Croatian/Latin/Croatia - { 27, 7, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 434,9 , 443,19 , 37,5 , 8,10 , 4467,49 , 4516,94 , 4610,39 , 4467,49 , 4649,98 , 4610,39 , 2032,28 , 2060,58 , 2118,14 , 2032,28 , 2060,58 , 2132,14 , 0,2 , 0,2 , {66,65,77}, 153,2 , 2603,106 , 25,5 , 4,0 , 565,8 , 581,19 , 2, 1, 1, 6, 7 }, // Croatian/Latin/BosniaAndHerzegowina - { 28, 7, 57, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 135,7 , 135,7 , 187,8 , 462,18 , 61,4 , 219,9 , 4747,48 , 4795,82 , 4877,24 , 4747,48 , 4901,84 , 158,27 , 2146,21 , 2167,49 , 2216,14 , 2146,21 , 2167,49 , 2216,14 , 81,4 , 80,4 , {67,90,75}, 155,2 , 2709,56 , 25,5 , 4,0 , 600,7 , 607,15 , 2, 1, 1, 6, 7 }, // Czech/Latin/CzechRepublic - { 29, 7, 58, 44, 46, 44, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 27,8 , 480,23 , 144,5 , 149,10 , 4985,48 , 5033,84 , 134,24 , 5117,59 , 5033,84 , 134,24 , 2230,28 , 2258,51 , 2309,14 , 2323,35 , 2258,51 , 2309,14 , 0,2 , 0,2 , {68,75,75}, 157,2 , 2765,42 , 25,5 , 4,0 , 622,5 , 627,7 , 2, 1, 1, 6, 7 }, // Danish/Latin/Denmark - { 30, 7, 151, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2807,19 , 14,5 , 19,6 , 634,10 , 644,9 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Netherlands - { 30, 7, 12, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {65,87,71}, 159,4 , 2826,55 , 14,5 , 19,6 , 634,10 , 653,5 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Aruba - { 30, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 511,7 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2807,19 , 25,5 , 4,0 , 658,6 , 664,6 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Belgium - { 30, 7, 152, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {65,78,71}, 163,4 , 2881,97 , 14,5 , 19,6 , 634,10 , 670,7 , 2, 1, 1, 6, 7 }, // Dutch/Latin/CuraSao - { 30, 7, 202, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {83,82,68}, 12,1 , 2978,24 , 14,5 , 19,6 , 634,10 , 677,8 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Suriname - { 30, 7, 256, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {65,78,71}, 163,4 , 2881,97 , 14,5 , 19,6 , 634,10 , 685,12 , 2, 1, 1, 6, 7 }, // Dutch/Latin/SintMaarten - { 31, 7, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 697,12 , 709,13 , 2, 1, 7, 6, 7 }, // English/Latin/UnitedStates - { 31, 3, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 5371,80 , 5451,154 , 5605,36 , 5371,80 , 5451,154 , 5605,36 , 2452,49 , 2501,85 , 2586,21 , 2452,49 , 2501,85 , 2586,21 , 85,4 , 84,4 , {85,83,68}, 12,1 , 0,7 , 14,5 , 4,0 , 722,10 , 732,25 , 2, 1, 7, 6, 7 }, // English/Deseret/UnitedStates - { 31, 7, 4, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 764,14 , 2, 1, 7, 6, 7 }, // English/Latin/AmericanSamoa - { 31, 7, 9, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3037,71 , 4,4 , 8,6 , 757,7 , 778,19 , 2, 1, 7, 6, 7 }, // English/Latin/AntiguaAndBarbuda - { 31, 7, 13, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 511,7 , 10,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {65,85,68}, 12,1 , 3108,59 , 4,4 , 4,0 , 797,18 , 815,9 , 2, 1, 7, 6, 7 }, // English/Latin/Australia - { 31, 7, 16, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,83,68}, 12,1 , 3167,53 , 4,4 , 8,6 , 757,7 , 824,7 , 2, 1, 7, 6, 7 }, // English/Latin/Bahamas - { 31, 7, 19, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,66,68}, 12,1 , 3220,56 , 4,4 , 8,6 , 757,7 , 831,8 , 2, 1, 1, 6, 7 }, // English/Latin/Barbados - { 31, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 27,8 , 99,16 , 37,5 , 228,24 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {69,85,82}, 131,1 , 2807,19 , 25,5 , 4,0 , 757,7 , 839,7 , 2, 1, 1, 6, 7 }, // English/Latin/Belgium - { 31, 7, 22, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 27,8 , 524,12 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,90,68}, 12,1 , 3276,47 , 4,4 , 4,0 , 757,7 , 846,6 , 2, 1, 7, 6, 7 }, // English/Latin/Belize - { 31, 7, 24, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,77,68}, 12,1 , 3323,53 , 4,4 , 8,6 , 757,7 , 852,7 , 2, 1, 1, 6, 7 }, // English/Latin/Bermuda - { 31, 7, 28, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 27,8 , 82,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,87,80}, 170,1 , 3376,50 , 4,4 , 4,0 , 757,7 , 859,8 , 2, 1, 7, 6, 7 }, // English/Latin/Botswana - { 31, 7, 37, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,65,70}, 36,4 , 3426,50 , 4,4 , 8,6 , 757,7 , 867,8 , 0, 0, 1, 6, 7 }, // English/Latin/Cameroon - { 31, 7, 38, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {67,65,68}, 12,1 , 3476,53 , 4,4 , 8,6 , 875,16 , 891,6 , 2, 0, 7, 6, 7 }, // English/Latin/Canada - { 31, 7, 40, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {75,89,68}, 12,1 , 3529,71 , 4,4 , 8,6 , 757,7 , 897,14 , 2, 1, 1, 6, 7 }, // English/Latin/CaymanIslands - { 31, 7, 60, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3037,71 , 4,4 , 8,6 , 757,7 , 911,8 , 2, 1, 7, 6, 7 }, // English/Latin/Dominica - { 31, 7, 72, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {70,74,68}, 12,1 , 3600,47 , 4,4 , 8,6 , 757,7 , 919,4 , 2, 1, 1, 6, 7 }, // English/Latin/Fiji - { 31, 7, 75, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3647,47 , 4,4 , 4,0 , 757,7 , 923,8 , 2, 1, 1, 6, 7 }, // English/Latin/Guernsey - { 31, 7, 80, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {71,77,68}, 172,1 , 3694,50 , 4,4 , 8,6 , 757,7 , 931,6 , 2, 1, 1, 6, 7 }, // English/Latin/Gambia - { 31, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {71,72,83}, 173,3 , 3744,47 , 4,4 , 8,6 , 757,7 , 937,5 , 2, 1, 1, 6, 7 }, // English/Latin/Ghana - { 31, 7, 84, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,73,80}, 171,1 , 3791,53 , 4,4 , 4,0 , 757,7 , 942,9 , 2, 1, 1, 6, 7 }, // English/Latin/Gibraltar - { 31, 7, 87, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3037,71 , 4,4 , 8,6 , 757,7 , 951,7 , 2, 1, 1, 6, 7 }, // English/Latin/Grenada - { 31, 7, 89, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 958,4 , 2, 1, 7, 6, 7 }, // English/Latin/Guam - { 31, 7, 93, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {71,89,68}, 12,1 , 3844,56 , 4,4 , 8,6 , 757,7 , 962,6 , 0, 0, 1, 6, 7 }, // English/Latin/Guyana - { 31, 7, 97, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 287,6 , 224,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {72,75,68}, 12,1 , 3900,56 , 4,4 , 8,6 , 757,7 , 968,19 , 2, 1, 7, 6, 7 }, // English/Latin/HongKong - { 31, 7, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 27,8 , 99,16 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {73,78,82}, 122,1 , 3956,44 , 14,5 , 4,0 , 757,7 , 987,5 , 2, 1, 7, 7, 7 }, // English/Latin/India - { 31, 7, 104, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 99,16 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 75,4 , 74,4 , {69,85,82}, 131,1 , 2807,19 , 4,4 , 4,0 , 757,7 , 992,7 , 2, 1, 7, 6, 7 }, // English/Latin/Ireland - { 31, 7, 107, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 287,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {74,77,68}, 12,1 , 4000,53 , 4,4 , 4,0 , 757,7 , 999,7 , 2, 1, 7, 6, 7 }, // English/Latin/Jamaica - { 31, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {75,69,83}, 2,3 , 4053,53 , 4,4 , 8,6 , 757,7 , 1006,5 , 2, 1, 7, 6, 7 }, // English/Latin/Kenya - { 31, 7, 112, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {65,85,68}, 12,1 , 3108,59 , 4,4 , 8,6 , 757,7 , 1011,8 , 2, 1, 1, 6, 7 }, // English/Latin/Kiribati - { 31, 7, 120, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 4106,61 , 4,4 , 8,6 , 757,7 , 1019,7 , 2, 1, 1, 6, 7 }, // English/Latin/Lesotho - { 31, 7, 121, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {76,82,68}, 12,1 , 4167,53 , 4,4 , 8,6 , 757,7 , 1026,7 , 2, 1, 1, 6, 7 }, // English/Latin/Liberia - { 31, 7, 128, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {77,71,65}, 176,2 , 4220,54 , 4,4 , 8,6 , 757,7 , 1033,10 , 0, 0, 1, 6, 7 }, // English/Latin/Madagascar - { 31, 7, 129, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {77,87,75}, 178,2 , 4274,53 , 4,4 , 8,6 , 757,7 , 1043,6 , 2, 1, 1, 6, 7 }, // English/Latin/Malawi - { 31, 7, 133, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {69,85,82}, 131,1 , 2807,19 , 4,4 , 4,0 , 757,7 , 1049,5 , 2, 1, 7, 6, 7 }, // English/Latin/Malta - { 31, 7, 134, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1054,16 , 2, 1, 7, 6, 7 }, // English/Latin/MarshallIslands - { 31, 7, 137, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {77,85,82}, 180,2 , 4327,53 , 4,4 , 8,6 , 757,7 , 1070,9 , 0, 0, 1, 6, 7 }, // English/Latin/Mauritius - { 31, 7, 140, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1079,10 , 2, 1, 1, 6, 7 }, // English/Latin/Micronesia - { 31, 7, 148, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {78,65,68}, 12,1 , 4380,53 , 4,4 , 4,0 , 757,7 , 1089,7 , 2, 1, 1, 6, 7 }, // English/Latin/Namibia - { 31, 7, 154, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 511,7 , 10,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {78,90,68}, 12,1 , 4433,62 , 4,4 , 4,0 , 757,7 , 1096,11 , 2, 1, 7, 6, 7 }, // English/Latin/NewZealand - { 31, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {78,71,78}, 182,1 , 4495,50 , 4,4 , 8,6 , 757,7 , 1107,7 , 2, 1, 1, 6, 7 }, // English/Latin/Nigeria - { 31, 7, 160, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1114,24 , 2, 1, 1, 6, 7 }, // English/Latin/NorthernMarianaIslands - { 31, 7, 163, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 27,8 , 99,16 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {80,75,82}, 180,2 , 4545,53 , 14,5 , 4,0 , 757,7 , 1138,8 , 0, 0, 7, 6, 7 }, // English/Latin/Pakistan - { 31, 7, 164, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1146,5 , 2, 1, 1, 6, 7 }, // English/Latin/Palau - { 31, 7, 167, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {80,71,75}, 139,1 , 4598,73 , 4,4 , 8,6 , 757,7 , 1151,16 , 2, 1, 1, 6, 7 }, // English/Latin/PapuaNewGuinea - { 31, 7, 170, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {80,72,80}, 183,1 , 4671,42 , 4,4 , 8,6 , 757,7 , 1167,11 , 2, 1, 7, 6, 7 }, // English/Latin/Philippines - { 31, 7, 174, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1178,11 , 2, 1, 7, 6, 7 }, // English/Latin/PuertoRico - { 31, 7, 180, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3037,71 , 4,4 , 8,6 , 757,7 , 1189,21 , 2, 1, 1, 6, 7 }, // English/Latin/SaintKittsAndNevis - { 31, 7, 181, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3037,71 , 4,4 , 8,6 , 757,7 , 1210,11 , 2, 1, 1, 6, 7 }, // English/Latin/SaintLucia - { 31, 7, 182, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3037,71 , 4,4 , 8,6 , 757,7 , 1221,32 , 2, 1, 1, 6, 7 }, // English/Latin/SaintVincentAndTheGrenadines - { 31, 7, 183, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {87,83,84}, 184,3 , 4713,40 , 4,4 , 8,6 , 757,7 , 1253,5 , 2, 1, 7, 6, 7 }, // English/Latin/Samoa - { 31, 7, 188, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,67,82}, 187,2 , 4753,59 , 4,4 , 8,6 , 757,7 , 1258,10 , 2, 1, 1, 6, 7 }, // English/Latin/Seychelles - { 31, 7, 189, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,76,76}, 189,2 , 4812,68 , 4,4 , 8,6 , 757,7 , 1268,12 , 0, 0, 1, 6, 7 }, // English/Latin/SierraLeone - { 31, 7, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 287,6 , 224,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {83,71,68}, 12,1 , 4880,56 , 4,4 , 8,6 , 757,7 , 1280,9 , 2, 1, 7, 6, 7 }, // English/Latin/Singapore - { 31, 7, 193, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,66,68}, 12,1 , 4936,74 , 4,4 , 8,6 , 757,7 , 1289,15 , 2, 1, 1, 6, 7 }, // English/Latin/SolomonIslands - { 31, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 536,10 , 82,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 4106,61 , 4,4 , 8,6 , 757,7 , 1304,12 , 2, 1, 7, 6, 7 }, // English/Latin/SouthAfrica - { 31, 7, 204, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,90,76}, 191,1 , 5010,53 , 4,4 , 8,6 , 757,7 , 1316,9 , 2, 1, 1, 6, 7 }, // English/Latin/Swaziland - { 31, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {84,90,83}, 192,3 , 5063,62 , 4,4 , 8,6 , 757,7 , 1325,8 , 0, 0, 1, 6, 7 }, // English/Latin/Tanzania - { 31, 7, 214, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {84,79,80}, 195,2 , 5125,49 , 4,4 , 8,6 , 757,7 , 1333,5 , 2, 1, 1, 6, 7 }, // English/Latin/Tonga - { 31, 7, 215, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {84,84,68}, 12,1 , 5174,86 , 4,4 , 4,0 , 757,7 , 1338,19 , 2, 1, 7, 6, 7 }, // English/Latin/TrinidadAndTobago - { 31, 7, 219, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1357,24 , 2, 1, 1, 6, 7 }, // English/Latin/TurksAndCaicosIslands - { 31, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 5260,56 , 4,4 , 8,6 , 757,7 , 1381,6 , 0, 0, 1, 6, 7 }, // English/Latin/Uganda - { 31, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3647,47 , 4,4 , 4,0 , 1387,15 , 1402,14 , 2, 1, 1, 6, 7 }, // English/Latin/UnitedKingdom - { 31, 7, 226, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1416,21 , 2, 1, 7, 6, 7 }, // English/Latin/UnitedStatesMinorOutlyingIslands - { 31, 7, 229, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {86,85,86}, 200,2 , 5316,44 , 4,4 , 8,6 , 757,7 , 1437,7 , 0, 0, 1, 6, 7 }, // English/Latin/Vanuatu - { 31, 7, 233, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1444,22 , 2, 1, 1, 6, 7 }, // English/Latin/BritishVirginIslands - { 31, 7, 234, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3002,35 , 4,4 , 8,6 , 757,7 , 1466,19 , 2, 1, 7, 6, 7 }, // English/Latin/UnitedStatesVirginIslands - { 31, 7, 239, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {90,77,87}, 202,2 , 5360,50 , 4,4 , 8,6 , 757,7 , 1485,6 , 2, 1, 1, 6, 7 }, // English/Latin/Zambia - { 31, 7, 240, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 364,8 , 82,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 3002,35 , 4,4 , 4,0 , 757,7 , 1491,8 , 2, 1, 7, 6, 7 }, // English/Latin/Zimbabwe - { 31, 7, 251, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3647,47 , 4,4 , 4,0 , 757,7 , 1499,11 , 2, 1, 1, 6, 7 }, // English/Latin/IsleOfMan - { 31, 7, 252, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3647,47 , 4,4 , 4,0 , 757,7 , 1510,6 , 2, 1, 1, 6, 7 }, // English/Latin/Jersey - { 31, 7, 254, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,83,80}, 171,1 , 5410,68 , 4,4 , 8,6 , 757,7 , 1516,11 , 2, 1, 1, 6, 7 }, // English/Latin/SouthSudan - { 33, 7, 68, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 169,8 , 169,8 , 187,8 , 462,18 , 61,4 , 252,9 , 5641,59 , 5700,91 , 5791,24 , 5641,59 , 5700,91 , 5791,24 , 2607,14 , 2621,63 , 2607,14 , 2607,14 , 2621,63 , 2607,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 5478,20 , 25,5 , 30,7 , 1527,5 , 1532,5 , 2, 1, 1, 6, 7 }, // Estonian/Latin/Estonia - { 34, 7, 71, 44, 46, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 503,8 , 82,17 , 37,5 , 8,10 , 5815,48 , 5863,83 , 134,24 , 5815,48 , 5863,83 , 134,24 , 2684,28 , 2712,74 , 2786,14 , 2684,28 , 2712,74 , 2786,14 , 0,2 , 0,2 , {68,75,75}, 157,2 , 5498,42 , 4,4 , 43,5 , 1537,8 , 1545,7 , 2, 1, 1, 6, 7 }, // Faroese/Latin/FaroeIslands - { 36, 7, 73, 44, 160, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 169,8 , 169,8 , 546,8 , 554,17 , 159,4 , 163,9 , 5946,69 , 6015,105 , 6120,24 , 6144,129 , 6144,129 , 6120,24 , 2800,21 , 2821,67 , 2888,14 , 2800,21 , 2902,81 , 2888,14 , 91,3 , 90,3 , {69,85,82}, 131,1 , 5540,20 , 25,5 , 4,0 , 1552,5 , 1557,5 , 2, 1, 1, 6, 7 }, // Finnish/Latin/Finland - { 37, 7, 74, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1570,6 , 2, 1, 1, 6, 7 }, // French/Latin/France - { 37, 7, 3, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {68,90,68}, 207,2 , 5560,51 , 25,5 , 30,7 , 1562,8 , 1576,7 , 2, 1, 6, 4, 5 }, // French/Latin/Algeria - { 37, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 511,7 , 99,16 , 37,5 , 261,23 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1583,8 , 2, 1, 1, 6, 7 }, // French/Latin/Belgium - { 37, 7, 23, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5611,59 , 25,5 , 30,7 , 1562,8 , 1591,5 , 0, 0, 1, 6, 7 }, // French/Latin/Benin - { 37, 7, 34, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5611,59 , 25,5 , 30,7 , 1562,8 , 1596,12 , 0, 0, 1, 6, 7 }, // French/Latin/BurkinaFaso - { 37, 7, 35, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {66,73,70}, 212,3 , 5670,53 , 25,5 , 30,7 , 1562,8 , 1608,7 , 0, 0, 1, 6, 7 }, // French/Latin/Burundi - { 37, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 36,4 , 5723,56 , 25,5 , 30,7 , 1562,8 , 1615,8 , 0, 0, 1, 6, 7 }, // French/Latin/Cameroon - { 37, 7, 38, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 177,8 , 177,8 , 115,8 , 99,16 , 37,5 , 228,24 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {67,65,68}, 12,1 , 5779,54 , 25,5 , 30,7 , 1623,17 , 891,6 , 2, 0, 7, 6, 7 }, // French/Latin/Canada - { 37, 7, 41, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 36,4 , 5723,56 , 25,5 , 30,7 , 1562,8 , 1640,25 , 0, 0, 1, 6, 7 }, // French/Latin/CentralAfricanRepublic - { 37, 7, 42, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 36,4 , 5723,56 , 25,5 , 30,7 , 1562,8 , 1665,5 , 0, 0, 1, 6, 7 }, // French/Latin/Chad - { 37, 7, 48, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {75,77,70}, 215,2 , 5833,51 , 25,5 , 30,7 , 1562,8 , 1670,7 , 0, 0, 1, 6, 7 }, // French/Latin/Comoros - { 37, 7, 49, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {67,68,70}, 217,2 , 5884,53 , 25,5 , 30,7 , 1562,8 , 1677,32 , 2, 1, 1, 6, 7 }, // French/Latin/CongoKinshasa - { 37, 7, 50, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 36,4 , 5723,56 , 25,5 , 30,7 , 1562,8 , 1709,17 , 0, 0, 1, 6, 7 }, // French/Latin/CongoBrazzaville - { 37, 7, 53, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5611,59 , 25,5 , 30,7 , 1562,8 , 1726,13 , 0, 0, 1, 6, 7 }, // French/Latin/IvoryCoast - { 37, 7, 59, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {68,74,70}, 5,3 , 5937,57 , 25,5 , 30,7 , 1562,8 , 1739,8 , 0, 0, 6, 6, 7 }, // French/Latin/Djibouti - { 37, 7, 66, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 36,4 , 5723,56 , 25,5 , 30,7 , 1562,8 , 1747,18 , 0, 0, 1, 6, 7 }, // French/Latin/EquatorialGuinea - { 37, 7, 76, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1765,16 , 2, 1, 1, 6, 7 }, // French/Latin/FrenchGuiana - { 37, 7, 77, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,80,70}, 219,4 , 5994,35 , 25,5 , 30,7 , 1562,8 , 1781,19 , 0, 0, 1, 6, 7 }, // French/Latin/FrenchPolynesia - { 37, 7, 79, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 36,4 , 5723,56 , 25,5 , 30,7 , 1562,8 , 1800,5 , 0, 0, 1, 6, 7 }, // French/Latin/Gabon - { 37, 7, 88, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1805,10 , 2, 1, 1, 6, 7 }, // French/Latin/Guadeloupe - { 37, 7, 91, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {71,78,70}, 223,2 , 6029,48 , 25,5 , 30,7 , 1562,8 , 1815,6 , 0, 0, 1, 6, 7 }, // French/Latin/Guinea - { 37, 7, 94, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {72,84,71}, 225,1 , 6077,57 , 25,5 , 30,7 , 1562,8 , 1821,5 , 2, 1, 1, 6, 7 }, // French/Latin/Haiti - { 37, 7, 125, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1826,10 , 2, 1, 1, 6, 7 }, // French/Latin/Luxembourg - { 37, 7, 128, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,71,65}, 176,2 , 6134,54 , 25,5 , 30,7 , 1562,8 , 1033,10 , 0, 0, 1, 6, 7 }, // French/Latin/Madagascar - { 37, 7, 132, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5611,59 , 25,5 , 30,7 , 1562,8 , 1836,4 , 0, 0, 1, 6, 7 }, // French/Latin/Mali - { 37, 7, 135, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1840,10 , 2, 1, 1, 6, 7 }, // French/Latin/Martinique - { 37, 7, 136, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,82,79}, 226,2 , 6188,66 , 25,5 , 30,7 , 1562,8 , 1850,10 , 0, 0, 1, 6, 7 }, // French/Latin/Mauritania - { 37, 7, 137, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,85,82}, 180,2 , 6254,63 , 25,5 , 30,7 , 1562,8 , 1860,7 , 0, 0, 1, 6, 7 }, // French/Latin/Mauritius - { 37, 7, 138, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1867,7 , 2, 1, 1, 6, 7 }, // French/Latin/Mayotte - { 37, 7, 142, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1874,6 , 2, 1, 1, 6, 7 }, // French/Latin/Monaco - { 37, 7, 145, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,65,68}, 0,0 , 6317,54 , 25,5 , 30,7 , 1562,8 , 1880,5 , 2, 1, 6, 5, 6 }, // French/Latin/Morocco - { 37, 7, 153, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,80,70}, 219,4 , 5994,35 , 25,5 , 30,7 , 1562,8 , 1885,18 , 0, 0, 1, 6, 7 }, // French/Latin/NewCaledonia - { 37, 7, 156, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5611,59 , 25,5 , 30,7 , 1562,8 , 1903,5 , 0, 0, 1, 6, 7 }, // French/Latin/Niger - { 37, 7, 176, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1908,7 , 2, 1, 1, 6, 7 }, // French/Latin/Reunion - { 37, 7, 179, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {82,87,70}, 228,2 , 6371,50 , 25,5 , 30,7 , 1562,8 , 1915,6 , 0, 0, 1, 6, 7 }, // French/Latin/Rwanda - { 37, 7, 187, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5611,59 , 25,5 , 30,7 , 1562,8 , 1921,7 , 0, 0, 1, 6, 7 }, // French/Latin/Senegal - { 37, 7, 188, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {83,67,82}, 187,2 , 6421,71 , 25,5 , 30,7 , 1562,8 , 1258,10 , 2, 1, 1, 6, 7 }, // French/Latin/Seychelles - { 37, 7, 206, 46, 39, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 177,8 , 177,8 , 187,8 , 10,17 , 37,5 , 284,14 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {67,72,70}, 230,3 , 6492,45 , 14,5 , 48,5 , 1928,15 , 1943,6 , 2, 0, 1, 6, 7 }, // French/Latin/Switzerland - { 37, 7, 207, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {83,89,80}, 233,2 , 6537,51 , 25,5 , 30,7 , 1562,8 , 1949,5 , 0, 0, 6, 5, 6 }, // French/Latin/Syria - { 37, 7, 212, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5611,59 , 25,5 , 30,7 , 1562,8 , 1954,4 , 0, 0, 1, 6, 7 }, // French/Latin/Togo - { 37, 7, 216, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {84,78,68}, 235,2 , 6588,51 , 25,5 , 30,7 , 1562,8 , 1958,7 , 3, 0, 7, 5, 6 }, // French/Latin/Tunisia - { 37, 7, 229, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {86,85,86}, 200,2 , 6639,51 , 25,5 , 30,7 , 1562,8 , 1437,7 , 0, 0, 1, 6, 7 }, // French/Latin/Vanuatu - { 37, 7, 244, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1965,16 , 2, 1, 1, 6, 7 }, // French/Latin/Saint Barthelemy - { 37, 7, 245, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 30,7 , 1562,8 , 1981,31 , 2, 1, 1, 6, 7 }, // French/Latin/Saint Martin - { 39, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 185,11 , 196,10 , 141,10 , 10,17 , 37,5 , 8,10 , 6421,61 , 6482,142 , 6624,36 , 6421,61 , 6482,142 , 6624,36 , 3084,28 , 3112,69 , 3181,14 , 3084,28 , 3112,69 , 3181,14 , 0,2 , 0,2 , {71,66,80}, 171,1 , 6690,22 , 4,4 , 8,6 , 2012,8 , 2020,22 , 2, 1, 1, 6, 7 }, // Gaelic/Latin/UnitedKingdom - { 40, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 82,17 , 37,5 , 8,10 , 6660,48 , 6708,87 , 6795,24 , 6660,48 , 6708,87 , 6795,24 , 3195,28 , 3223,49 , 3272,14 , 3195,28 , 3223,49 , 3272,14 , 75,4 , 74,4 , {69,85,82}, 131,1 , 6712,20 , 4,4 , 8,6 , 2042,6 , 2048,6 , 2, 1, 1, 6, 7 }, // Galician/Latin/Spain - { 41, 15, 81, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8222, 8220, 0,6 , 0,6 , 213,8 , 213,8 , 187,8 , 571,19 , 37,5 , 8,10 , 6819,48 , 6867,99 , 6966,24 , 6819,48 , 6867,99 , 6966,24 , 3286,28 , 3314,62 , 3376,14 , 3286,28 , 3314,62 , 3376,14 , 0,2 , 0,2 , {71,69,76}, 0,0 , 6732,19 , 25,5 , 4,0 , 2054,7 , 2061,10 , 2, 1, 1, 6, 7 }, // Georgian/Georgian/Georgia - { 42, 7, 82, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 131,1 , 6751,19 , 25,5 , 4,0 , 2071,7 , 2078,11 , 2, 1, 1, 6, 7 }, // German/Latin/Germany - { 42, 7, 14, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 590,19 , 37,5 , 8,10 , 7180,48 , 7038,83 , 134,24 , 7228,58 , 7286,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 131,1 , 6751,19 , 14,5 , 4,0 , 2089,24 , 2113,10 , 2, 1, 1, 6, 7 }, // German/Latin/Austria - { 42, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 131,1 , 6751,19 , 25,5 , 4,0 , 2071,7 , 2123,7 , 2, 1, 1, 6, 7 }, // German/Latin/Belgium - { 42, 7, 123, 46, 39, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {67,72,70}, 0,0 , 6770,58 , 14,5 , 4,0 , 2071,7 , 2130,13 , 2, 0, 1, 6, 7 }, // German/Latin/Liechtenstein - { 42, 7, 125, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 131,1 , 6751,19 , 25,5 , 4,0 , 2071,7 , 2143,9 , 2, 1, 1, 6, 7 }, // German/Latin/Luxembourg - { 42, 7, 206, 46, 39, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {67,72,70}, 230,3 , 6770,58 , 14,5 , 48,5 , 2152,21 , 2173,7 , 2, 0, 1, 6, 7 }, // German/Latin/Switzerland - { 43, 16, 85, 44, 46, 44, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 230,9 , 230,9 , 287,6 , 10,17 , 18,7 , 25,12 , 7369,50 , 7419,115 , 7534,24 , 7558,50 , 7608,115 , 7534,24 , 3513,28 , 3541,55 , 3596,14 , 3513,28 , 3541,55 , 3596,14 , 99,4 , 99,4 , {69,85,82}, 131,1 , 6828,19 , 25,5 , 4,0 , 2180,8 , 2188,6 , 2, 1, 1, 6, 7 }, // Greek/Greek/Greece - { 43, 16, 56, 44, 46, 44, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 230,9 , 230,9 , 287,6 , 10,17 , 18,7 , 25,12 , 7369,50 , 7419,115 , 7534,24 , 7558,50 , 7608,115 , 7534,24 , 3513,28 , 3541,55 , 3596,14 , 3513,28 , 3541,55 , 3596,14 , 99,4 , 99,4 , {69,85,82}, 131,1 , 6828,19 , 4,4 , 4,0 , 2180,8 , 2194,6 , 2, 1, 1, 6, 7 }, // Greek/Greek/Cyprus - { 44, 7, 86, 44, 46, 59, 37, 48, 8722, 43, 101, 187, 171, 8250, 8249, 0,6 , 0,6 , 239,11 , 239,11 , 72,10 , 82,17 , 18,7 , 25,12 , 4985,48 , 7723,96 , 134,24 , 4985,48 , 7723,96 , 134,24 , 3610,28 , 3638,98 , 3736,14 , 3610,28 , 3638,98 , 3736,14 , 0,2 , 0,2 , {68,75,75}, 157,2 , 6847,59 , 4,4 , 43,5 , 2200,11 , 2211,16 , 2, 1, 1, 6, 7 }, // Greenlandic/Latin/Greenland - { 46, 17, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 250,9 , 250,9 , 609,7 , 224,18 , 298,8 , 306,13 , 7819,64 , 7883,87 , 7970,31 , 8001,67 , 8068,87 , 7970,31 , 3750,32 , 3782,53 , 3835,19 , 3750,32 , 3782,53 , 3835,19 , 0,2 , 0,2 , {73,78,82}, 122,1 , 6906,20 , 4,4 , 8,6 , 2227,7 , 2234,4 , 2, 1, 7, 7, 7 }, // Gujarati/Gujarati/India - { 47, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 224,18 , 37,5 , 8,10 , 8155,48 , 8203,85 , 8288,24 , 8155,48 , 8203,85 , 8288,24 , 3854,21 , 3875,52 , 3927,14 , 3854,21 , 3875,52 , 3927,14 , 0,2 , 0,2 , {78,71,78}, 182,1 , 6926,12 , 14,5 , 4,0 , 2238,5 , 2243,8 , 2, 1, 1, 6, 7 }, // Hausa/Latin/Nigeria - { 47, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 224,18 , 37,5 , 8,10 , 8155,48 , 8203,85 , 8288,24 , 8155,48 , 8203,85 , 8288,24 , 3854,21 , 3875,52 , 3927,14 , 3854,21 , 3875,52 , 3927,14 , 0,2 , 0,2 , {71,72,83}, 173,3 , 0,7 , 14,5 , 4,0 , 2238,5 , 2251,4 , 2, 1, 1, 6, 7 }, // Hausa/Latin/Ghana - { 47, 7, 156, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 224,18 , 37,5 , 8,10 , 8155,48 , 8203,85 , 8288,24 , 8155,48 , 8203,85 , 8288,24 , 3854,21 , 3875,52 , 3927,14 , 3854,21 , 3875,52 , 3927,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 6938,36 , 14,5 , 4,0 , 2238,5 , 2255,5 , 0, 0, 1, 6, 7 }, // Hausa/Latin/Niger - { 48, 18, 105, 46, 44, 59, 37, 48, 45, 43, 101, 34, 34, 39, 39, 0,6 , 0,6 , 259,6 , 259,6 , 27,8 , 616,18 , 37,5 , 8,10 , 8312,58 , 8370,72 , 158,27 , 8442,48 , 8370,72 , 158,27 , 3941,46 , 3987,65 , 4052,19 , 3941,46 , 3987,65 , 4071,21 , 103,6 , 103,5 , {73,76,83}, 52,1 , 6974,54 , 25,5 , 4,0 , 2260,5 , 2265,5 , 2, 1, 7, 5, 6 }, // Hebrew/Hebrew/Israel - { 49, 13, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 265,9 , 274,8 , 634,6 , 10,17 , 18,7 , 25,12 , 8490,75 , 8490,75 , 8565,30 , 8490,75 , 8490,75 , 8565,30 , 4092,38 , 4130,57 , 4187,19 , 4092,38 , 4130,57 , 4187,19 , 109,9 , 108,7 , {73,78,82}, 122,1 , 7028,19 , 14,5 , 4,0 , 2270,6 , 2276,4 , 2, 1, 7, 7, 7 }, // Hindi/Devanagari/India - { 50, 7, 98, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 187, 171, 0,6 , 0,6 , 282,8 , 282,8 , 640,11 , 651,19 , 61,4 , 219,9 , 8595,64 , 8659,98 , 8757,25 , 8595,64 , 8659,98 , 8782,25 , 4206,19 , 4225,52 , 4277,17 , 4206,19 , 4225,52 , 4277,17 , 118,3 , 115,3 , {72,85,70}, 237,2 , 7047,20 , 25,5 , 4,0 , 2280,6 , 2286,12 , 0, 0, 1, 6, 7 }, // Hungarian/Latin/Hungary - { 51, 7, 99, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 142,8 , 142,8 , 546,8 , 462,18 , 37,5 , 8,10 , 8807,48 , 8855,82 , 8937,24 , 8807,48 , 8855,82 , 8961,24 , 4294,28 , 4322,81 , 4403,14 , 4294,28 , 4322,81 , 4417,14 , 121,4 , 118,4 , {73,83,75}, 157,2 , 7067,49 , 4,4 , 8,6 , 2298,8 , 2306,6 , 0, 0, 1, 6, 7 }, // Icelandic/Latin/Iceland - { 52, 7, 101, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 27,8 , 123,18 , 144,5 , 149,10 , 8985,48 , 9033,87 , 134,24 , 8985,48 , 9033,87 , 134,24 , 4431,28 , 4459,43 , 4502,14 , 4431,28 , 4459,43 , 4502,14 , 0,2 , 0,2 , {73,68,82}, 239,2 , 7116,23 , 4,4 , 4,0 , 2312,16 , 2328,9 , 0, 0, 7, 6, 7 }, // Indonesian/Latin/Indonesia - { 53, 7, 74, 44, 46, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 9120,48 , 9168,93 , 158,27 , 9120,48 , 9168,93 , 158,27 , 4516,28 , 4544,57 , 85,14 , 4516,28 , 4544,57 , 85,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 7139,12 , 14,5 , 4,0 , 2337,11 , 2348,7 , 2, 1, 1, 6, 7 }, // Interlingua/Latin/France - { 57, 7, 104, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 99,16 , 37,5 , 8,10 , 9261,62 , 9323,107 , 9430,24 , 9261,62 , 9323,107 , 9430,24 , 4601,37 , 4638,75 , 4713,14 , 4601,37 , 4638,75 , 4713,14 , 75,4 , 74,4 , {69,85,82}, 131,1 , 7151,11 , 4,4 , 4,0 , 2355,7 , 2362,4 , 2, 1, 7, 6, 7 }, // Irish/Latin/Ireland - { 58, 7, 106, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 309,8 , 206,7 , 27,8 , 99,16 , 37,5 , 8,10 , 9454,48 , 9502,94 , 9596,24 , 9454,48 , 9620,94 , 9596,24 , 4727,28 , 4755,57 , 4812,14 , 4727,28 , 4826,57 , 4812,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2807,19 , 14,5 , 4,0 , 2366,8 , 2374,6 , 2, 1, 1, 6, 7 }, // Italian/Latin/Italy - { 58, 7, 184, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 309,8 , 206,7 , 27,8 , 99,16 , 37,5 , 8,10 , 9454,48 , 9502,94 , 9596,24 , 9454,48 , 9620,94 , 9596,24 , 4727,28 , 4755,57 , 4812,14 , 4727,28 , 4826,57 , 4812,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2807,19 , 14,5 , 4,0 , 2366,8 , 2380,10 , 2, 1, 1, 6, 7 }, // Italian/Latin/SanMarino - { 58, 7, 206, 46, 39, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 309,8 , 206,7 , 187,8 , 10,17 , 37,5 , 284,14 , 9454,48 , 9502,94 , 9596,24 , 9454,48 , 9620,94 , 9596,24 , 4727,28 , 4755,57 , 4812,14 , 4727,28 , 4826,57 , 4812,14 , 0,2 , 0,2 , {67,72,70}, 230,3 , 7162,53 , 14,5 , 48,5 , 2366,8 , 2390,8 , 2, 0, 1, 6, 7 }, // Italian/Latin/Switzerland - { 59, 19, 108, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 125,5 , 125,5 , 536,10 , 399,13 , 61,4 , 319,10 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 4883,14 , 4897,28 , 4883,14 , 4883,14 , 4897,28 , 4883,14 , 125,2 , 122,2 , {74,80,89}, 143,1 , 7215,10 , 4,4 , 4,0 , 2398,3 , 2401,2 , 0, 0, 7, 6, 7 }, // Japanese/Japanese/Japan - { 61, 21, 100, 46, 44, 59, 37, 48, 45, 43, 3208, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 317,12 , 329,11 , 634,6 , 99,16 , 298,8 , 306,13 , 9714,91 , 9805,86 , 9891,31 , 9714,91 , 9805,86 , 9922,31 , 4925,28 , 4953,53 , 5006,19 , 4925,28 , 4953,53 , 5006,19 , 0,2 , 0,2 , {73,78,82}, 122,1 , 7225,20 , 4,4 , 8,6 , 2403,5 , 2408,4 , 2, 1, 7, 7, 7 }, // Kannada/Kannada/India - { 62, 1, 100, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 518,6 , 35,18 , 18,7 , 25,12 , 9953,72 , 9953,72 , 10025,24 , 9953,72 , 9953,72 , 10025,24 , 5025,54 , 5079,56 , 5135,14 , 5025,54 , 5079,56 , 5135,14 , 0,2 , 0,2 , {73,78,82}, 122,1 , 7245,23 , 14,5 , 4,0 , 2412,5 , 2417,10 , 2, 1, 7, 7, 7 }, // Kashmiri/Arabic/India - { 63, 2, 110, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 187,8 , 670,22 , 37,5 , 8,10 , 10049,61 , 10110,83 , 158,27 , 10049,61 , 10110,83 , 158,27 , 5149,28 , 5177,54 , 85,14 , 5149,28 , 5177,54 , 85,14 , 0,2 , 0,2 , {75,90,84}, 241,1 , 7268,24 , 25,5 , 4,0 , 2427,10 , 2437,9 , 2, 1, 1, 6, 7 }, // Kazakh/Cyrillic/Kazakhstan - { 64, 7, 179, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 10193,60 , 10253,101 , 158,27 , 10193,60 , 10253,101 , 158,27 , 5231,35 , 5266,84 , 85,14 , 5231,35 , 5266,84 , 85,14 , 0,2 , 0,2 , {82,87,70}, 228,2 , 0,7 , 14,5 , 4,0 , 2446,11 , 1915,6 , 0, 0, 1, 6, 7 }, // Kinyarwanda/Latin/Rwanda - { 65, 2, 116, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 0,6 , 0,6 , 187,8 , 670,22 , 37,5 , 8,10 , 10354,60 , 10414,80 , 158,27 , 10494,59 , 10553,80 , 158,27 , 5350,28 , 5378,57 , 85,14 , 5435,28 , 5463,57 , 85,14 , 0,2 , 0,2 , {75,71,83}, 242,3 , 0,7 , 14,5 , 4,0 , 2457,6 , 2463,10 , 2, 1, 1, 6, 7 }, // Kirghiz/Cyrillic/Kyrgyzstan - { 66, 22, 114, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 340,7 , 340,7 , 692,9 , 701,16 , 329,7 , 336,13 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 5520,14 , 5534,28 , 5520,14 , 5520,14 , 5534,28 , 5520,14 , 127,2 , 124,2 , {75,82,87}, 245,1 , 7292,13 , 4,4 , 8,6 , 2473,3 , 2476,4 , 0, 0, 7, 6, 7 }, // Korean/Korean/SouthKorea - { 66, 22, 113, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 340,7 , 340,7 , 692,9 , 701,16 , 329,7 , 336,13 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 5520,14 , 5534,28 , 5520,14 , 5520,14 , 5534,28 , 5520,14 , 127,2 , 124,2 , {75,80,87}, 0,0 , 7305,23 , 4,4 , 8,6 , 2473,3 , 2480,14 , 0, 0, 1, 6, 7 }, // Korean/Korean/NorthKorea - { 68, 7, 35, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 10672,60 , 10732,106 , 158,27 , 10672,60 , 10732,106 , 158,27 , 5562,34 , 5596,89 , 85,14 , 5562,34 , 5596,89 , 85,14 , 129,5 , 126,5 , {66,73,70}, 212,3 , 7328,27 , 0,4 , 4,0 , 2494,8 , 2502,8 , 0, 0, 1, 6, 7 }, // Rundi/Latin/Burundi - { 69, 23, 117, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 717,18 , 61,4 , 349,24 , 10838,62 , 10900,75 , 158,27 , 10975,61 , 10900,75 , 158,27 , 5685,23 , 5708,57 , 5765,18 , 5783,24 , 5708,57 , 1765,14 , 134,8 , 131,8 , {76,65,75}, 246,1 , 7355,14 , 4,4 , 48,5 , 2510,3 , 2513,9 , 0, 0, 7, 6, 7 }, // Lao/Lao/Laos - { 71, 7, 118, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 347,8 , 347,8 , 187,8 , 735,26 , 37,5 , 8,10 , 11036,65 , 11101,101 , 134,24 , 11202,65 , 11267,101 , 134,24 , 5807,21 , 5828,72 , 5900,14 , 5807,21 , 5914,72 , 5900,14 , 142,14 , 139,11 , {76,86,76}, 247,2 , 7369,59 , 4,4 , 8,6 , 2522,8 , 2530,7 , 2, 1, 1, 6, 7 }, // Latvian/Latin/Latvia - { 72, 7, 49, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {67,68,70}, 217,2 , 7428,23 , 25,5 , 4,0 , 2537,7 , 2544,29 , 2, 1, 1, 6, 7 }, // Lingala/Latin/CongoKinshasa - { 72, 7, 6, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {65,79,65}, 249,2 , 7451,23 , 25,5 , 4,0 , 2537,7 , 2573,6 , 2, 1, 1, 6, 7 }, // Lingala/Latin/Angola - { 72, 7, 41, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {88,65,70}, 36,4 , 7474,23 , 25,5 , 4,0 , 2537,7 , 2579,26 , 0, 0, 1, 6, 7 }, // Lingala/Latin/CentralAfricanRepublic - { 72, 7, 50, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {88,65,70}, 36,4 , 7474,23 , 25,5 , 4,0 , 2537,7 , 2605,5 , 0, 0, 1, 6, 7 }, // Lingala/Latin/CongoBrazzaville - { 73, 7, 124, 44, 160, 59, 37, 48, 8211, 43, 101, 8222, 8220, 8222, 8220, 0,6 , 0,6 , 364,8 , 364,8 , 72,10 , 761,27 , 37,5 , 8,10 , 11643,70 , 11713,96 , 11809,24 , 11643,70 , 11713,96 , 11809,24 , 6128,21 , 6149,89 , 6238,14 , 6128,21 , 6149,89 , 6238,14 , 164,9 , 156,6 , {76,84,76}, 251,2 , 7497,62 , 25,5 , 4,0 , 2610,8 , 2618,7 , 2, 1, 1, 6, 7 }, // Lithuanian/Latin/Lithuania - { 74, 2, 127, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 0,6 , 0,6 , 788,7 , 123,18 , 37,5 , 8,10 , 11833,63 , 11896,85 , 11981,24 , 11833,63 , 11896,85 , 11981,24 , 6252,34 , 6286,54 , 1521,14 , 6252,34 , 6286,54 , 1521,14 , 173,10 , 162,8 , {77,75,68}, 253,3 , 7559,23 , 14,5 , 4,0 , 2625,10 , 2635,10 , 2, 1, 1, 6, 7 }, // Macedonian/Cyrillic/Macedonia - { 75, 7, 128, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 12005,48 , 12053,92 , 134,24 , 12005,48 , 12053,92 , 134,24 , 6340,34 , 6374,60 , 6434,14 , 6340,34 , 6374,60 , 6434,14 , 0,2 , 0,2 , {77,71,65}, 176,2 , 7582,13 , 4,4 , 4,0 , 2645,8 , 2653,12 , 0, 0, 1, 6, 7 }, // Malagasy/Latin/Madagascar - { 76, 7, 130, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 511,7 , 10,17 , 18,7 , 25,12 , 12145,49 , 12194,82 , 12276,24 , 12145,49 , 12194,82 , 12276,24 , 6448,28 , 6476,43 , 6519,14 , 6448,28 , 6476,43 , 6519,14 , 183,2 , 170,3 , {77,89,82}, 256,2 , 7595,23 , 4,4 , 8,6 , 2665,13 , 2678,8 , 2, 1, 1, 6, 7 }, // Malay/Latin/Malaysia - { 76, 7, 32, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 511,7 , 524,12 , 18,7 , 25,12 , 12145,49 , 12194,82 , 12276,24 , 12145,49 , 12194,82 , 12276,24 , 6448,28 , 6476,43 , 6519,14 , 6448,28 , 6476,43 , 6519,14 , 183,2 , 170,3 , {66,78,68}, 12,1 , 7618,19 , 14,5 , 4,0 , 2665,13 , 2686,6 , 2, 1, 1, 6, 7 }, // Malay/Latin/Brunei - { 76, 7, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 511,7 , 10,17 , 18,7 , 25,12 , 12145,49 , 12194,82 , 12276,24 , 12145,49 , 12194,82 , 12276,24 , 6448,28 , 6476,43 , 6519,14 , 6448,28 , 6476,43 , 6519,14 , 183,2 , 170,3 , {83,71,68}, 12,1 , 7637,22 , 4,4 , 8,6 , 2665,13 , 2692,9 , 2, 1, 7, 6, 7 }, // Malay/Latin/Singapore - { 77, 24, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 372,13 , 385,12 , 27,8 , 795,18 , 18,7 , 25,12 , 12300,62 , 12362,87 , 12449,31 , 12300,62 , 12362,87 , 12449,31 , 6533,41 , 6574,70 , 6644,22 , 6533,41 , 6574,70 , 6644,22 , 0,2 , 0,2 , {73,78,82}, 122,1 , 7659,40 , 0,4 , 4,0 , 2701,6 , 2707,6 , 2, 1, 7, 7, 7 }, // Malayalam/Malayalam/India - { 78, 7, 133, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 397,8 , 405,7 , 141,10 , 813,23 , 37,5 , 8,10 , 12480,48 , 12528,86 , 12614,24 , 12480,48 , 12528,86 , 12614,24 , 6666,28 , 6694,63 , 6757,14 , 6666,28 , 6694,63 , 6757,14 , 185,2 , 173,2 , {69,85,82}, 131,1 , 7699,11 , 4,4 , 4,0 , 2713,5 , 1049,5 , 2, 1, 7, 6, 7 }, // Maltese/Latin/Malta - { 80, 13, 100, 46, 44, 59, 37, 2406, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 412,9 , 412,9 , 634,6 , 99,16 , 373,7 , 380,12 , 12638,66 , 12704,86 , 12790,32 , 12638,66 , 12704,86 , 12790,32 , 6771,32 , 6803,53 , 4187,19 , 6771,32 , 6803,53 , 4187,19 , 0,2 , 0,2 , {73,78,82}, 122,1 , 7710,19 , 4,4 , 8,6 , 2718,5 , 2276,4 , 2, 1, 7, 7, 7 }, // Marathi/Devanagari/India - { 82, 2, 143, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 836,31 , 37,5 , 8,10 , 12822,48 , 12870,66 , 158,27 , 12822,48 , 12870,66 , 158,27 , 6856,21 , 6877,43 , 1765,14 , 6856,21 , 6877,43 , 1765,14 , 187,2 , 175,2 , {77,78,84}, 258,1 , 7729,25 , 14,5 , 4,0 , 2723,6 , 2729,6 , 0, 0, 1, 6, 7 }, // Mongolian/Cyrillic/Mongolia - { 84, 13, 150, 46, 44, 59, 37, 2406, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 12936,56 , 12992,85 , 13077,27 , 12936,56 , 12992,85 , 13077,27 , 6920,33 , 6953,54 , 7007,14 , 6920,33 , 6953,54 , 7007,14 , 189,14 , 177,14 , {78,80,82}, 259,4 , 7754,52 , 14,5 , 4,0 , 2735,6 , 2741,5 , 2, 1, 7, 6, 7 }, // Nepali/Devanagari/Nepal - { 84, 13, 100, 46, 44, 59, 37, 2406, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 12936,56 , 12992,85 , 13077,27 , 12936,56 , 13104,80 , 13077,27 , 6920,33 , 6953,54 , 7007,14 , 6920,33 , 7021,54 , 7007,14 , 109,9 , 108,7 , {73,78,82}, 122,1 , 7806,49 , 14,5 , 4,0 , 2735,6 , 2276,4 , 2, 1, 7, 7, 7 }, // Nepali/Devanagari/India - { 85, 7, 161, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 187,8 , 554,17 , 37,5 , 392,16 , 5815,48 , 13184,83 , 134,24 , 13267,59 , 13184,83 , 134,24 , 7075,28 , 2258,51 , 2309,14 , 2323,35 , 2258,51 , 2309,14 , 0,2 , 0,2 , {78,79,75}, 157,2 , 7855,44 , 14,5 , 4,0 , 2746,12 , 2758,5 , 2, 1, 1, 6, 7 }, // NorwegianBokmal/Latin/Norway - { 87, 26, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 634,6 , 10,17 , 18,7 , 25,12 , 13326,89 , 13326,89 , 13415,32 , 13326,89 , 13326,89 , 13415,32 , 7103,33 , 7136,54 , 7190,18 , 7103,33 , 7136,54 , 7190,18 , 89,2 , 88,2 , {73,78,82}, 122,1 , 7899,11 , 14,5 , 4,0 , 2763,5 , 2768,4 , 2, 1, 7, 7, 7 }, // Oriya/Oriya/India - { 88, 1, 1, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 179,8 , 867,20 , 61,4 , 408,11 , 13447,68 , 13447,68 , 158,27 , 13447,68 , 13447,68 , 158,27 , 7208,49 , 7208,49 , 85,14 , 7208,49 , 7208,49 , 85,14 , 203,4 , 191,4 , {65,70,78}, 263,1 , 7910,13 , 25,5 , 4,0 , 2772,4 , 2776,9 , 0, 0, 6, 4, 5 }, // Pashto/Arabic/Afghanistan - { 89, 1, 102, 1643, 1644, 1563, 1642, 1776, 8722, 43, 101, 171, 187, 8249, 8250, 421,7 , 421,7 , 43,8 , 51,7 , 179,8 , 99,16 , 61,4 , 408,11 , 13515,70 , 13515,70 , 13585,24 , 13609,74 , 13609,74 , 13585,24 , 7208,49 , 7208,49 , 7257,14 , 7208,49 , 7208,49 , 7257,14 , 207,9 , 195,8 , {73,82,82}, 264,1 , 7923,17 , 53,5 , 58,7 , 2785,5 , 2790,5 , 0, 0, 6, 4, 5 }, // Persian/Arabic/Iran - { 89, 1, 1, 1643, 1644, 1563, 1642, 1776, 8722, 43, 101, 171, 187, 8249, 8250, 421,7 , 421,7 , 43,8 , 51,7 , 179,8 , 99,16 , 61,4 , 408,11 , 13515,70 , 13515,70 , 13683,24 , 13707,64 , 13771,68 , 13585,24 , 7208,49 , 7208,49 , 7257,14 , 7208,49 , 7208,49 , 7257,14 , 207,9 , 195,8 , {65,70,78}, 263,1 , 7940,23 , 53,5 , 58,7 , 2795,3 , 2776,9 , 0, 0, 6, 4, 5 }, // Persian/Arabic/Afghanistan - { 90, 7, 172, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 118,7 , 118,7 , 887,10 , 10,17 , 37,5 , 8,10 , 13839,48 , 13887,97 , 13984,24 , 13839,48 , 14008,99 , 13984,24 , 7271,34 , 7305,59 , 7364,14 , 7271,34 , 7305,59 , 7364,14 , 0,2 , 0,2 , {80,76,78}, 265,2 , 7963,77 , 25,5 , 30,7 , 2798,6 , 2804,6 , 2, 1, 1, 6, 7 }, // Polish/Latin/Poland - { 91, 7, 30, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14107,48 , 14155,89 , 134,24 , 14107,48 , 14155,89 , 134,24 , 7378,28 , 7406,79 , 7485,14 , 7378,28 , 7406,79 , 7485,14 , 0,2 , 0,2 , {66,82,76}, 267,2 , 8040,54 , 4,4 , 8,6 , 2810,19 , 2829,6 , 2, 1, 7, 6, 7 }, // Portuguese/Latin/Brazil - { 91, 7, 6, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {65,79,65}, 249,2 , 8094,54 , 25,5 , 4,0 , 2835,9 , 2844,6 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/Angola - { 91, 7, 39, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {67,86,69}, 0,0 , 8148,69 , 25,5 , 4,0 , 2835,9 , 2850,10 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/CapeVerde - { 91, 7, 62, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 8217,81 , 25,5 , 4,0 , 2835,9 , 2860,11 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/EastTimor - { 91, 7, 92, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 8298,62 , 25,5 , 4,0 , 2835,9 , 2871,12 , 0, 0, 1, 6, 7 }, // Portuguese/Latin/GuineaBissau - { 91, 7, 126, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {77,79,80}, 144,4 , 8360,53 , 25,5 , 4,0 , 2835,9 , 2883,19 , 2, 1, 7, 6, 7 }, // Portuguese/Latin/Macau - { 91, 7, 146, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {77,90,78}, 269,3 , 8413,72 , 25,5 , 4,0 , 2835,9 , 2902,10 , 2, 1, 7, 6, 7 }, // Portuguese/Latin/Mozambique - { 91, 7, 173, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 8485,20 , 25,5 , 4,0 , 2912,17 , 2929,8 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/Portugal - { 91, 7, 185, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {83,84,68}, 272,2 , 8505,92 , 25,5 , 4,0 , 2835,9 , 2937,19 , 0, 0, 1, 6, 7 }, // Portuguese/Latin/SaoTomeAndPrincipe - { 92, 4, 100, 46, 44, 59, 37, 48, 45, 43, 101, 39, 39, 34, 34, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 123,18 , 18,7 , 25,12 , 14381,68 , 14381,68 , 14449,27 , 14381,68 , 14381,68 , 14449,27 , 7578,38 , 7616,55 , 7671,23 , 7578,38 , 7616,55 , 7671,23 , 216,11 , 203,11 , {73,78,82}, 122,1 , 8597,12 , 14,5 , 4,0 , 2956,6 , 2962,4 , 2, 1, 7, 7, 7 }, // Punjabi/Gurmukhi/India - { 92, 1, 163, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 123,18 , 18,7 , 25,12 , 14476,67 , 14476,67 , 158,27 , 14476,67 , 14476,67 , 158,27 , 7694,37 , 7694,37 , 85,14 , 7694,37 , 7694,37 , 85,14 , 0,2 , 0,2 , {80,75,82}, 274,1 , 8609,13 , 14,5 , 4,0 , 2966,5 , 2971,6 , 0, 0, 7, 6, 7 }, // Punjabi/Arabic/Pakistan - { 94, 7, 206, 46, 8217, 59, 37, 48, 8722, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 503,8 , 924,28 , 37,5 , 8,10 , 14543,67 , 14610,92 , 14702,24 , 14543,67 , 14610,92 , 14702,24 , 7731,23 , 7754,56 , 7810,14 , 7731,23 , 7754,56 , 7810,14 , 89,2 , 214,2 , {67,72,70}, 230,3 , 8622,20 , 25,5 , 4,0 , 2977,9 , 2986,6 , 2, 0, 1, 6, 7 }, // Romansh/Latin/Switzerland - { 95, 7, 177, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 428,8 , 428,8 , 887,10 , 10,17 , 37,5 , 8,10 , 14726,60 , 14786,98 , 14884,24 , 14726,60 , 14786,98 , 14884,24 , 7824,21 , 7845,48 , 3070,14 , 7824,21 , 7845,48 , 3070,14 , 0,2 , 0,2 , {82,79,78}, 0,0 , 8642,57 , 25,5 , 4,0 , 2992,6 , 2998,7 , 2, 1, 1, 6, 7 }, // Romanian/Latin/Romania - { 95, 7, 141, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 428,8 , 428,8 , 887,10 , 10,17 , 37,5 , 8,10 , 14726,60 , 14786,98 , 14884,24 , 14726,60 , 14786,98 , 14884,24 , 7824,21 , 7845,48 , 3070,14 , 7824,21 , 7845,48 , 3070,14 , 0,2 , 0,2 , {77,68,76}, 0,0 , 8699,69 , 25,5 , 4,0 , 2992,6 , 3005,17 , 2, 1, 1, 6, 7 }, // Romanian/Latin/Moldova - { 96, 2, 178, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {82,85,66}, 275,4 , 8768,89 , 25,5 , 4,0 , 3022,7 , 3029,6 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Russia - { 96, 2, 20, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {66,89,82}, 140,2 , 8857,94 , 25,5 , 4,0 , 3022,7 , 464,8 , 0, 0, 7, 6, 7 }, // Russian/Cyrillic/Belarus - { 96, 2, 110, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {75,90,84}, 241,1 , 8951,83 , 25,5 , 4,0 , 3022,7 , 3035,9 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Kazakhstan - { 96, 2, 116, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {75,71,83}, 242,3 , 9034,81 , 25,5 , 4,0 , 3022,7 , 3044,8 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Kyrgyzstan - { 96, 2, 141, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {77,68,76}, 0,0 , 9115,79 , 25,5 , 4,0 , 3022,7 , 3052,7 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Moldova - { 96, 2, 222, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 37,5 , 8,10 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {85,65,72}, 279,1 , 9194,92 , 25,5 , 4,0 , 3022,7 , 3059,7 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Ukraine - { 98, 7, 41, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 15139,48 , 15187,91 , 15278,24 , 15139,48 , 15187,91 , 15278,24 , 8073,28 , 8101,66 , 8167,14 , 8073,28 , 8101,66 , 8167,14 , 237,2 , 229,2 , {88,65,70}, 36,4 , 9286,25 , 4,4 , 48,5 , 3066,5 , 3071,22 , 0, 0, 1, 6, 7 }, // Sango/Latin/CentralAfricanRepublic - { 100, 2, 243, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15302,48 , 15350,81 , 11981,24 , 15302,48 , 15350,81 , 11981,24 , 8181,28 , 8209,52 , 8261,14 , 8181,28 , 8209,52 , 8261,14 , 239,9 , 231,7 , {82,83,68}, 280,4 , 9311,72 , 25,5 , 4,0 , 3093,6 , 3099,6 , 0, 0, 1, 6, 7 }, // Serbian/Cyrillic/Serbia - { 100, 2, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 115,8 , 981,20 , 37,5 , 419,40 , 15302,48 , 15350,81 , 11981,24 , 15302,48 , 15431,83 , 11981,24 , 8181,28 , 8209,52 , 8261,14 , 8275,28 , 8303,54 , 8261,14 , 239,9 , 231,7 , {66,65,77}, 284,2 , 9383,196 , 25,5 , 4,0 , 3105,6 , 3111,19 , 2, 1, 1, 6, 7 }, // Serbian/Cyrillic/BosniaAndHerzegowina - { 100, 2, 242, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15302,48 , 15350,81 , 11981,24 , 15302,48 , 15350,81 , 11981,24 , 8181,28 , 8209,52 , 8261,14 , 8181,28 , 8209,52 , 8261,14 , 239,9 , 231,7 , {69,85,82}, 131,1 , 9579,27 , 25,5 , 4,0 , 3093,6 , 3130,9 , 2, 1, 1, 6, 7 }, // Serbian/Cyrillic/Montenegro - { 100, 7, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15514,48 , 15562,81 , 15643,24 , 15514,48 , 15562,81 , 15643,24 , 8357,28 , 8385,54 , 2118,14 , 8357,28 , 8385,54 , 2118,14 , 248,9 , 238,7 , {66,65,77}, 153,2 , 9606,196 , 25,5 , 4,0 , 3139,6 , 581,19 , 2, 1, 1, 6, 7 }, // Serbian/Latin/BosniaAndHerzegowina - { 100, 7, 242, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15514,48 , 15562,81 , 15643,24 , 15514,48 , 15562,81 , 15643,24 , 8357,28 , 8385,54 , 2118,14 , 8357,28 , 8385,54 , 2118,14 , 248,9 , 238,7 , {69,85,82}, 131,1 , 9802,27 , 25,5 , 4,0 , 3139,6 , 3145,9 , 2, 1, 1, 6, 7 }, // Serbian/Latin/Montenegro - { 100, 7, 243, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15514,48 , 15562,81 , 15643,24 , 15514,48 , 15562,81 , 15643,24 , 8357,28 , 8385,54 , 2118,14 , 8357,28 , 8385,54 , 2118,14 , 248,9 , 238,7 , {82,83,68}, 286,4 , 9829,72 , 25,5 , 4,0 , 3139,6 , 3154,6 , 0, 0, 1, 6, 7 }, // Serbian/Latin/Serbia - { 101, 2, 81, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 436,9 , 436,9 , 187,8 , 1001,23 , 37,5 , 8,10 , 14908,62 , 15667,82 , 14970,24 , 15749,59 , 15808,86 , 14970,24 , 8439,28 , 8467,61 , 8528,14 , 8542,28 , 8570,61 , 8528,14 , 0,2 , 0,2 , {71,69,76}, 0,0 , 9901,17 , 14,5 , 4,0 , 3160,4 , 3164,11 , 2, 1, 1, 6, 7 }, // Ossetic/Cyrillic/Georgia - { 101, 2, 178, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 436,9 , 436,9 , 187,8 , 1001,23 , 37,5 , 8,10 , 14908,62 , 15667,82 , 14970,24 , 15749,59 , 15808,86 , 14970,24 , 8439,28 , 8467,61 , 8528,14 , 8542,28 , 8570,61 , 8528,14 , 0,2 , 0,2 , {82,85,66}, 275,4 , 9918,17 , 14,5 , 4,0 , 3160,4 , 3175,6 , 2, 1, 1, 6, 7 }, // Ossetic/Cyrillic/Russia - { 102, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 15894,48 , 15942,105 , 158,27 , 15894,48 , 15942,105 , 158,27 , 8631,27 , 8658,61 , 85,14 , 8631,27 , 8658,61 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3181,7 , 0,0 , 2, 1, 7, 6, 7 }, // Southern Sotho/Latin/SouthAfrica - { 102, 7, 120, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 15894,48 , 15942,105 , 158,27 , 15894,48 , 15942,105 , 158,27 , 8631,27 , 8658,61 , 85,14 , 8631,27 , 8658,61 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3181,7 , 0,0 , 2, 1, 1, 6, 7 }, // Southern Sotho/Latin/Lesotho - { 103, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16047,48 , 16095,117 , 158,27 , 16047,48 , 16095,117 , 158,27 , 8719,27 , 8746,64 , 85,14 , 8719,27 , 8746,64 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3188,8 , 0,0 , 2, 1, 7, 6, 7 }, // Tswana/Latin/SouthAfrica - { 103, 7, 28, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16047,48 , 16095,117 , 158,27 , 16047,48 , 16095,117 , 158,27 , 8719,27 , 8746,64 , 85,14 , 8719,27 , 8746,64 , 85,14 , 0,2 , 0,2 , {66,87,80}, 170,1 , 0,7 , 4,4 , 4,0 , 3188,8 , 0,0 , 2, 1, 7, 6, 7 }, // Tswana/Latin/Botswana - { 104, 7, 240, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 16212,47 , 16259,100 , 16359,24 , 16212,47 , 16259,100 , 16359,24 , 8810,32 , 8842,55 , 8897,14 , 8810,32 , 8842,55 , 8897,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 9935,22 , 4,4 , 8,6 , 3196,8 , 1491,8 , 2, 1, 7, 6, 7 }, // Shona/Latin/Zimbabwe - { 106, 32, 198, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 536,10 , 323,17 , 459,7 , 466,13 , 16383,59 , 16442,96 , 16538,32 , 16570,61 , 16442,96 , 16538,32 , 8911,30 , 8941,62 , 9003,19 , 8911,30 , 8941,62 , 9003,19 , 257,5 , 245,4 , {76,75,82}, 290,3 , 9957,19 , 14,5 , 4,0 , 3204,5 , 3209,11 , 2, 1, 1, 6, 7 }, // Sinhala/Sinhala/SriLanka - { 107, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16631,48 , 16679,114 , 158,27 , 16631,48 , 16679,114 , 158,27 , 9022,27 , 9049,68 , 85,14 , 9022,27 , 9049,68 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3220,7 , 0,0 , 2, 1, 7, 6, 7 }, // Swati/Latin/SouthAfrica - { 107, 7, 204, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16631,48 , 16679,114 , 158,27 , 16631,48 , 16679,114 , 158,27 , 9022,27 , 9049,68 , 85,14 , 9022,27 , 9049,68 , 85,14 , 0,2 , 0,2 , {83,90,76}, 191,1 , 0,7 , 4,4 , 4,0 , 3220,7 , 0,0 , 2, 1, 1, 6, 7 }, // Swati/Latin/Swaziland - { 108, 7, 191, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 135,7 , 135,7 , 546,8 , 462,18 , 61,4 , 219,9 , 16793,48 , 16841,82 , 15643,24 , 16793,48 , 16923,89 , 15643,24 , 9117,21 , 9138,52 , 9190,14 , 9117,21 , 9138,52 , 9190,14 , 262,10 , 249,9 , {69,85,82}, 131,1 , 9976,28 , 25,5 , 4,0 , 3227,10 , 3237,9 , 2, 1, 1, 6, 7 }, // Slovak/Latin/Slovakia - { 109, 7, 192, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 445,8 , 445,8 , 1024,9 , 590,19 , 37,5 , 8,10 , 15514,48 , 17012,86 , 15643,24 , 17098,59 , 17012,86 , 15643,24 , 9204,28 , 9232,52 , 9284,14 , 9298,35 , 9232,52 , 9284,14 , 81,4 , 258,4 , {69,85,82}, 131,1 , 10004,28 , 4,4 , 8,6 , 3246,11 , 3257,9 , 2, 1, 1, 6, 7 }, // Slovenian/Latin/Slovenia - { 110, 7, 194, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {83,79,83}, 98,1 , 10032,22 , 4,4 , 4,0 , 3266,8 , 3274,10 , 0, 0, 1, 6, 7 }, // Somali/Latin/Somalia - { 110, 7, 59, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {68,74,70}, 5,3 , 10054,21 , 4,4 , 4,0 , 3266,8 , 3284,7 , 0, 0, 6, 6, 7 }, // Somali/Latin/Djibouti - { 110, 7, 69, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {69,84,66}, 0,2 , 10075,22 , 4,4 , 4,0 , 3266,8 , 3291,8 , 2, 1, 7, 6, 7 }, // Somali/Latin/Ethiopia - { 110, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {75,69,83}, 2,3 , 0,7 , 4,4 , 4,0 , 3266,8 , 3299,7 , 2, 1, 7, 6, 7 }, // Somali/Latin/Kenya - { 111, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 4,0 , 3306,17 , 2048,6 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Spain - { 111, 7, 10, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 479,14 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {65,82,83}, 12,1 , 10097,51 , 4,4 , 4,0 , 3323,7 , 3330,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Argentina - { 111, 7, 26, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {66,79,66}, 293,2 , 10148,35 , 4,4 , 4,0 , 3323,7 , 3339,7 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Bolivia - { 111, 7, 43, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 503,8 , 897,27 , 61,4 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,76,80}, 12,1 , 10183,45 , 4,4 , 48,5 , 3323,7 , 3346,5 , 0, 0, 1, 6, 7 }, // Spanish/Latin/Chile - { 111, 7, 47, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 511,7 , 897,27 , 61,4 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,79,80}, 12,1 , 10228,54 , 4,4 , 4,0 , 3323,7 , 3351,8 , 0, 0, 7, 6, 7 }, // Spanish/Latin/Colombia - { 111, 7, 52, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,82,67}, 295,1 , 10282,67 , 4,4 , 4,0 , 3323,7 , 3359,10 , 0, 0, 1, 6, 7 }, // Spanish/Latin/CostaRica - { 111, 7, 55, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,85,80}, 12,1 , 10349,42 , 4,4 , 4,0 , 3323,7 , 3369,4 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Cuba - { 111, 7, 61, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {68,79,80}, 12,1 , 10391,54 , 4,4 , 4,0 , 3323,7 , 3373,20 , 2, 1, 7, 6, 7 }, // Spanish/Latin/DominicanRepublic - { 111, 7, 63, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 61,4 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,83,68}, 12,1 , 10445,70 , 4,4 , 48,5 , 3323,7 , 3393,7 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Ecuador - { 111, 7, 65, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,83,68}, 204,3 , 10445,70 , 4,4 , 4,0 , 3323,7 , 3400,11 , 2, 1, 7, 6, 7 }, // Spanish/Latin/ElSalvador - { 111, 7, 66, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {88,65,70}, 36,4 , 10515,53 , 4,4 , 4,0 , 3323,7 , 3411,17 , 0, 0, 1, 6, 7 }, // Spanish/Latin/EquatorialGuinea - { 111, 7, 90, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 511,7 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {71,84,81}, 296,1 , 10568,70 , 4,4 , 4,0 , 3323,7 , 3428,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Guatemala - { 111, 7, 96, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 1033,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {72,78,76}, 297,1 , 10638,60 , 4,4 , 4,0 , 3323,7 , 3437,8 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Honduras - { 111, 7, 139, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {77,88,78}, 12,1 , 10698,48 , 4,4 , 4,0 , 3323,7 , 3445,6 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Mexico - { 111, 7, 155, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {78,73,79}, 298,2 , 10746,69 , 4,4 , 4,0 , 3323,7 , 3451,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Nicaragua - { 111, 7, 166, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 1060,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {80,65,66}, 300,3 , 10815,54 , 4,4 , 4,0 , 3323,7 , 3460,6 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Panama - { 111, 7, 168, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {80,89,71}, 303,1 , 10869,61 , 14,5 , 65,6 , 3323,7 , 3466,8 , 0, 0, 7, 6, 7 }, // Spanish/Latin/Paraguay - { 111, 7, 169, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 511,7 , 897,27 , 37,5 , 493,15 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {80,69,78}, 304,3 , 10930,62 , 4,4 , 4,0 , 3323,7 , 3474,4 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Peru - { 111, 7, 170, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {80,72,80}, 183,1 , 10992,48 , 25,5 , 4,0 , 3323,7 , 3478,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Philippines - { 111, 7, 174, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 1060,8 , 897,27 , 18,7 , 25,12 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,83,68}, 12,1 , 10445,70 , 4,4 , 4,0 , 3323,7 , 1178,11 , 2, 1, 7, 6, 7 }, // Spanish/Latin/PuertoRico - { 111, 7, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 518,6 , 897,27 , 18,7 , 25,12 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 10445,70 , 4,4 , 4,0 , 3323,7 , 3487,14 , 2, 1, 7, 6, 7 }, // Spanish/Latin/UnitedStates - { 111, 7, 227, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,89,85}, 12,1 , 11040,48 , 14,5 , 71,7 , 3323,7 , 3501,7 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Uruguay - { 111, 7, 231, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {86,69,70}, 307,3 , 11088,64 , 4,4 , 48,5 , 3323,7 , 3508,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Venezuela - { 111, 7, 238, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 4,0 , 3323,7 , 3517,14 , 2, 1, 1, 6, 7 }, // Spanish/Latin/CanaryIslands - { 111, 7, 246, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {0,0,0}, 0,0 , 11152,0 , 4,4 , 4,0 , 3531,23 , 3554,13 , 2, 1, 1, 6, 7 }, // Spanish/Latin/LatinAmericaAndTheCaribbean - { 111, 7, 250, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 4,0 , 3323,7 , 3567,15 , 2, 1, 1, 6, 7 }, // Spanish/Latin/CeutaAndMelilla - { 113, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 460,9 , 469,8 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 17676,84 , 134,24 , 17628,48 , 17676,84 , 134,24 , 9517,22 , 9539,60 , 9599,14 , 9517,22 , 9539,60 , 9599,14 , 275,7 , 265,7 , {84,90,83}, 192,3 , 11152,27 , 4,4 , 8,6 , 3582,9 , 1325,8 , 0, 0, 1, 6, 7 }, // Swahili/Latin/Tanzania - { 113, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 460,9 , 469,8 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 17676,84 , 134,24 , 17628,48 , 17676,84 , 134,24 , 9517,22 , 9539,60 , 9599,14 , 9517,22 , 9539,60 , 9599,14 , 275,7 , 265,7 , {75,69,83}, 2,3 , 11179,24 , 4,4 , 4,0 , 3582,9 , 1006,5 , 2, 1, 7, 6, 7 }, // Swahili/Latin/Kenya - { 113, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 460,9 , 469,8 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 17676,84 , 134,24 , 17628,48 , 17676,84 , 134,24 , 9517,22 , 9539,60 , 9599,14 , 9517,22 , 9539,60 , 9599,14 , 275,7 , 265,7 , {85,71,88}, 197,3 , 11203,25 , 4,4 , 8,6 , 3582,9 , 1381,6 , 0, 0, 1, 6, 7 }, // Swahili/Latin/Uganda - { 114, 7, 205, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 477,9 , 477,9 , 72,10 , 1068,30 , 37,5 , 392,16 , 17760,48 , 17808,86 , 134,24 , 4985,48 , 17894,86 , 134,24 , 9613,28 , 9641,50 , 2309,14 , 9691,29 , 9720,50 , 2309,14 , 282,2 , 272,2 , {83,69,75}, 157,2 , 11228,45 , 25,5 , 4,0 , 3591,7 , 3598,7 , 2, 1, 1, 6, 7 }, // Swedish/Latin/Sweden - { 114, 7, 73, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 477,9 , 477,9 , 72,10 , 1068,30 , 37,5 , 392,16 , 17760,48 , 17808,86 , 134,24 , 4985,48 , 17894,86 , 134,24 , 9613,28 , 9641,50 , 2309,14 , 9691,29 , 9720,50 , 2309,14 , 282,2 , 272,2 , {69,85,82}, 131,1 , 11273,19 , 25,5 , 4,0 , 3591,7 , 3605,7 , 2, 1, 1, 6, 7 }, // Swedish/Latin/Finland - { 114, 7, 248, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 477,9 , 477,9 , 72,10 , 1068,30 , 37,5 , 392,16 , 17760,48 , 17808,86 , 134,24 , 4985,48 , 17894,86 , 134,24 , 9613,28 , 9641,50 , 2309,14 , 9691,29 , 9720,50 , 2309,14 , 282,2 , 272,2 , {69,85,82}, 131,1 , 11273,19 , 25,5 , 4,0 , 3591,7 , 3612,5 , 2, 1, 1, 6, 7 }, // Swedish/Latin/AlandIslands - { 116, 2, 209, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 171, 8222, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 17980,48 , 18028,71 , 158,27 , 17980,48 , 18028,71 , 158,27 , 9770,28 , 9798,55 , 85,14 , 9770,28 , 9798,55 , 85,14 , 0,2 , 0,2 , {84,74,83}, 242,3 , 11292,13 , 14,5 , 4,0 , 3617,6 , 3623,10 , 2, 1, 1, 6, 7 }, // Tajik/Cyrillic/Tajikistan - { 117, 27, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {73,78,82}, 122,1 , 11305,13 , 14,5 , 4,0 , 3633,5 , 3638,7 , 2, 1, 7, 7, 7 }, // Tamil/Tamil/India - { 117, 27, 130, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {77,89,82}, 256,2 , 11318,22 , 14,5 , 4,0 , 3633,5 , 3645,7 , 2, 1, 1, 6, 7 }, // Tamil/Tamil/Malaysia - { 117, 27, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {83,71,68}, 12,1 , 11340,24 , 14,5 , 4,0 , 3633,5 , 3652,11 , 2, 1, 7, 6, 7 }, // Tamil/Tamil/Singapore - { 117, 27, 198, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {76,75,82}, 310,3 , 11364,20 , 14,5 , 4,0 , 3633,5 , 3663,6 , 2, 1, 1, 6, 7 }, // Tamil/Tamil/SriLanka - { 119, 28, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 499,11 , 499,11 , 503,8 , 99,16 , 18,7 , 25,12 , 18360,66 , 18426,86 , 18512,31 , 18543,78 , 18426,86 , 18621,31 , 9922,32 , 9954,60 , 10014,18 , 9922,32 , 9954,60 , 10014,18 , 0,2 , 0,2 , {73,78,82}, 122,1 , 11384,26 , 4,4 , 8,6 , 3669,6 , 3675,9 , 2, 1, 7, 7, 7 }, // Telugu/Telugu/India - { 120, 30, 211, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 510,5 , 510,5 , 515,8 , 523,7 , 287,6 , 1098,19 , 37,5 , 508,28 , 18652,63 , 18715,98 , 18652,63 , 18652,63 , 18715,98 , 18813,62 , 10032,23 , 10055,68 , 10032,23 , 10032,23 , 10055,68 , 10032,23 , 284,10 , 274,10 , {84,72,66}, 313,1 , 11410,13 , 4,4 , 8,6 , 3684,3 , 3684,3 , 2, 1, 7, 6, 7 }, // Thai/Thai/Thailand - { 121, 31, 44, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 2663,63 , 18875,158 , 158,27 , 2663,63 , 18875,158 , 158,27 , 10123,49 , 10172,77 , 10249,21 , 10123,49 , 10172,77 , 10270,22 , 294,7 , 284,8 , {67,78,89}, 314,1 , 11423,13 , 14,5 , 4,0 , 3687,8 , 3695,6 , 2, 1, 7, 6, 7 }, // Tibetan/Tibetan/China - { 121, 31, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 2663,63 , 18875,158 , 158,27 , 2663,63 , 18875,158 , 158,27 , 10123,49 , 10172,77 , 10249,21 , 10123,49 , 10172,77 , 10270,22 , 294,7 , 284,8 , {73,78,82}, 122,1 , 11436,22 , 14,5 , 4,0 , 3687,8 , 3701,7 , 2, 1, 7, 7, 7 }, // Tibetan/Tibetan/India - { 122, 14, 69, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1117,23 , 18,7 , 25,12 , 19033,46 , 19079,62 , 1050,24 , 19033,46 , 19079,62 , 1050,24 , 10292,29 , 10292,29 , 10321,14 , 10292,29 , 10292,29 , 10321,14 , 301,7 , 292,7 , {69,84,66}, 0,2 , 11458,16 , 4,4 , 4,0 , 3708,4 , 103,5 , 2, 1, 7, 6, 7 }, // Tigrinya/Ethiopic/Ethiopia - { 122, 14, 67, 46, 44, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1140,23 , 18,7 , 25,12 , 19141,46 , 19187,54 , 1050,24 , 19141,46 , 19187,54 , 1050,24 , 10335,29 , 10335,29 , 10321,14 , 10335,29 , 10335,29 , 10321,14 , 301,7 , 292,7 , {69,82,78}, 8,3 , 0,7 , 4,4 , 4,0 , 3708,4 , 3712,4 , 2, 1, 1, 6, 7 }, // Tigrinya/Ethiopic/Eritrea - { 123, 7, 214, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 530,8 , 530,8 , 530,8 , 530,8 , 287,6 , 99,16 , 37,5 , 8,10 , 19241,51 , 19292,87 , 19379,24 , 19241,51 , 19292,87 , 19379,24 , 10364,29 , 10393,60 , 10453,14 , 10364,29 , 10393,60 , 10453,14 , 0,2 , 0,2 , {84,79,80}, 195,2 , 0,7 , 14,5 , 4,0 , 3716,13 , 1333,5 , 2, 1, 1, 6, 7 }, // Tongan/Latin/Tonga - { 124, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 19403,48 , 19451,122 , 158,27 , 19403,48 , 19451,122 , 158,27 , 10467,27 , 10494,72 , 85,14 , 10467,27 , 10494,72 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3729,8 , 0,0 , 2, 1, 7, 6, 7 }, // Tsonga/Latin/SouthAfrica - { 125, 7, 217, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 538,8 , 538,8 , 1163,9 , 1172,16 , 37,5 , 8,10 , 19573,48 , 19621,75 , 19696,24 , 19573,48 , 19621,75 , 19696,24 , 10566,28 , 10594,54 , 10648,14 , 10566,28 , 10594,54 , 10648,14 , 308,2 , 299,2 , {84,82,89}, 315,1 , 11474,18 , 25,5 , 30,7 , 3737,6 , 3743,7 , 2, 1, 1, 6, 7 }, // Turkish/Latin/Turkey - { 125, 7, 56, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 538,8 , 538,8 , 1163,9 , 1172,16 , 37,5 , 8,10 , 19573,48 , 19621,75 , 19696,24 , 19573,48 , 19621,75 , 19696,24 , 10566,28 , 10594,54 , 10648,14 , 10566,28 , 10594,54 , 10648,14 , 308,2 , 299,2 , {69,85,82}, 131,1 , 7151,11 , 25,5 , 30,7 , 3737,6 , 3750,23 , 2, 1, 1, 6, 7 }, // Turkish/Latin/Cyprus - { 129, 2, 222, 44, 160, 59, 37, 48, 45, 43, 1077, 171, 187, 8222, 8220, 0,6 , 0,6 , 546,8 , 546,8 , 187,8 , 1188,22 , 37,5 , 8,10 , 19720,48 , 19768,95 , 19863,24 , 19887,67 , 19954,87 , 19863,24 , 10662,21 , 10683,56 , 10739,14 , 10662,21 , 10683,56 , 10739,14 , 310,2 , 301,2 , {85,65,72}, 279,1 , 11492,49 , 25,5 , 4,0 , 3773,10 , 3783,7 , 2, 1, 1, 6, 7 }, // Ukrainian/Cyrillic/Ukraine - { 130, 1, 163, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 554,10 , 564,9 , 287,6 , 161,18 , 18,7 , 25,12 , 20041,66 , 20041,66 , 134,24 , 20041,66 , 20041,66 , 134,24 , 10753,36 , 10753,36 , 85,14 , 10753,36 , 10753,36 , 85,14 , 312,9 , 303,9 , {80,75,82}, 180,2 , 11541,21 , 4,4 , 4,0 , 3790,4 , 3794,7 , 0, 0, 7, 6, 7 }, // Urdu/Arabic/Pakistan - { 130, 1, 100, 46, 44, 59, 37, 1776, 45, 43, 1602, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 554,10 , 564,9 , 287,6 , 161,18 , 18,7 , 25,12 , 20041,66 , 20041,66 , 134,24 , 20041,66 , 20041,66 , 134,24 , 10753,36 , 10753,36 , 85,14 , 10753,36 , 10753,36 , 85,14 , 312,9 , 303,9 , {73,78,82}, 122,1 , 11562,18 , 14,5 , 4,0 , 3790,4 , 3801,5 , 2, 1, 7, 7, 7 }, // Urdu/Arabic/India - { 131, 2, 228, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 17980,48 , 18028,71 , 14970,24 , 17980,48 , 18028,71 , 14970,24 , 10789,28 , 10817,53 , 10870,14 , 10789,28 , 10817,53 , 10870,14 , 0,2 , 0,2 , {85,90,83}, 316,3 , 11580,21 , 14,5 , 4,0 , 3806,5 , 3811,10 , 0, 0, 1, 6, 7 }, // Uzbek/Cyrillic/Uzbekistan - { 131, 1, 1, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 179,8 , 1210,33 , 61,4 , 408,11 , 20107,48 , 13771,68 , 158,27 , 20107,48 , 13771,68 , 158,27 , 10884,21 , 7208,49 , 85,14 , 10884,21 , 7208,49 , 85,14 , 0,2 , 0,2 , {65,70,78}, 263,1 , 11601,13 , 25,5 , 4,0 , 3821,6 , 2776,9 , 0, 0, 6, 4, 5 }, // Uzbek/Arabic/Afghanistan - { 131, 7, 228, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 20155,52 , 20207,77 , 20284,24 , 20155,52 , 20207,77 , 20284,24 , 10905,34 , 10939,61 , 11000,14 , 10905,34 , 10939,61 , 11000,14 , 0,2 , 0,2 , {85,90,83}, 319,4 , 11614,23 , 14,5 , 4,0 , 3827,9 , 3836,11 , 0, 0, 1, 6, 7 }, // Uzbek/Latin/Uzbekistan - { 132, 7, 232, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 573,8 , 573,8 , 141,10 , 1243,31 , 37,5 , 8,10 , 20308,75 , 20383,130 , 158,27 , 20308,75 , 20383,130 , 158,27 , 11014,33 , 11047,55 , 11102,21 , 11014,33 , 11047,55 , 11102,21 , 321,2 , 312,2 , {86,78,68}, 323,1 , 11637,20 , 25,5 , 4,0 , 3847,10 , 3857,8 , 0, 0, 1, 6, 7 }, // Vietnamese/Latin/Vietnam - { 134, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 135,7 , 135,7 , 141,10 , 10,17 , 37,5 , 8,10 , 20513,52 , 20565,87 , 20652,26 , 20678,62 , 20565,87 , 20652,26 , 11123,29 , 11152,77 , 11229,15 , 11244,30 , 11152,77 , 11229,15 , 0,2 , 0,2 , {71,66,80}, 171,1 , 11657,154 , 4,4 , 4,0 , 3865,7 , 3872,16 , 2, 1, 1, 6, 7 }, // Welsh/Latin/UnitedKingdom - { 136, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 20740,48 , 20788,91 , 158,27 , 20740,48 , 20788,91 , 158,27 , 11274,28 , 11302,61 , 85,14 , 11274,28 , 11302,61 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3888,8 , 0,0 , 2, 1, 7, 6, 7 }, // Xhosa/Latin/SouthAfrica - { 138, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 20879,73 , 20952,121 , 158,27 , 20879,73 , 20952,121 , 158,27 , 11363,44 , 11407,69 , 85,14 , 11363,44 , 11407,69 , 85,14 , 323,5 , 314,5 , {78,71,78}, 182,1 , 11811,34 , 4,4 , 8,6 , 3896,10 , 3906,18 , 2, 1, 1, 6, 7 }, // Yoruba/Latin/Nigeria - { 140, 7, 195, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 581,9 , 590,10 , 72,10 , 82,17 , 18,7 , 25,12 , 21073,48 , 21121,104 , 134,24 , 21073,48 , 21225,90 , 134,24 , 11476,28 , 11504,68 , 11572,14 , 11476,28 , 11504,68 , 11572,14 , 328,7 , 319,8 , {90,65,82}, 11,1 , 11845,27 , 4,4 , 8,6 , 3924,7 , 3931,17 , 2, 1, 7, 6, 7 }, // Zulu/Latin/SouthAfrica - { 141, 7, 161, 44, 160, 59, 37, 48, 8722, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 187,8 , 554,17 , 37,5 , 392,16 , 5815,48 , 13184,83 , 134,24 , 13267,59 , 13184,83 , 134,24 , 11586,28 , 11614,51 , 2309,14 , 11665,28 , 11614,51 , 2309,14 , 335,9 , 327,11 , {78,79,75}, 157,2 , 11872,42 , 25,5 , 4,0 , 3948,7 , 3955,5 , 2, 1, 1, 6, 7 }, // NorwegianNynorsk/Latin/Norway - { 142, 7, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 118,7 , 118,7 , 1274,9 , 981,20 , 37,5 , 8,10 , 15514,48 , 21315,83 , 15643,24 , 15514,48 , 21315,83 , 15643,24 , 2032,28 , 2060,58 , 85,14 , 2032,28 , 2060,58 , 85,14 , 248,9 , 238,7 , {66,65,77}, 153,2 , 11914,218 , 14,5 , 4,0 , 3960,8 , 581,19 , 2, 1, 1, 6, 7 }, // Bosnian/Latin/BosniaAndHerzegowina - { 142, 2, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 974,7 , 981,20 , 37,5 , 8,10 , 15302,48 , 15431,83 , 11981,24 , 15302,48 , 15431,83 , 11981,24 , 8275,28 , 8303,54 , 8261,14 , 8275,28 , 8303,54 , 8261,14 , 239,9 , 231,7 , {66,65,77}, 284,2 , 12132,195 , 25,5 , 4,0 , 3968,8 , 3111,19 , 2, 1, 1, 6, 7 }, // Bosnian/Cyrillic/BosniaAndHerzegowina - { 144, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 82,17 , 37,5 , 8,10 , 21398,102 , 21500,140 , 158,27 , 21398,102 , 21500,140 , 158,27 , 11693,30 , 11723,57 , 85,14 , 11693,30 , 11723,57 , 85,14 , 75,4 , 74,4 , {71,66,80}, 171,1 , 0,7 , 4,4 , 4,0 , 3976,5 , 3981,14 , 2, 1, 1, 6, 7 }, // Manx/Latin/UnitedKingdom - { 145, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 99,16 , 37,5 , 8,10 , 21640,46 , 21686,124 , 158,27 , 21640,46 , 21686,124 , 158,27 , 11780,28 , 11808,60 , 85,14 , 11780,28 , 11808,60 , 85,14 , 75,4 , 74,4 , {71,66,80}, 171,1 , 0,7 , 4,4 , 4,0 , 3995,8 , 3981,14 , 2, 1, 1, 6, 7 }, // Cornish/Latin/UnitedKingdom - { 146, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 21810,48 , 21858,192 , 158,27 , 21810,48 , 21858,192 , 158,27 , 11868,28 , 11896,49 , 11945,14 , 11868,28 , 11896,49 , 11945,14 , 344,2 , 338,2 , {71,72,83}, 173,3 , 12327,17 , 4,4 , 4,0 , 4003,4 , 4007,5 , 2, 1, 1, 6, 7 }, // Akan/Latin/Ghana - { 147, 13, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 634,6 , 99,16 , 18,7 , 25,12 , 22050,87 , 22050,87 , 158,27 , 22050,87 , 22050,87 , 158,27 , 6771,32 , 11959,55 , 85,14 , 6771,32 , 11959,55 , 85,14 , 346,5 , 340,5 , {73,78,82}, 122,1 , 0,7 , 14,5 , 4,0 , 4012,6 , 2276,4 , 2, 1, 7, 7, 7 }, // Konkani/Devanagari/India - { 149, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 22137,48 , 22185,86 , 158,27 , 22137,48 , 22185,86 , 158,27 , 12014,29 , 12043,57 , 85,14 , 12014,29 , 12043,57 , 85,14 , 351,4 , 345,4 , {78,71,78}, 182,1 , 12344,12 , 4,4 , 8,6 , 4018,4 , 1107,7 , 2, 1, 1, 6, 7 }, // Igbo/Latin/Nigeria - { 150, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 22271,48 , 22319,189 , 22508,24 , 22271,48 , 22319,189 , 22508,24 , 12100,28 , 12128,74 , 12202,14 , 12100,28 , 12128,74 , 12202,14 , 355,9 , 349,7 , {75,69,83}, 2,3 , 12356,23 , 4,4 , 8,6 , 4022,7 , 1006,5 , 2, 1, 7, 6, 7 }, // Kamba/Latin/Kenya - { 152, 14, 67, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1283,22 , 18,7 , 25,12 , 22532,47 , 22579,77 , 22656,24 , 22532,47 , 22579,77 , 22656,24 , 12216,26 , 12242,43 , 12285,14 , 12216,26 , 12242,43 , 12285,14 , 0,2 , 0,2 , {69,82,78}, 8,3 , 0,7 , 4,4 , 4,0 , 4029,3 , 3712,4 , 2, 1, 1, 6, 7 }, // Blin/Ethiopic/Eritrea - { 157, 14, 67, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1305,21 , 18,7 , 25,12 , 19033,46 , 19079,62 , 1050,24 , 19033,46 , 19079,62 , 1050,24 , 12299,27 , 12326,41 , 12367,14 , 12299,27 , 12326,41 , 12367,14 , 0,2 , 0,2 , {69,82,78}, 8,3 , 0,7 , 4,4 , 4,0 , 4032,3 , 3712,4 , 2, 1, 1, 6, 7 }, // Tigre/Ethiopic/Eritrea - { 159, 7, 106, 44, 46, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 1326,27 , 37,5 , 8,10 , 22680,48 , 22728,77 , 22805,24 , 22680,48 , 22728,77 , 22805,24 , 12381,28 , 12409,50 , 3070,14 , 12381,28 , 12409,50 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 14,5 , 4,0 , 4035,6 , 4041,6 , 2, 1, 1, 6, 7 }, // Friulian/Latin/Italy - { 160, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 22829,48 , 22877,111 , 158,27 , 22829,48 , 22877,111 , 158,27 , 12459,27 , 12486,70 , 85,14 , 12459,27 , 12486,70 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 4047,9 , 0,0 , 2, 1, 7, 6, 7 }, // Venda/Latin/SouthAfrica - { 161, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 600,11 , 611,10 , 518,6 , 1353,23 , 536,12 , 548,12 , 22988,48 , 23036,87 , 23123,24 , 22988,48 , 23036,87 , 23123,24 , 12556,28 , 12584,44 , 12628,14 , 12556,28 , 12584,44 , 12628,14 , 364,3 , 356,5 , {71,72,83}, 173,3 , 12379,37 , 4,4 , 8,6 , 4056,6 , 4062,12 , 2, 1, 1, 6, 7 }, // Ewe/Latin/Ghana - { 161, 7, 212, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 600,11 , 611,10 , 518,6 , 1353,23 , 536,12 , 548,12 , 22988,48 , 23036,87 , 23123,24 , 22988,48 , 23036,87 , 23123,24 , 12556,28 , 12584,44 , 12628,14 , 12556,28 , 12584,44 , 12628,14 , 364,3 , 356,5 , {88,79,70}, 209,3 , 12416,106 , 4,4 , 8,6 , 4056,6 , 4074,11 , 0, 0, 1, 6, 7 }, // Ewe/Latin/Togo - { 162, 14, 69, 46, 8217, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1376,22 , 18,7 , 25,12 , 19033,46 , 19079,62 , 1050,24 , 19033,46 , 19079,62 , 1050,24 , 12642,27 , 12642,27 , 12669,14 , 12642,27 , 12642,27 , 12669,14 , 0,2 , 0,2 , {69,84,66}, 0,2 , 11458,16 , 4,4 , 4,0 , 4085,5 , 103,5 , 2, 1, 7, 6, 7 }, // Walamo/Ethiopic/Ethiopia - { 163, 7, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 10,17 , 18,7 , 25,12 , 23147,59 , 23206,95 , 158,27 , 23147,59 , 23206,95 , 158,27 , 12683,21 , 12704,57 , 85,14 , 12683,21 , 12704,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 0,7 , 4,4 , 8,6 , 4090,14 , 4104,19 , 2, 1, 7, 6, 7 }, // Hawaiian/Latin/UnitedStates - { 166, 7, 170, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 621,8 , 621,8 , 518,6 , 1398,18 , 37,5 , 8,10 , 23301,48 , 23349,88 , 23437,24 , 23301,48 , 23349,88 , 23437,24 , 12761,28 , 12789,55 , 12844,14 , 12858,28 , 12789,55 , 12844,14 , 0,2 , 0,2 , {80,72,80}, 183,1 , 12522,22 , 4,4 , 8,6 , 4123,8 , 4131,9 , 2, 1, 7, 6, 7 }, // Filipino/Latin/Philippines - { 167, 7, 206, 46, 8217, 59, 37, 48, 8722, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 23461,86 , 134,24 , 6990,48 , 23461,86 , 134,24 , 12886,28 , 12914,63 , 3471,14 , 12886,28 , 12914,63 , 3471,14 , 94,5 , 361,4 , {67,72,70}, 230,3 , 12544,55 , 25,5 , 4,0 , 4140,16 , 4156,7 , 2, 0, 1, 6, 7 }, // Swiss German/Latin/Switzerland - { 168, 34, 44, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 158,27 , 23547,38 , 158,27 , 158,27 , 23547,38 , 158,27 , 12977,21 , 12998,28 , 13026,14 , 12977,21 , 12998,28 , 13026,14 , 367,2 , 365,2 , {67,78,89}, 314,1 , 0,7 , 14,5 , 4,0 , 4163,3 , 4166,2 , 2, 1, 7, 6, 7 }, // Sichuan Yi/Yi/China - { 171, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 23585,48 , 23633,100 , 158,27 , 23585,48 , 23633,100 , 158,27 , 13040,27 , 13067,66 , 85,14 , 13040,27 , 13067,66 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 4168,10 , 0,0 , 2, 1, 7, 6, 7 }, // South Ndebele/Latin/SouthAfrica - { 172, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 23733,48 , 23781,94 , 158,27 , 23733,48 , 23781,94 , 158,27 , 13133,27 , 13160,63 , 85,14 , 13133,27 , 13160,63 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 4178,16 , 0,0 , 2, 1, 7, 6, 7 }, // Northern Sotho/Latin/SouthAfrica - { 173, 7, 161, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 169,8 , 169,8 , 72,10 , 323,17 , 37,5 , 8,10 , 23875,59 , 23934,145 , 24079,24 , 23875,59 , 23934,145 , 24079,24 , 13223,33 , 13256,75 , 13331,14 , 13223,33 , 13256,75 , 13331,14 , 0,2 , 0,2 , {78,79,75}, 157,2 , 12599,63 , 25,5 , 4,0 , 4194,15 , 4209,5 , 2, 1, 1, 6, 7 }, // Northern Sami/Latin/Norway - { 173, 7, 73, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 169,8 , 169,8 , 72,10 , 323,17 , 37,5 , 8,10 , 24103,85 , 23934,145 , 24079,24 , 24103,85 , 23934,145 , 24079,24 , 13223,33 , 13345,65 , 13410,14 , 13223,33 , 13345,65 , 13410,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 12662,23 , 25,5 , 4,0 , 4194,15 , 4214,6 , 2, 1, 1, 6, 7 }, // Northern Sami/Latin/Finland - { 175, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 24188,48 , 24236,88 , 24324,24 , 24188,48 , 24236,88 , 24324,24 , 13424,28 , 13452,62 , 13514,14 , 13424,28 , 13452,62 , 13514,14 , 369,5 , 367,10 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4220,8 , 1006,5 , 2, 1, 7, 6, 7 }, // Gusii/Latin/Kenya - { 176, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 24348,48 , 24396,221 , 24617,24 , 24348,48 , 24396,221 , 24617,24 , 13528,28 , 13556,105 , 13661,14 , 13528,28 , 13556,105 , 13661,14 , 374,10 , 377,10 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4228,7 , 1006,5 , 2, 1, 7, 6, 7 }, // Taita/Latin/Kenya - { 177, 7, 187, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 8218, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 24641,48 , 24689,77 , 24766,24 , 24641,48 , 24689,77 , 24766,24 , 13675,28 , 13703,59 , 13762,14 , 13675,28 , 13703,59 , 13762,14 , 384,6 , 387,7 , {88,79,70}, 209,3 , 12709,26 , 25,5 , 4,0 , 4235,6 , 4241,8 , 0, 0, 1, 6, 7 }, // Fulah/Latin/Senegal - { 178, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 24790,48 , 24838,185 , 25023,24 , 24790,48 , 24838,185 , 25023,24 , 13776,28 , 13804,63 , 13867,14 , 13776,28 , 13804,63 , 13867,14 , 390,6 , 394,8 , {75,69,83}, 2,3 , 12735,23 , 4,4 , 8,6 , 4249,6 , 1006,5 , 2, 1, 7, 6, 7 }, // Kikuyu/Latin/Kenya - { 179, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 25047,48 , 25095,173 , 25268,24 , 25047,48 , 25095,173 , 25268,24 , 13881,28 , 13909,105 , 14014,14 , 13881,28 , 13909,105 , 14014,14 , 396,7 , 402,5 , {75,69,83}, 2,3 , 12758,25 , 4,4 , 8,6 , 4255,8 , 1006,5 , 2, 1, 7, 6, 7 }, // Samburu/Latin/Kenya - { 180, 7, 146, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 897,27 , 37,5 , 8,10 , 25292,48 , 25340,88 , 134,24 , 25292,48 , 25340,88 , 134,24 , 14028,28 , 14056,55 , 14111,14 , 14028,28 , 14056,55 , 14111,14 , 0,2 , 0,2 , {77,90,78}, 269,3 , 12783,28 , 0,4 , 4,0 , 4263,4 , 2902,10 , 2, 1, 7, 6, 7 }, // Sena/Latin/Mozambique - { 181, 7, 240, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 25428,52 , 25480,112 , 25592,24 , 25428,52 , 25480,112 , 25592,24 , 14125,28 , 14153,50 , 14203,14 , 14125,28 , 14153,50 , 14203,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 12811,24 , 4,4 , 8,6 , 4168,10 , 1491,8 , 2, 1, 7, 6, 7 }, // North Ndebele/Latin/Zimbabwe - { 182, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 25616,39 , 25655,194 , 25849,24 , 25616,39 , 25655,194 , 25849,24 , 14217,29 , 14246,65 , 14311,14 , 14217,29 , 14246,65 , 14311,14 , 403,8 , 407,7 , {84,90,83}, 192,3 , 12835,25 , 4,4 , 4,0 , 4267,9 , 1325,8 , 0, 0, 1, 6, 7 }, // Rombo/Latin/Tanzania - { 183, 9, 145, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 25873,48 , 25921,81 , 26002,24 , 25873,48 , 25921,81 , 26002,24 , 14325,30 , 14355,47 , 85,14 , 14325,30 , 14355,47 , 85,14 , 411,6 , 414,8 , {77,65,68}, 0,0 , 12860,21 , 0,4 , 4,0 , 4276,8 , 4284,6 , 2, 1, 6, 5, 6 }, // Tachelhit/Tifinagh/Morocco - { 183, 7, 145, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 26026,48 , 26074,81 , 26155,24 , 26026,48 , 26074,81 , 26155,24 , 14402,30 , 14432,48 , 85,14 , 14402,30 , 14432,48 , 85,14 , 417,6 , 422,8 , {77,65,68}, 0,0 , 12881,21 , 0,4 , 4,0 , 4290,9 , 4299,6 , 2, 1, 6, 5, 6 }, // Tachelhit/Latin/Morocco - { 184, 7, 3, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 26179,48 , 26227,84 , 26311,24 , 26179,48 , 26227,84 , 26311,24 , 14480,30 , 14510,51 , 14561,14 , 14480,30 , 14510,51 , 14561,14 , 423,7 , 430,9 , {68,90,68}, 207,2 , 12902,21 , 0,4 , 4,0 , 4305,9 , 4314,8 , 2, 1, 6, 4, 5 }, // Kabyle/Latin/Algeria - { 185, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 26335,48 , 26383,152 , 134,24 , 26335,48 , 26383,152 , 134,24 , 14575,28 , 14603,74 , 14677,14 , 14575,28 , 14603,74 , 14677,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 12923,26 , 4,4 , 78,5 , 4322,10 , 1381,6 , 0, 0, 1, 6, 7 }, // Nyankole/Latin/Uganda - { 186, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 26535,48 , 26583,254 , 26837,24 , 26535,48 , 26583,254 , 26837,24 , 14691,28 , 14719,82 , 14801,14 , 14691,28 , 14719,82 , 14801,14 , 430,7 , 439,7 , {84,90,83}, 192,3 , 12949,29 , 0,4 , 4,0 , 4332,6 , 4338,10 , 0, 0, 1, 6, 7 }, // Bena/Latin/Tanzania - { 187, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 26861,87 , 134,24 , 17628,48 , 26861,87 , 134,24 , 14815,28 , 14843,62 , 14905,14 , 14815,28 , 14843,62 , 14905,14 , 437,5 , 446,9 , {84,90,83}, 192,3 , 12978,27 , 4,4 , 4,0 , 4348,8 , 1325,8 , 0, 0, 1, 6, 7 }, // Vunjo/Latin/Tanzania - { 188, 7, 132, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 26948,47 , 26995,92 , 27087,24 , 26948,47 , 26995,92 , 27087,24 , 14919,28 , 14947,44 , 14991,14 , 14919,28 , 14947,44 , 14991,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 13005,24 , 4,4 , 8,6 , 4356,9 , 1836,4 , 0, 0, 1, 6, 7 }, // Bambara/Latin/Mali - { 189, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 27111,48 , 27159,207 , 27366,24 , 27111,48 , 27159,207 , 27366,24 , 15005,28 , 15033,64 , 15097,14 , 15005,28 , 15033,64 , 15097,14 , 442,2 , 455,2 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4365,6 , 1006,5 , 2, 1, 7, 6, 7 }, // Embu/Latin/Kenya - { 190, 12, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 518,6 , 35,18 , 18,7 , 25,12 , 27390,36 , 27426,58 , 27484,24 , 27390,36 , 27426,58 , 27484,24 , 15111,28 , 15139,49 , 15188,14 , 15111,28 , 15139,49 , 15188,14 , 444,3 , 457,6 , {85,83,68}, 12,1 , 13029,19 , 4,4 , 8,6 , 4371,3 , 4374,4 , 2, 1, 7, 6, 7 }, // Cherokee/Cherokee/UnitedStates - { 191, 7, 137, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 27508,47 , 27555,68 , 27623,24 , 27508,47 , 27555,68 , 27623,24 , 15202,27 , 15229,48 , 15277,14 , 15202,27 , 15229,48 , 15277,14 , 0,2 , 0,2 , {77,85,82}, 180,2 , 13048,21 , 14,5 , 4,0 , 4378,14 , 4392,5 , 0, 0, 1, 6, 7 }, // Morisyen/Latin/Mauritius - { 192, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 27647,264 , 134,24 , 17628,48 , 27647,264 , 134,24 , 15291,28 , 15319,133 , 14311,14 , 15291,28 , 15319,133 , 14311,14 , 447,4 , 463,5 , {84,90,83}, 192,3 , 12978,27 , 4,4 , 8,6 , 4397,10 , 1325,8 , 0, 0, 1, 6, 7 }, // Makonde/Latin/Tanzania - { 193, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 27911,83 , 27994,111 , 28105,24 , 27911,83 , 27994,111 , 28105,24 , 15452,36 , 15488,63 , 15551,14 , 15452,36 , 15488,63 , 15551,14 , 451,3 , 468,3 , {84,90,83}, 192,3 , 13069,29 , 14,5 , 4,0 , 4407,8 , 4415,9 , 0, 0, 1, 6, 7 }, // Langi/Latin/Tanzania - { 194, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28129,48 , 28177,97 , 134,24 , 28129,48 , 28177,97 , 134,24 , 15565,28 , 15593,66 , 15659,14 , 15565,28 , 15593,66 , 15659,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 13098,26 , 0,4 , 4,0 , 4424,7 , 4431,7 , 0, 0, 1, 6, 7 }, // Ganda/Latin/Uganda - { 195, 7, 239, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28274,48 , 28322,83 , 28405,24 , 28274,48 , 28322,83 , 28405,24 , 15673,80 , 15673,80 , 85,14 , 15673,80 , 15673,80 , 85,14 , 454,8 , 471,7 , {90,77,87}, 202,2 , 0,7 , 4,4 , 8,6 , 4438,9 , 1485,6 , 2, 1, 1, 6, 7 }, // Bemba/Latin/Zambia - { 196, 7, 39, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 453,7 , 453,7 , 364,8 , 1416,27 , 37,5 , 8,10 , 28429,48 , 28477,86 , 134,24 , 28429,48 , 28477,86 , 134,24 , 15753,28 , 15781,73 , 15854,14 , 15753,28 , 15781,73 , 15854,14 , 89,2 , 88,2 , {67,86,69}, 0,0 , 13124,25 , 0,4 , 4,0 , 4447,12 , 4459,10 , 2, 1, 1, 6, 7 }, // Kabuverdianu/Latin/CapeVerde - { 197, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28563,48 , 28611,86 , 28697,24 , 28563,48 , 28611,86 , 28697,24 , 15868,28 , 15896,51 , 15947,14 , 15868,28 , 15896,51 , 15947,14 , 462,2 , 478,2 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4469,6 , 1006,5 , 2, 1, 7, 6, 7 }, // Meru/Latin/Kenya - { 198, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28721,48 , 28769,111 , 28880,24 , 28721,48 , 28769,111 , 28880,24 , 15961,28 , 15989,93 , 16082,14 , 15961,28 , 15989,93 , 16082,14 , 464,4 , 480,4 , {75,69,83}, 2,3 , 13149,26 , 4,4 , 8,6 , 4475,8 , 4483,12 , 2, 1, 7, 6, 7 }, // Kalenjin/Latin/Kenya - { 199, 7, 148, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 0,48 , 28904,136 , 134,24 , 0,48 , 28904,136 , 134,24 , 16096,23 , 16119,92 , 16211,14 , 16096,23 , 16119,92 , 16211,14 , 468,7 , 484,5 , {78,65,68}, 12,1 , 13175,22 , 4,4 , 4,0 , 4495,13 , 4508,8 , 2, 1, 1, 6, 7 }, // Nama/Latin/Namibia - { 200, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 26861,87 , 134,24 , 17628,48 , 26861,87 , 134,24 , 14815,28 , 14843,62 , 14905,14 , 14815,28 , 14843,62 , 14905,14 , 437,5 , 446,9 , {84,90,83}, 192,3 , 12978,27 , 4,4 , 4,0 , 4516,9 , 1325,8 , 0, 0, 1, 6, 7 }, // Machame/Latin/Tanzania - { 201, 7, 82, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 347,8 , 347,8 , 1443,10 , 1453,23 , 37,5 , 8,10 , 29040,59 , 29099,87 , 134,24 , 29186,48 , 29099,87 , 134,24 , 16225,28 , 16253,72 , 3471,14 , 16225,28 , 16253,72 , 3471,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 7151,11 , 25,5 , 4,0 , 4525,6 , 4531,11 , 2, 1, 1, 6, 7 }, // Colognian/Latin/Germany - { 202, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29234,51 , 29285,132 , 158,27 , 29234,51 , 29285,132 , 158,27 , 14815,28 , 16325,58 , 14311,14 , 14815,28 , 16325,58 , 14311,14 , 475,9 , 489,6 , {75,69,83}, 2,3 , 13197,25 , 4,4 , 8,6 , 4542,3 , 1006,5 , 2, 1, 7, 6, 7 }, // Masai/Latin/Kenya - { 202, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29234,51 , 29285,132 , 158,27 , 29234,51 , 29285,132 , 158,27 , 14815,28 , 16325,58 , 14311,14 , 14815,28 , 16325,58 , 14311,14 , 475,9 , 489,6 , {84,90,83}, 192,3 , 13222,28 , 4,4 , 8,6 , 4542,3 , 4545,8 , 0, 0, 1, 6, 7 }, // Masai/Latin/Tanzania - { 203, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28129,48 , 28177,97 , 134,24 , 28129,48 , 28177,97 , 134,24 , 16383,35 , 16418,65 , 16483,14 , 16383,35 , 16418,65 , 16483,14 , 484,6 , 495,6 , {85,71,88}, 197,3 , 13098,26 , 25,5 , 4,0 , 4553,7 , 4431,7 , 0, 0, 1, 6, 7 }, // Soga/Latin/Uganda - { 204, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29417,48 , 17676,84 , 134,24 , 29417,48 , 17676,84 , 134,24 , 16497,21 , 16518,75 , 85,14 , 16497,21 , 16518,75 , 85,14 , 75,4 , 74,4 , {75,69,83}, 2,3 , 13250,23 , 4,4 , 83,6 , 4560,7 , 1006,5 , 2, 1, 7, 6, 7 }, // Luyia/Latin/Kenya - { 205, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29465,48 , 17676,84 , 134,24 , 29465,48 , 17676,84 , 134,24 , 16593,28 , 9539,60 , 14905,14 , 16593,28 , 9539,60 , 14905,14 , 490,9 , 501,8 , {84,90,83}, 192,3 , 13273,28 , 25,5 , 4,0 , 4567,6 , 4573,8 , 0, 0, 1, 6, 7 }, // Asu/Latin/Tanzania - { 206, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29513,48 , 29561,94 , 29655,24 , 29513,48 , 29561,94 , 29655,24 , 16621,28 , 16649,69 , 16718,14 , 16621,28 , 16649,69 , 16718,14 , 499,9 , 509,6 , {85,71,88}, 197,3 , 13301,28 , 4,4 , 8,6 , 4581,6 , 1381,6 , 0, 0, 1, 6, 7 }, // Teso/Latin/Uganda - { 206, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29513,48 , 29561,94 , 29655,24 , 29513,48 , 29561,94 , 29655,24 , 16621,28 , 16649,69 , 16718,14 , 16621,28 , 16649,69 , 16718,14 , 499,9 , 509,6 , {75,69,83}, 2,3 , 13329,27 , 4,4 , 8,6 , 4581,6 , 4587,5 , 2, 1, 7, 6, 7 }, // Teso/Latin/Kenya + { 6, 7, 257, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 0,6 , 0,6 , 115,8 , 123,18 , 42,7 , 49,12 , 793,48 , 841,78 , 919,24 , 793,48 , 841,78 , 919,24 , 383,28 , 411,58 , 469,14 , 383,28 , 411,58 , 469,14 , 7,2 , 7,2 , {69,85,82}, 19,1 , 81,11 , 4,4 , 4,0 , 77,5 , 99,6 , 2, 1, 1, 6, 7 }, // Albanian/Latin/Kosovo + { 7, 14, 69, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 14,6 , 14,6 , 20,9 , 29,8 , 141,10 , 10,17 , 18,7 , 25,12 , 943,46 , 989,61 , 1050,24 , 1074,46 , 1120,62 , 1050,24 , 483,27 , 510,28 , 538,14 , 483,27 , 510,28 , 538,14 , 9,3 , 9,4 , {69,84,66}, 20,2 , 92,34 , 4,4 , 8,6 , 105,4 , 109,5 , 2, 1, 7, 6, 7 }, // Amharic/Ethiopic/Ethiopia + { 8, 1, 64, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {69,71,80}, 22,5 , 126,70 , 14,5 , 19,6 , 114,7 , 121,3 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Egypt + { 8, 1, 3, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 179,8 , 161,18 , 18,7 , 25,12 , 1281,71 , 1281,71 , 1352,24 , 1281,71 , 1281,71 , 1352,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {68,90,68}, 27,5 , 196,91 , 14,5 , 19,6 , 114,7 , 124,7 , 2, 1, 6, 4, 5 }, // Arabic/Arabic/Algeria + { 8, 1, 17, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {66,72,68}, 32,5 , 287,91 , 14,5 , 19,6 , 114,7 , 131,7 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Bahrain + { 8, 1, 42, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {88,65,70}, 37,4 , 378,84 , 14,5 , 19,6 , 114,7 , 138,4 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Chad + { 8, 1, 48, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {75,77,70}, 41,7 , 462,105 , 14,5 , 19,6 , 114,7 , 142,9 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Comoros + { 8, 1, 59, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {68,74,70}, 5,3 , 567,84 , 14,5 , 19,6 , 114,7 , 151,6 , 0, 0, 6, 6, 7 }, // Arabic/Arabic/Djibouti + { 8, 1, 67, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {69,82,78}, 8,3 , 651,91 , 14,5 , 19,6 , 114,7 , 157,7 , 2, 1, 1, 6, 7 }, // Arabic/Arabic/Eritrea + { 8, 1, 103, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1376,92 , 1376,92 , 1468,24 , 1492,92 , 1376,92 , 1468,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {73,81,68}, 48,5 , 742,84 , 14,5 , 19,6 , 114,7 , 164,6 , 0, 0, 6, 5, 6 }, // Arabic/Arabic/Iraq + { 8, 1, 105, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {73,76,83}, 53,1 , 826,133 , 14,5 , 19,6 , 114,7 , 170,7 , 2, 1, 7, 5, 6 }, // Arabic/Arabic/Israel + { 8, 1, 109, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1376,92 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {74,79,68}, 54,5 , 959,84 , 14,5 , 19,6 , 114,7 , 177,6 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Jordan + { 8, 1, 115, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {75,87,68}, 59,5 , 1043,84 , 14,5 , 19,6 , 114,7 , 183,6 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Kuwait + { 8, 1, 119, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1376,92 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {76,66,80}, 64,5 , 1127,84 , 14,5 , 19,6 , 114,7 , 189,5 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Lebanon + { 8, 1, 122, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {76,89,68}, 69,5 , 1211,77 , 14,5 , 19,6 , 114,7 , 194,5 , 3, 0, 6, 5, 6 }, // Arabic/Arabic/Libya + { 8, 1, 136, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {77,82,79}, 74,5 , 1288,112 , 14,5 , 19,6 , 114,7 , 199,9 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Mauritania + { 8, 1, 145, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 179,8 , 161,18 , 18,7 , 25,12 , 1584,71 , 1655,71 , 1726,24 , 1655,71 , 1750,71 , 1821,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {77,65,68}, 79,5 , 1400,77 , 14,5 , 19,6 , 114,7 , 208,6 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Morocco + { 8, 1, 162, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {79,77,82}, 84,5 , 1477,77 , 14,5 , 19,6 , 114,7 , 214,5 , 3, 0, 6, 4, 5 }, // Arabic/Arabic/Oman + { 8, 1, 165, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {73,76,83}, 53,1 , 826,133 , 14,5 , 19,6 , 114,7 , 219,6 , 2, 1, 1, 6, 7 }, // Arabic/Arabic/PalestinianTerritories + { 8, 1, 175, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {81,65,82}, 89,5 , 1554,70 , 4,4 , 4,0 , 114,7 , 225,3 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Qatar + { 8, 1, 186, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,65,82}, 94,5 , 1624,77 , 4,4 , 4,0 , 114,7 , 228,24 , 2, 1, 6, 4, 5 }, // Arabic/Arabic/SaudiArabia + { 8, 1, 194, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,79,83}, 99,1 , 1701,77 , 14,5 , 19,6 , 114,7 , 252,7 , 0, 0, 1, 6, 7 }, // Arabic/Arabic/Somalia + { 8, 1, 201, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,68,71}, 0,0 , 1778,84 , 14,5 , 19,6 , 114,7 , 259,7 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/Sudan + { 8, 1, 207, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1376,92 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {83,89,80}, 100,5 , 1862,77 , 4,4 , 4,0 , 114,7 , 266,5 , 0, 0, 6, 5, 6 }, // Arabic/Arabic/Syria + { 8, 1, 216, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 179,8 , 161,18 , 18,7 , 25,12 , 1281,71 , 1281,71 , 1352,24 , 1281,71 , 1281,71 , 1352,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {84,78,68}, 105,5 , 1939,77 , 4,4 , 4,0 , 114,7 , 271,4 , 3, 0, 7, 5, 6 }, // Arabic/Arabic/Tunisia + { 8, 1, 223, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {65,69,68}, 110,5 , 2016,91 , 14,5 , 19,6 , 114,7 , 275,24 , 2, 1, 6, 5, 6 }, // Arabic/Arabic/UnitedArabEmirates + { 8, 1, 236, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {77,65,68}, 79,5 , 1400,77 , 14,5 , 19,6 , 114,7 , 299,15 , 2, 1, 1, 6, 7 }, // Arabic/Arabic/WesternSahara + { 8, 1, 237, 1643, 1644, 1563, 1642, 1632, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 43,8 , 51,7 , 151,10 , 161,18 , 18,7 , 25,12 , 1182,75 , 1182,75 , 1257,24 , 1182,75 , 1182,75 , 1257,24 , 552,52 , 552,52 , 604,14 , 552,52 , 552,52 , 604,14 , 12,1 , 13,1 , {89,69,82}, 115,5 , 2107,70 , 4,4 , 4,0 , 114,7 , 314,5 , 0, 0, 6, 4, 5 }, // Arabic/Arabic/Yemen + { 9, 10, 11, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 58,7 , 58,7 , 187,8 , 195,21 , 61,4 , 65,10 , 1845,48 , 1893,106 , 1999,24 , 1845,48 , 1893,106 , 1999,24 , 618,28 , 646,62 , 708,15 , 618,28 , 646,62 , 708,15 , 13,12 , 14,12 , {65,77,68}, 120,3 , 2177,46 , 25,5 , 4,0 , 319,7 , 326,8 , 0, 0, 1, 6, 7 }, // Armenian/Armenian/Armenia + { 10, 11, 100, 46, 44, 59, 37, 2534, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 216,8 , 224,18 , 75,8 , 83,12 , 2023,62 , 2085,88 , 158,27 , 2023,62 , 2085,88 , 158,27 , 723,37 , 760,58 , 85,14 , 723,37 , 760,58 , 85,14 , 25,9 , 26,7 , {73,78,82}, 123,1 , 0,7 , 14,5 , 4,0 , 334,7 , 341,4 , 2, 1, 7, 7, 7 }, // Assamese/Bengali/India + { 12, 7, 15, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 250,19 , 37,5 , 8,10 , 2173,48 , 2221,77 , 158,27 , 2173,48 , 2221,77 , 158,27 , 818,26 , 844,67 , 99,14 , 818,26 , 844,67 , 99,14 , 0,2 , 0,2 , {65,90,78}, 124,4 , 2223,41 , 14,5 , 4,0 , 345,12 , 357,10 , 2, 1, 1, 6, 7 }, // Azerbaijani/Latin/Azerbaijan + { 12, 2, 15, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 250,19 , 37,5 , 8,10 , 2298,77 , 2298,77 , 158,27 , 2298,77 , 2298,77 , 158,27 , 911,67 , 911,67 , 99,14 , 911,67 , 911,67 , 99,14 , 0,2 , 0,2 , {65,90,78}, 128,4 , 2264,12 , 14,5 , 4,0 , 367,10 , 367,10 , 2, 1, 1, 6, 7 }, // Azerbaijani/Cyrillic/Azerbaijan + { 14, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 65,9 , 65,9 , 72,10 , 269,18 , 37,5 , 8,10 , 2375,48 , 2423,93 , 2516,24 , 2375,48 , 2423,93 , 2516,24 , 978,21 , 999,68 , 1067,14 , 978,21 , 999,68 , 1081,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2276,12 , 25,5 , 30,7 , 377,7 , 384,8 , 2, 1, 1, 6, 7 }, // Basque/Latin/Spain + { 15, 11, 18, 46, 44, 59, 37, 2534, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 74,10 , 84,9 , 287,6 , 224,18 , 18,7 , 25,12 , 2540,90 , 2540,90 , 2630,33 , 2540,90 , 2540,90 , 2630,33 , 1095,37 , 1132,58 , 1190,18 , 1095,37 , 1132,58 , 1190,18 , 34,9 , 33,7 , {66,68,84}, 132,1 , 2288,21 , 0,4 , 37,6 , 392,5 , 397,8 , 2, 1, 5, 6, 7 }, // Bengali/Bengali/Bangladesh + { 15, 11, 100, 46, 44, 59, 37, 2534, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 74,10 , 84,9 , 287,6 , 224,18 , 18,7 , 25,12 , 2540,90 , 2540,90 , 2630,33 , 2540,90 , 2540,90 , 2630,33 , 1095,37 , 1132,58 , 1190,18 , 1095,37 , 1132,58 , 1190,18 , 34,9 , 33,7 , {73,78,82}, 123,1 , 2309,19 , 0,4 , 37,6 , 392,5 , 405,4 , 2, 1, 7, 7, 7 }, // Bengali/Bengali/India + { 16, 31, 25, 46, 44, 59, 37, 3872, 45, 43, 101, 8220, 8221, 8216, 8217, 93,9 , 93,9 , 93,9 , 93,9 , 72,10 , 293,30 , 95,22 , 117,27 , 2663,63 , 2726,191 , 2917,27 , 2944,27 , 2971,132 , 3103,27 , 1208,34 , 1242,79 , 1321,27 , 1208,34 , 1242,79 , 1321,27 , 43,5 , 40,6 , {66,84,78}, 133,3 , 2328,15 , 4,4 , 4,0 , 409,6 , 415,5 , 2, 1, 7, 6, 7 }, // Dzongkha/Tibetan/Bhutan + { 19, 7, 74, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 3130,55 , 3185,78 , 158,27 , 3130,55 , 3185,78 , 158,27 , 1348,33 , 1381,43 , 1424,21 , 1348,33 , 1381,43 , 1424,21 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2343,11 , 14,5 , 4,0 , 420,9 , 429,5 , 2, 1, 1, 6, 7 }, // Breton/Latin/France + { 20, 2, 33, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 340,18 , 37,5 , 8,10 , 3263,59 , 3322,82 , 3404,24 , 3263,59 , 3322,82 , 3404,24 , 1445,21 , 1466,55 , 1521,14 , 1445,21 , 1466,55 , 1521,14 , 48,7 , 46,7 , {66,71,78}, 136,3 , 2354,47 , 25,5 , 4,0 , 434,9 , 443,8 , 2, 1, 1, 6, 7 }, // Bulgarian/Cyrillic/Bulgaria + { 21, 25, 147, 46, 44, 4170, 37, 4160, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 3428,43 , 3471,88 , 3559,24 , 3428,43 , 3471,88 , 3559,24 , 1535,25 , 1560,54 , 1614,14 , 1535,25 , 1560,54 , 1614,14 , 55,5 , 53,3 , {77,77,75}, 139,1 , 2401,18 , 14,5 , 4,0 , 451,3 , 454,6 , 0, 0, 7, 6, 7 }, // Burmese/Myanmar/Myanmar + { 22, 2, 20, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 358,6 , 10,17 , 144,5 , 149,10 , 3583,48 , 3631,99 , 3730,24 , 3754,48 , 3802,95 , 3897,24 , 1628,21 , 1649,56 , 1705,14 , 1628,21 , 1649,56 , 1705,14 , 60,10 , 56,13 , {66,89,82}, 140,2 , 2419,23 , 4,4 , 4,0 , 460,10 , 470,8 , 0, 0, 7, 6, 7 }, // Belarusian/Cyrillic/Belarus + { 23, 20, 36, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 109,9 , 364,8 , 10,17 , 18,7 , 25,12 , 3921,71 , 3921,71 , 158,27 , 3921,71 , 3921,71 , 158,27 , 1719,46 , 1719,46 , 1765,14 , 1719,46 , 1719,46 , 1765,14 , 70,5 , 69,5 , {75,72,82}, 142,1 , 2442,18 , 4,4 , 8,6 , 478,5 , 483,7 , 2, 1, 7, 6, 7 }, // Khmer/Khmer/Cambodia + { 24, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 118,7 , 118,7 , 27,8 , 372,21 , 159,4 , 163,9 , 3992,60 , 4052,82 , 4134,24 , 4158,93 , 4251,115 , 4366,24 , 1779,21 , 1800,60 , 1779,21 , 1860,28 , 1888,60 , 1779,21 , 75,4 , 74,4 , {69,85,82}, 19,1 , 2460,20 , 4,4 , 8,6 , 490,6 , 496,7 , 2, 1, 1, 6, 7 }, // Catalan/Latin/Spain + { 24, 7, 5, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 118,7 , 118,7 , 27,8 , 372,21 , 159,4 , 163,9 , 3992,60 , 4052,82 , 4134,24 , 4158,93 , 4251,115 , 4366,24 , 1779,21 , 1800,60 , 1779,21 , 1860,28 , 1888,60 , 1779,21 , 75,4 , 74,4 , {69,85,82}, 19,1 , 2460,20 , 4,4 , 8,6 , 490,6 , 503,7 , 2, 1, 1, 6, 7 }, // Catalan/Latin/Andorra + { 25, 5, 44, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 393,6 , 399,13 , 172,6 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {67,78,89}, 143,1 , 2480,10 , 4,4 , 8,6 , 510,4 , 514,2 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/China + { 25, 5, 97, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 287,6 , 399,13 , 172,6 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {72,75,68}, 12,1 , 2490,9 , 4,4 , 4,0 , 510,4 , 516,9 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/HongKong + { 25, 5, 126, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 287,6 , 399,13 , 172,6 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {77,79,80}, 144,4 , 2499,10 , 4,4 , 4,0 , 510,4 , 525,9 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/Macau + { 25, 5, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 125,5 , 125,5 , 130,5 , 130,5 , 27,8 , 399,13 , 188,7 , 178,10 , 4390,39 , 4429,38 , 158,27 , 4390,39 , 4429,38 , 158,27 , 1948,21 , 1969,28 , 1997,14 , 1948,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {83,71,68}, 12,1 , 2509,11 , 4,4 , 4,0 , 510,4 , 534,3 , 2, 1, 7, 6, 7 }, // Chinese/Simplified Han/Singapore + { 25, 6, 97, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 130,5 , 130,5 , 287,6 , 399,13 , 172,6 , 195,13 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 2011,21 , 1969,28 , 1997,14 , 2011,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {72,75,68}, 12,1 , 2490,9 , 4,4 , 8,6 , 537,4 , 541,14 , 2, 1, 7, 6, 7 }, // Chinese/Traditional Han/HongKong + { 25, 6, 126, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 130,5 , 130,5 , 412,7 , 419,15 , 172,6 , 195,13 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 2011,21 , 1969,28 , 1997,14 , 2011,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {77,79,80}, 144,4 , 2520,10 , 4,4 , 4,0 , 537,4 , 555,14 , 2, 1, 7, 6, 7 }, // Chinese/Traditional Han/Macau + { 25, 6, 208, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 130,5 , 130,5 , 179,8 , 399,13 , 172,6 , 208,11 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 2011,21 , 1969,28 , 1997,14 , 2011,21 , 1969,28 , 1997,14 , 79,2 , 78,2 , {84,87,68}, 148,3 , 2530,10 , 4,4 , 4,0 , 537,4 , 569,2 , 2, 1, 7, 6, 7 }, // Chinese/Traditional Han/Taiwan + { 27, 7, 54, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 434,9 , 443,19 , 37,5 , 8,10 , 4467,49 , 4516,94 , 4610,39 , 4467,49 , 4649,98 , 4610,39 , 2032,28 , 2060,58 , 2118,14 , 2032,28 , 2060,58 , 2132,14 , 0,2 , 0,2 , {72,82,75}, 151,2 , 2540,74 , 25,5 , 4,0 , 571,8 , 579,8 , 2, 1, 1, 6, 7 }, // Croatian/Latin/Croatia + { 27, 7, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 434,9 , 443,19 , 37,5 , 8,10 , 4467,49 , 4516,94 , 4610,39 , 4467,49 , 4649,98 , 4610,39 , 2032,28 , 2060,58 , 2118,14 , 2032,28 , 2060,58 , 2132,14 , 0,2 , 0,2 , {66,65,77}, 153,2 , 2614,106 , 25,5 , 4,0 , 571,8 , 587,19 , 2, 1, 1, 6, 7 }, // Croatian/Latin/BosniaAndHerzegowina + { 28, 7, 57, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 135,7 , 135,7 , 187,8 , 462,18 , 61,4 , 219,9 , 4747,48 , 4795,82 , 4877,24 , 4747,48 , 4901,84 , 158,27 , 2146,21 , 2167,49 , 2216,14 , 2146,21 , 2167,49 , 2216,14 , 81,4 , 80,4 , {67,90,75}, 155,2 , 2720,56 , 25,5 , 4,0 , 606,7 , 613,15 , 2, 1, 1, 6, 7 }, // Czech/Latin/CzechRepublic + { 29, 7, 58, 44, 46, 44, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 27,8 , 480,23 , 144,5 , 149,10 , 4985,48 , 5033,84 , 134,24 , 5117,59 , 5033,84 , 134,24 , 2230,28 , 2258,51 , 2309,14 , 2323,35 , 2258,51 , 2309,14 , 0,2 , 0,2 , {68,75,75}, 157,2 , 2776,42 , 25,5 , 4,0 , 628,5 , 633,7 , 2, 1, 1, 6, 7 }, // Danish/Latin/Denmark + { 30, 7, 151, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2818,19 , 14,5 , 19,6 , 640,10 , 650,9 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Netherlands + { 30, 7, 12, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {65,87,71}, 159,4 , 2837,55 , 14,5 , 19,6 , 640,10 , 659,5 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Aruba + { 30, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 511,7 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2818,19 , 25,5 , 4,0 , 664,6 , 670,6 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Belgium + { 30, 7, 152, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {65,78,71}, 163,4 , 2892,97 , 14,5 , 19,6 , 640,10 , 676,7 , 2, 1, 1, 6, 7 }, // Dutch/Latin/CuraSao + { 30, 7, 202, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {83,82,68}, 12,1 , 2989,24 , 14,5 , 19,6 , 640,10 , 683,8 , 2, 1, 1, 6, 7 }, // Dutch/Latin/Suriname + { 30, 7, 256, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 6,8 , 6,8 , 503,8 , 99,16 , 37,5 , 8,10 , 5176,48 , 5224,88 , 134,24 , 5312,59 , 5224,88 , 134,24 , 2358,21 , 2379,59 , 2438,14 , 2358,21 , 2379,59 , 2438,14 , 0,2 , 0,2 , {65,78,71}, 163,4 , 2892,97 , 14,5 , 19,6 , 640,10 , 691,12 , 2, 1, 1, 6, 7 }, // Dutch/Latin/SintMaarten + { 31, 7, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 703,12 , 715,13 , 2, 1, 7, 6, 7 }, // English/Latin/UnitedStates + { 31, 3, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 5371,80 , 5451,154 , 5605,36 , 5371,80 , 5451,154 , 5605,36 , 2452,49 , 2501,85 , 2586,21 , 2452,49 , 2501,85 , 2586,21 , 85,4 , 84,4 , {85,83,68}, 12,1 , 0,7 , 14,5 , 4,0 , 728,10 , 738,25 , 2, 1, 7, 6, 7 }, // English/Deseret/UnitedStates + { 31, 7, 4, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 770,14 , 2, 1, 7, 6, 7 }, // English/Latin/AmericanSamoa + { 31, 7, 9, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3048,71 , 4,4 , 8,6 , 763,7 , 784,19 , 2, 1, 7, 6, 7 }, // English/Latin/AntiguaAndBarbuda + { 31, 7, 13, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 511,7 , 10,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {65,85,68}, 12,1 , 3119,59 , 4,4 , 4,0 , 803,18 , 821,9 , 2, 1, 7, 6, 7 }, // English/Latin/Australia + { 31, 7, 16, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,83,68}, 12,1 , 3178,53 , 4,4 , 8,6 , 763,7 , 830,7 , 2, 1, 7, 6, 7 }, // English/Latin/Bahamas + { 31, 7, 19, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,66,68}, 12,1 , 3231,56 , 4,4 , 8,6 , 763,7 , 837,8 , 2, 1, 1, 6, 7 }, // English/Latin/Barbados + { 31, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 27,8 , 99,16 , 37,5 , 228,24 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {69,85,82}, 19,1 , 2818,19 , 25,5 , 4,0 , 763,7 , 845,7 , 2, 1, 1, 6, 7 }, // English/Latin/Belgium + { 31, 7, 22, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 27,8 , 524,12 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,90,68}, 12,1 , 3287,47 , 4,4 , 4,0 , 763,7 , 852,6 , 2, 1, 7, 6, 7 }, // English/Latin/Belize + { 31, 7, 24, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,77,68}, 12,1 , 3334,53 , 4,4 , 8,6 , 763,7 , 858,7 , 2, 1, 1, 6, 7 }, // English/Latin/Bermuda + { 31, 7, 28, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 27,8 , 82,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {66,87,80}, 170,1 , 3387,50 , 4,4 , 4,0 , 763,7 , 865,8 , 2, 1, 7, 6, 7 }, // English/Latin/Botswana + { 31, 7, 37, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,65,70}, 37,4 , 3437,50 , 4,4 , 8,6 , 763,7 , 873,8 , 0, 0, 1, 6, 7 }, // English/Latin/Cameroon + { 31, 7, 38, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {67,65,68}, 12,1 , 3487,53 , 4,4 , 8,6 , 881,16 , 897,6 , 2, 0, 7, 6, 7 }, // English/Latin/Canada + { 31, 7, 40, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {75,89,68}, 12,1 , 3540,71 , 4,4 , 8,6 , 763,7 , 903,14 , 2, 1, 1, 6, 7 }, // English/Latin/CaymanIslands + { 31, 7, 60, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3048,71 , 4,4 , 8,6 , 763,7 , 917,8 , 2, 1, 7, 6, 7 }, // English/Latin/Dominica + { 31, 7, 72, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {70,74,68}, 12,1 , 3611,47 , 4,4 , 8,6 , 763,7 , 925,4 , 2, 1, 1, 6, 7 }, // English/Latin/Fiji + { 31, 7, 75, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3658,47 , 4,4 , 4,0 , 763,7 , 929,8 , 2, 1, 1, 6, 7 }, // English/Latin/Guernsey + { 31, 7, 80, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {71,77,68}, 172,1 , 3705,50 , 4,4 , 8,6 , 763,7 , 937,6 , 2, 1, 1, 6, 7 }, // English/Latin/Gambia + { 31, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {71,72,83}, 173,3 , 3755,47 , 4,4 , 8,6 , 763,7 , 943,5 , 2, 1, 1, 6, 7 }, // English/Latin/Ghana + { 31, 7, 84, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,73,80}, 171,1 , 3802,53 , 4,4 , 4,0 , 763,7 , 948,9 , 2, 1, 1, 6, 7 }, // English/Latin/Gibraltar + { 31, 7, 87, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3048,71 , 4,4 , 8,6 , 763,7 , 957,7 , 2, 1, 1, 6, 7 }, // English/Latin/Grenada + { 31, 7, 89, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 964,4 , 2, 1, 7, 6, 7 }, // English/Latin/Guam + { 31, 7, 93, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {71,89,68}, 12,1 , 3855,56 , 4,4 , 8,6 , 763,7 , 968,6 , 0, 0, 1, 6, 7 }, // English/Latin/Guyana + { 31, 7, 97, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 287,6 , 224,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {72,75,68}, 12,1 , 3911,56 , 4,4 , 8,6 , 763,7 , 974,19 , 2, 1, 7, 6, 7 }, // English/Latin/HongKong + { 31, 7, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 27,8 , 99,16 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {73,78,82}, 123,1 , 3967,44 , 14,5 , 4,0 , 763,7 , 993,5 , 2, 1, 7, 7, 7 }, // English/Latin/India + { 31, 7, 104, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 99,16 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 75,4 , 74,4 , {69,85,82}, 19,1 , 2818,19 , 4,4 , 4,0 , 763,7 , 998,7 , 2, 1, 7, 6, 7 }, // English/Latin/Ireland + { 31, 7, 107, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 287,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {74,77,68}, 12,1 , 4011,53 , 4,4 , 4,0 , 763,7 , 1005,7 , 2, 1, 7, 6, 7 }, // English/Latin/Jamaica + { 31, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {75,69,83}, 2,3 , 4064,53 , 4,4 , 8,6 , 763,7 , 1012,5 , 2, 1, 7, 6, 7 }, // English/Latin/Kenya + { 31, 7, 112, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {65,85,68}, 12,1 , 3119,59 , 4,4 , 8,6 , 763,7 , 1017,8 , 2, 1, 1, 6, 7 }, // English/Latin/Kiribati + { 31, 7, 120, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 4117,61 , 4,4 , 8,6 , 763,7 , 1025,7 , 2, 1, 1, 6, 7 }, // English/Latin/Lesotho + { 31, 7, 121, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {76,82,68}, 12,1 , 4178,53 , 4,4 , 8,6 , 763,7 , 1032,7 , 2, 1, 1, 6, 7 }, // English/Latin/Liberia + { 31, 7, 128, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {77,71,65}, 176,2 , 4231,54 , 4,4 , 8,6 , 763,7 , 1039,10 , 0, 0, 1, 6, 7 }, // English/Latin/Madagascar + { 31, 7, 129, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {77,87,75}, 178,2 , 4285,53 , 4,4 , 8,6 , 763,7 , 1049,6 , 2, 1, 1, 6, 7 }, // English/Latin/Malawi + { 31, 7, 133, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {69,85,82}, 19,1 , 2818,19 , 4,4 , 4,0 , 763,7 , 1055,5 , 2, 1, 7, 6, 7 }, // English/Latin/Malta + { 31, 7, 134, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1060,16 , 2, 1, 7, 6, 7 }, // English/Latin/MarshallIslands + { 31, 7, 137, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {77,85,82}, 180,2 , 4338,53 , 4,4 , 8,6 , 763,7 , 1076,9 , 0, 0, 1, 6, 7 }, // English/Latin/Mauritius + { 31, 7, 140, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1085,10 , 2, 1, 1, 6, 7 }, // English/Latin/Micronesia + { 31, 7, 148, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {78,65,68}, 12,1 , 4391,53 , 4,4 , 4,0 , 763,7 , 1095,7 , 2, 1, 1, 6, 7 }, // English/Latin/Namibia + { 31, 7, 154, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 511,7 , 10,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {78,90,68}, 12,1 , 4444,62 , 4,4 , 4,0 , 763,7 , 1102,11 , 2, 1, 7, 6, 7 }, // English/Latin/NewZealand + { 31, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {78,71,78}, 182,1 , 4506,50 , 4,4 , 8,6 , 763,7 , 1113,7 , 2, 1, 1, 6, 7 }, // English/Latin/Nigeria + { 31, 7, 160, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1120,24 , 2, 1, 1, 6, 7 }, // English/Latin/NorthernMarianaIslands + { 31, 7, 163, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 27,8 , 99,16 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {80,75,82}, 180,2 , 4556,53 , 14,5 , 4,0 , 763,7 , 1144,8 , 0, 0, 7, 6, 7 }, // English/Latin/Pakistan + { 31, 7, 164, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1152,5 , 2, 1, 1, 6, 7 }, // English/Latin/Palau + { 31, 7, 167, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {80,71,75}, 139,1 , 4609,73 , 4,4 , 8,6 , 763,7 , 1157,16 , 2, 1, 1, 6, 7 }, // English/Latin/PapuaNewGuinea + { 31, 7, 170, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {80,72,80}, 183,1 , 4682,42 , 4,4 , 8,6 , 763,7 , 1173,11 , 2, 1, 7, 6, 7 }, // English/Latin/Philippines + { 31, 7, 174, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1184,11 , 2, 1, 7, 6, 7 }, // English/Latin/PuertoRico + { 31, 7, 180, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3048,71 , 4,4 , 8,6 , 763,7 , 1195,21 , 2, 1, 1, 6, 7 }, // English/Latin/SaintKittsAndNevis + { 31, 7, 181, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3048,71 , 4,4 , 8,6 , 763,7 , 1216,11 , 2, 1, 1, 6, 7 }, // English/Latin/SaintLucia + { 31, 7, 182, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {88,67,68}, 167,3 , 3048,71 , 4,4 , 8,6 , 763,7 , 1227,32 , 2, 1, 1, 6, 7 }, // English/Latin/SaintVincentAndTheGrenadines + { 31, 7, 183, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {87,83,84}, 184,3 , 4724,40 , 4,4 , 8,6 , 763,7 , 1259,5 , 2, 1, 7, 6, 7 }, // English/Latin/Samoa + { 31, 7, 188, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,67,82}, 187,2 , 4764,59 , 4,4 , 8,6 , 763,7 , 1264,10 , 2, 1, 1, 6, 7 }, // English/Latin/Seychelles + { 31, 7, 189, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,76,76}, 189,2 , 4823,68 , 4,4 , 8,6 , 763,7 , 1274,12 , 0, 0, 1, 6, 7 }, // English/Latin/SierraLeone + { 31, 7, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 287,6 , 224,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {83,71,68}, 12,1 , 4891,56 , 4,4 , 8,6 , 763,7 , 1286,9 , 2, 1, 7, 6, 7 }, // English/Latin/Singapore + { 31, 7, 193, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,66,68}, 12,1 , 4947,74 , 4,4 , 8,6 , 763,7 , 1295,15 , 2, 1, 1, 6, 7 }, // English/Latin/SolomonIslands + { 31, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 536,10 , 82,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 4117,61 , 4,4 , 8,6 , 763,7 , 1310,12 , 2, 1, 7, 6, 7 }, // English/Latin/SouthAfrica + { 31, 7, 204, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,90,76}, 191,1 , 5021,53 , 4,4 , 8,6 , 763,7 , 1322,9 , 2, 1, 1, 6, 7 }, // English/Latin/Swaziland + { 31, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {84,90,83}, 192,3 , 5074,62 , 4,4 , 8,6 , 763,7 , 1331,8 , 0, 0, 1, 6, 7 }, // English/Latin/Tanzania + { 31, 7, 214, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {84,79,80}, 195,2 , 5136,49 , 4,4 , 8,6 , 763,7 , 1339,5 , 2, 1, 1, 6, 7 }, // English/Latin/Tonga + { 31, 7, 215, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {84,84,68}, 12,1 , 5185,86 , 4,4 , 4,0 , 763,7 , 1344,19 , 2, 1, 7, 6, 7 }, // English/Latin/TrinidadAndTobago + { 31, 7, 219, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1363,24 , 2, 1, 1, 6, 7 }, // English/Latin/TurksAndCaicosIslands + { 31, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 5271,56 , 4,4 , 8,6 , 763,7 , 1387,6 , 0, 0, 1, 6, 7 }, // English/Latin/Uganda + { 31, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3658,47 , 4,4 , 4,0 , 1393,15 , 1408,14 , 2, 1, 1, 6, 7 }, // English/Latin/UnitedKingdom + { 31, 7, 226, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1422,21 , 2, 1, 7, 6, 7 }, // English/Latin/UnitedStatesMinorOutlyingIslands + { 31, 7, 229, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {86,85,86}, 200,2 , 5327,44 , 4,4 , 8,6 , 763,7 , 1443,7 , 0, 0, 1, 6, 7 }, // English/Latin/Vanuatu + { 31, 7, 233, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1450,22 , 2, 1, 1, 6, 7 }, // English/Latin/BritishVirginIslands + { 31, 7, 234, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 3013,35 , 4,4 , 8,6 , 763,7 , 1472,19 , 2, 1, 7, 6, 7 }, // English/Latin/UnitedStatesVirginIslands + { 31, 7, 239, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {90,77,87}, 202,2 , 5371,50 , 4,4 , 8,6 , 763,7 , 1491,6 , 2, 1, 1, 6, 7 }, // English/Latin/Zambia + { 31, 7, 240, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 364,8 , 82,17 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 3013,35 , 4,4 , 4,0 , 763,7 , 1497,8 , 2, 1, 7, 6, 7 }, // English/Latin/Zimbabwe + { 31, 7, 251, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3658,47 , 4,4 , 4,0 , 763,7 , 1505,11 , 2, 1, 1, 6, 7 }, // English/Latin/IsleOfMan + { 31, 7, 252, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 160,9 , 160,9 , 141,10 , 10,17 , 37,5 , 8,10 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 89,2 , 88,2 , {71,66,80}, 171,1 , 3658,47 , 4,4 , 4,0 , 763,7 , 1516,6 , 2, 1, 1, 6, 7 }, // English/Latin/Jersey + { 31, 7, 254, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 150,10 , 160,9 , 518,6 , 35,18 , 18,7 , 25,12 , 0,48 , 48,86 , 134,24 , 0,48 , 48,86 , 134,24 , 0,28 , 28,57 , 85,14 , 0,28 , 28,57 , 85,14 , 0,2 , 0,2 , {83,83,80}, 171,1 , 5421,68 , 4,4 , 8,6 , 763,7 , 1522,11 , 2, 1, 1, 6, 7 }, // English/Latin/SouthSudan + { 33, 7, 68, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 169,8 , 169,8 , 187,8 , 462,18 , 61,4 , 252,9 , 5641,59 , 5700,91 , 5791,24 , 5641,59 , 5700,91 , 5791,24 , 2607,14 , 2621,63 , 2607,14 , 2607,14 , 2621,63 , 2607,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 5489,20 , 25,5 , 30,7 , 1533,5 , 1538,5 , 2, 1, 1, 6, 7 }, // Estonian/Latin/Estonia + { 34, 7, 71, 44, 46, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 503,8 , 82,17 , 37,5 , 8,10 , 5815,48 , 5863,83 , 134,24 , 5815,48 , 5863,83 , 134,24 , 2684,28 , 2712,74 , 2786,14 , 2684,28 , 2712,74 , 2786,14 , 0,2 , 0,2 , {68,75,75}, 157,2 , 5509,42 , 4,4 , 43,5 , 1543,8 , 1551,7 , 2, 1, 1, 6, 7 }, // Faroese/Latin/FaroeIslands + { 36, 7, 73, 44, 160, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 169,8 , 169,8 , 546,8 , 554,17 , 159,4 , 163,9 , 5946,69 , 6015,105 , 6120,24 , 6144,129 , 6144,129 , 6120,24 , 2800,21 , 2821,67 , 2888,14 , 2800,21 , 2902,81 , 2888,14 , 91,3 , 90,3 , {69,85,82}, 19,1 , 5551,20 , 25,5 , 4,0 , 1558,5 , 1563,5 , 2, 1, 1, 6, 7 }, // Finnish/Latin/Finland + { 37, 7, 74, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1576,6 , 2, 1, 1, 6, 7 }, // French/Latin/France + { 37, 7, 3, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {68,90,68}, 207,2 , 5571,51 , 25,5 , 30,7 , 1568,8 , 1582,7 , 2, 1, 6, 4, 5 }, // French/Latin/Algeria + { 37, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 511,7 , 99,16 , 37,5 , 261,23 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1589,8 , 2, 1, 1, 6, 7 }, // French/Latin/Belgium + { 37, 7, 23, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5622,59 , 25,5 , 30,7 , 1568,8 , 1597,5 , 0, 0, 1, 6, 7 }, // French/Latin/Benin + { 37, 7, 34, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5622,59 , 25,5 , 30,7 , 1568,8 , 1602,12 , 0, 0, 1, 6, 7 }, // French/Latin/BurkinaFaso + { 37, 7, 35, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {66,73,70}, 212,3 , 5681,53 , 25,5 , 30,7 , 1568,8 , 1614,7 , 0, 0, 1, 6, 7 }, // French/Latin/Burundi + { 37, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 37,4 , 5734,56 , 25,5 , 30,7 , 1568,8 , 1621,8 , 0, 0, 1, 6, 7 }, // French/Latin/Cameroon + { 37, 7, 38, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 177,8 , 177,8 , 115,8 , 99,16 , 37,5 , 228,24 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {67,65,68}, 12,1 , 5790,54 , 25,5 , 30,7 , 1629,17 , 897,6 , 2, 0, 7, 6, 7 }, // French/Latin/Canada + { 37, 7, 41, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 37,4 , 5734,56 , 25,5 , 30,7 , 1568,8 , 1646,25 , 0, 0, 1, 6, 7 }, // French/Latin/CentralAfricanRepublic + { 37, 7, 42, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 37,4 , 5734,56 , 25,5 , 30,7 , 1568,8 , 1671,5 , 0, 0, 1, 6, 7 }, // French/Latin/Chad + { 37, 7, 48, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {75,77,70}, 215,2 , 5844,51 , 25,5 , 30,7 , 1568,8 , 1676,7 , 0, 0, 1, 6, 7 }, // French/Latin/Comoros + { 37, 7, 49, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {67,68,70}, 217,2 , 5895,53 , 25,5 , 30,7 , 1568,8 , 1683,32 , 2, 1, 1, 6, 7 }, // French/Latin/CongoKinshasa + { 37, 7, 50, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 37,4 , 5734,56 , 25,5 , 30,7 , 1568,8 , 1715,17 , 0, 0, 1, 6, 7 }, // French/Latin/CongoBrazzaville + { 37, 7, 53, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5622,59 , 25,5 , 30,7 , 1568,8 , 1732,13 , 0, 0, 1, 6, 7 }, // French/Latin/IvoryCoast + { 37, 7, 59, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {68,74,70}, 5,3 , 5948,57 , 25,5 , 30,7 , 1568,8 , 1745,8 , 0, 0, 6, 6, 7 }, // French/Latin/Djibouti + { 37, 7, 66, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 37,4 , 5734,56 , 25,5 , 30,7 , 1568,8 , 1753,18 , 0, 0, 1, 6, 7 }, // French/Latin/EquatorialGuinea + { 37, 7, 76, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1771,16 , 2, 1, 1, 6, 7 }, // French/Latin/FrenchGuiana + { 37, 7, 77, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,80,70}, 219,4 , 6005,35 , 25,5 , 30,7 , 1568,8 , 1787,19 , 0, 0, 1, 6, 7 }, // French/Latin/FrenchPolynesia + { 37, 7, 79, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,65,70}, 37,4 , 5734,56 , 25,5 , 30,7 , 1568,8 , 1806,5 , 0, 0, 1, 6, 7 }, // French/Latin/Gabon + { 37, 7, 88, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1811,10 , 2, 1, 1, 6, 7 }, // French/Latin/Guadeloupe + { 37, 7, 91, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {71,78,70}, 223,2 , 6040,48 , 25,5 , 30,7 , 1568,8 , 1821,6 , 0, 0, 1, 6, 7 }, // French/Latin/Guinea + { 37, 7, 94, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {72,84,71}, 225,1 , 6088,57 , 25,5 , 30,7 , 1568,8 , 1827,5 , 2, 1, 1, 6, 7 }, // French/Latin/Haiti + { 37, 7, 125, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1832,10 , 2, 1, 1, 6, 7 }, // French/Latin/Luxembourg + { 37, 7, 128, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,71,65}, 176,2 , 6145,54 , 25,5 , 30,7 , 1568,8 , 1039,10 , 0, 0, 1, 6, 7 }, // French/Latin/Madagascar + { 37, 7, 132, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5622,59 , 25,5 , 30,7 , 1568,8 , 1842,4 , 0, 0, 1, 6, 7 }, // French/Latin/Mali + { 37, 7, 135, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1846,10 , 2, 1, 1, 6, 7 }, // French/Latin/Martinique + { 37, 7, 136, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,82,79}, 226,2 , 6199,66 , 25,5 , 30,7 , 1568,8 , 1856,10 , 0, 0, 1, 6, 7 }, // French/Latin/Mauritania + { 37, 7, 137, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,85,82}, 180,2 , 6265,63 , 25,5 , 30,7 , 1568,8 , 1866,7 , 0, 0, 1, 6, 7 }, // French/Latin/Mauritius + { 37, 7, 138, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1873,7 , 2, 1, 1, 6, 7 }, // French/Latin/Mayotte + { 37, 7, 142, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1880,6 , 2, 1, 1, 6, 7 }, // French/Latin/Monaco + { 37, 7, 145, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {77,65,68}, 0,0 , 6328,54 , 25,5 , 30,7 , 1568,8 , 1886,5 , 2, 1, 6, 5, 6 }, // French/Latin/Morocco + { 37, 7, 153, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,80,70}, 219,4 , 6005,35 , 25,5 , 30,7 , 1568,8 , 1891,18 , 0, 0, 1, 6, 7 }, // French/Latin/NewCaledonia + { 37, 7, 156, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5622,59 , 25,5 , 30,7 , 1568,8 , 1909,5 , 0, 0, 1, 6, 7 }, // French/Latin/Niger + { 37, 7, 176, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1914,7 , 2, 1, 1, 6, 7 }, // French/Latin/Reunion + { 37, 7, 179, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {82,87,70}, 228,2 , 6382,50 , 25,5 , 30,7 , 1568,8 , 1921,6 , 0, 0, 1, 6, 7 }, // French/Latin/Rwanda + { 37, 7, 187, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5622,59 , 25,5 , 30,7 , 1568,8 , 1927,7 , 0, 0, 1, 6, 7 }, // French/Latin/Senegal + { 37, 7, 188, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {83,67,82}, 187,2 , 6432,71 , 25,5 , 30,7 , 1568,8 , 1264,10 , 2, 1, 1, 6, 7 }, // French/Latin/Seychelles + { 37, 7, 206, 46, 39, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 177,8 , 177,8 , 187,8 , 10,17 , 37,5 , 284,14 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {67,72,70}, 230,3 , 6503,45 , 14,5 , 48,5 , 1934,15 , 1949,6 , 2, 0, 1, 6, 7 }, // French/Latin/Switzerland + { 37, 7, 207, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {83,89,80}, 233,2 , 6548,51 , 25,5 , 30,7 , 1568,8 , 1955,5 , 0, 0, 6, 5, 6 }, // French/Latin/Syria + { 37, 7, 212, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 5622,59 , 25,5 , 30,7 , 1568,8 , 1960,4 , 0, 0, 1, 6, 7 }, // French/Latin/Togo + { 37, 7, 216, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {84,78,68}, 235,2 , 6599,51 , 25,5 , 30,7 , 1568,8 , 1964,7 , 3, 0, 7, 5, 6 }, // French/Latin/Tunisia + { 37, 7, 229, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {86,85,86}, 200,2 , 6650,51 , 25,5 , 30,7 , 1568,8 , 1443,7 , 0, 0, 1, 6, 7 }, // French/Latin/Vanuatu + { 37, 7, 244, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1971,16 , 2, 1, 1, 6, 7 }, // French/Latin/Saint Barthelemy + { 37, 7, 245, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 177,8 , 177,8 , 141,10 , 99,16 , 37,5 , 8,10 , 6273,63 , 6336,85 , 134,24 , 6273,63 , 6336,85 , 134,24 , 2983,35 , 3018,52 , 3070,14 , 2983,35 , 3018,52 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 30,7 , 1568,8 , 1987,31 , 2, 1, 1, 6, 7 }, // French/Latin/Saint Martin + { 39, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 185,11 , 196,10 , 141,10 , 10,17 , 37,5 , 8,10 , 6421,61 , 6482,142 , 6624,36 , 6421,61 , 6482,142 , 6624,36 , 3084,28 , 3112,69 , 3181,14 , 3084,28 , 3112,69 , 3181,14 , 0,2 , 0,2 , {71,66,80}, 171,1 , 6701,22 , 4,4 , 8,6 , 2018,8 , 2026,22 , 2, 1, 1, 6, 7 }, // Gaelic/Latin/UnitedKingdom + { 40, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 82,17 , 37,5 , 8,10 , 6660,48 , 6708,87 , 6795,24 , 6660,48 , 6708,87 , 6795,24 , 3195,28 , 3223,49 , 3272,14 , 3195,28 , 3223,49 , 3272,14 , 75,4 , 74,4 , {69,85,82}, 19,1 , 6723,20 , 4,4 , 8,6 , 2048,6 , 2054,6 , 2, 1, 1, 6, 7 }, // Galician/Latin/Spain + { 41, 15, 81, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8222, 8220, 0,6 , 0,6 , 213,8 , 213,8 , 187,8 , 571,19 , 37,5 , 8,10 , 6819,48 , 6867,99 , 6966,24 , 6819,48 , 6867,99 , 6966,24 , 3286,28 , 3314,62 , 3376,14 , 3286,28 , 3314,62 , 3376,14 , 0,2 , 0,2 , {71,69,76}, 0,0 , 6743,19 , 25,5 , 4,0 , 2060,7 , 2067,10 , 2, 1, 1, 6, 7 }, // Georgian/Georgian/Georgia + { 42, 7, 82, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 19,1 , 6762,19 , 25,5 , 4,0 , 2077,7 , 2084,11 , 2, 1, 1, 6, 7 }, // German/Latin/Germany + { 42, 7, 14, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 590,19 , 37,5 , 8,10 , 7180,48 , 7038,83 , 134,24 , 7228,58 , 7286,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 19,1 , 6762,19 , 14,5 , 4,0 , 2095,24 , 2119,10 , 2, 1, 1, 6, 7 }, // German/Latin/Austria + { 42, 7, 21, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 19,1 , 6762,19 , 25,5 , 4,0 , 2077,7 , 2129,7 , 2, 1, 1, 6, 7 }, // German/Latin/Belgium + { 42, 7, 123, 46, 39, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {67,72,70}, 0,0 , 6781,58 , 14,5 , 4,0 , 2077,7 , 2136,13 , 2, 0, 1, 6, 7 }, // German/Latin/Liechtenstein + { 42, 7, 125, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {69,85,82}, 19,1 , 6762,19 , 25,5 , 4,0 , 2077,7 , 2149,9 , 2, 1, 1, 6, 7 }, // German/Latin/Luxembourg + { 42, 7, 206, 46, 39, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 7038,83 , 134,24 , 7121,59 , 7038,83 , 134,24 , 3390,21 , 3411,60 , 3471,14 , 3485,28 , 3411,60 , 3471,14 , 94,5 , 93,6 , {67,72,70}, 230,3 , 6781,58 , 14,5 , 48,5 , 2158,21 , 2179,7 , 2, 0, 1, 6, 7 }, // German/Latin/Switzerland + { 43, 16, 85, 44, 46, 44, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 230,9 , 230,9 , 287,6 , 10,17 , 18,7 , 25,12 , 7369,50 , 7419,115 , 7534,24 , 7558,50 , 7608,115 , 7534,24 , 3513,28 , 3541,55 , 3596,14 , 3513,28 , 3541,55 , 3596,14 , 99,4 , 99,4 , {69,85,82}, 19,1 , 6839,19 , 25,5 , 4,0 , 2186,8 , 2194,6 , 2, 1, 1, 6, 7 }, // Greek/Greek/Greece + { 43, 16, 56, 44, 46, 44, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 230,9 , 230,9 , 287,6 , 10,17 , 18,7 , 25,12 , 7369,50 , 7419,115 , 7534,24 , 7558,50 , 7608,115 , 7534,24 , 3513,28 , 3541,55 , 3596,14 , 3513,28 , 3541,55 , 3596,14 , 99,4 , 99,4 , {69,85,82}, 19,1 , 6839,19 , 4,4 , 4,0 , 2186,8 , 2200,6 , 2, 1, 1, 6, 7 }, // Greek/Greek/Cyprus + { 44, 7, 86, 44, 46, 59, 37, 48, 8722, 43, 101, 187, 171, 8250, 8249, 0,6 , 0,6 , 239,11 , 239,11 , 72,10 , 82,17 , 18,7 , 25,12 , 4985,48 , 7723,96 , 134,24 , 4985,48 , 7723,96 , 134,24 , 3610,28 , 3638,98 , 3736,14 , 3610,28 , 3638,98 , 3736,14 , 0,2 , 0,2 , {68,75,75}, 157,2 , 6858,59 , 4,4 , 43,5 , 2206,11 , 2217,16 , 2, 1, 1, 6, 7 }, // Greenlandic/Latin/Greenland + { 46, 17, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 250,9 , 250,9 , 609,7 , 224,18 , 298,8 , 306,13 , 7819,64 , 7883,87 , 7970,31 , 8001,67 , 8068,87 , 7970,31 , 3750,32 , 3782,53 , 3835,19 , 3750,32 , 3782,53 , 3835,19 , 0,2 , 0,2 , {73,78,82}, 123,1 , 6917,20 , 4,4 , 8,6 , 2233,7 , 2240,4 , 2, 1, 7, 7, 7 }, // Gujarati/Gujarati/India + { 47, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 224,18 , 37,5 , 8,10 , 8155,48 , 8203,85 , 8288,24 , 8155,48 , 8203,85 , 8288,24 , 3854,21 , 3875,52 , 3927,14 , 3854,21 , 3875,52 , 3927,14 , 0,2 , 0,2 , {78,71,78}, 182,1 , 6937,12 , 14,5 , 4,0 , 2244,5 , 2249,8 , 2, 1, 1, 6, 7 }, // Hausa/Latin/Nigeria + { 47, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 224,18 , 37,5 , 8,10 , 8155,48 , 8203,85 , 8288,24 , 8155,48 , 8203,85 , 8288,24 , 3854,21 , 3875,52 , 3927,14 , 3854,21 , 3875,52 , 3927,14 , 0,2 , 0,2 , {71,72,83}, 173,3 , 0,7 , 14,5 , 4,0 , 2244,5 , 2257,4 , 2, 1, 1, 6, 7 }, // Hausa/Latin/Ghana + { 47, 7, 156, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 224,18 , 37,5 , 8,10 , 8155,48 , 8203,85 , 8288,24 , 8155,48 , 8203,85 , 8288,24 , 3854,21 , 3875,52 , 3927,14 , 3854,21 , 3875,52 , 3927,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 6949,36 , 14,5 , 4,0 , 2244,5 , 2261,5 , 0, 0, 1, 6, 7 }, // Hausa/Latin/Niger + { 48, 18, 105, 46, 44, 59, 37, 48, 45, 43, 101, 34, 34, 39, 39, 0,6 , 0,6 , 259,6 , 259,6 , 27,8 , 616,18 , 37,5 , 8,10 , 8312,58 , 8370,72 , 158,27 , 8442,48 , 8370,72 , 158,27 , 3941,46 , 3987,65 , 4052,19 , 3941,46 , 3987,65 , 4071,21 , 103,6 , 103,5 , {73,76,83}, 53,1 , 6985,54 , 25,5 , 4,0 , 2266,5 , 2271,5 , 2, 1, 7, 5, 6 }, // Hebrew/Hebrew/Israel + { 49, 13, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 265,9 , 274,8 , 634,6 , 10,17 , 18,7 , 25,12 , 8490,75 , 8490,75 , 8565,30 , 8490,75 , 8490,75 , 8565,30 , 4092,38 , 4130,57 , 4187,19 , 4092,38 , 4130,57 , 4187,19 , 109,9 , 108,7 , {73,78,82}, 123,1 , 7039,19 , 14,5 , 4,0 , 2276,6 , 2282,4 , 2, 1, 7, 7, 7 }, // Hindi/Devanagari/India + { 50, 7, 98, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 187, 171, 0,6 , 0,6 , 282,8 , 282,8 , 640,11 , 651,19 , 61,4 , 219,9 , 8595,64 , 8659,98 , 8757,25 , 8595,64 , 8659,98 , 8782,25 , 4206,19 , 4225,52 , 4277,17 , 4206,19 , 4225,52 , 4277,17 , 118,3 , 115,3 , {72,85,70}, 237,2 , 7058,20 , 25,5 , 4,0 , 2286,6 , 2292,12 , 0, 0, 1, 6, 7 }, // Hungarian/Latin/Hungary + { 51, 7, 99, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 142,8 , 142,8 , 546,8 , 462,18 , 37,5 , 8,10 , 8807,48 , 8855,82 , 8937,24 , 8807,48 , 8855,82 , 8961,24 , 4294,28 , 4322,81 , 4403,14 , 4294,28 , 4322,81 , 4417,14 , 121,4 , 118,4 , {73,83,75}, 157,2 , 7078,49 , 4,4 , 8,6 , 2304,8 , 2312,6 , 0, 0, 1, 6, 7 }, // Icelandic/Latin/Iceland + { 52, 7, 101, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 27,8 , 123,18 , 144,5 , 149,10 , 8985,48 , 9033,87 , 134,24 , 8985,48 , 9033,87 , 134,24 , 4431,28 , 4459,43 , 4502,14 , 4431,28 , 4459,43 , 4502,14 , 0,2 , 0,2 , {73,68,82}, 239,2 , 7127,23 , 4,4 , 4,0 , 2318,16 , 2334,9 , 0, 0, 7, 6, 7 }, // Indonesian/Latin/Indonesia + { 53, 7, 74, 44, 46, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 9120,48 , 9168,93 , 158,27 , 9120,48 , 9168,93 , 158,27 , 4516,28 , 4544,57 , 85,14 , 4516,28 , 4544,57 , 85,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 7150,12 , 14,5 , 4,0 , 2343,11 , 2354,7 , 2, 1, 1, 6, 7 }, // Interlingua/Latin/France + { 57, 7, 104, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 99,16 , 37,5 , 8,10 , 9261,62 , 9323,107 , 9430,24 , 9261,62 , 9323,107 , 9430,24 , 4601,37 , 4638,75 , 4713,14 , 4601,37 , 4638,75 , 4713,14 , 75,4 , 74,4 , {69,85,82}, 19,1 , 81,11 , 4,4 , 4,0 , 2361,7 , 2368,4 , 2, 1, 7, 6, 7 }, // Irish/Latin/Ireland + { 58, 7, 106, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 309,8 , 206,7 , 27,8 , 99,16 , 37,5 , 8,10 , 9454,48 , 9502,94 , 9596,24 , 9454,48 , 9620,94 , 9596,24 , 4727,28 , 4755,57 , 4812,14 , 4727,28 , 4826,57 , 4812,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2818,19 , 14,5 , 4,0 , 2372,8 , 2380,6 , 2, 1, 1, 6, 7 }, // Italian/Latin/Italy + { 58, 7, 184, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 309,8 , 206,7 , 27,8 , 99,16 , 37,5 , 8,10 , 9454,48 , 9502,94 , 9596,24 , 9454,48 , 9620,94 , 9596,24 , 4727,28 , 4755,57 , 4812,14 , 4727,28 , 4826,57 , 4812,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2818,19 , 14,5 , 4,0 , 2372,8 , 2386,10 , 2, 1, 1, 6, 7 }, // Italian/Latin/SanMarino + { 58, 7, 206, 46, 39, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 309,8 , 206,7 , 187,8 , 10,17 , 37,5 , 284,14 , 9454,48 , 9502,94 , 9596,24 , 9454,48 , 9620,94 , 9596,24 , 4727,28 , 4755,57 , 4812,14 , 4727,28 , 4826,57 , 4812,14 , 0,2 , 0,2 , {67,72,70}, 230,3 , 7162,53 , 14,5 , 48,5 , 2372,8 , 2396,8 , 2, 0, 1, 6, 7 }, // Italian/Latin/Switzerland + { 59, 19, 108, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 125,5 , 125,5 , 125,5 , 125,5 , 536,10 , 399,13 , 61,4 , 319,10 , 4390,39 , 4390,39 , 158,27 , 4390,39 , 4390,39 , 158,27 , 4883,14 , 4897,28 , 4883,14 , 4883,14 , 4897,28 , 4883,14 , 125,2 , 122,2 , {74,80,89}, 143,1 , 7215,10 , 4,4 , 4,0 , 2404,3 , 2407,2 , 0, 0, 7, 6, 7 }, // Japanese/Japanese/Japan + { 61, 21, 100, 46, 44, 59, 37, 48, 45, 43, 3208, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 317,12 , 329,11 , 634,6 , 99,16 , 298,8 , 306,13 , 9714,91 , 9805,86 , 9891,31 , 9714,91 , 9805,86 , 9922,31 , 4925,28 , 4953,53 , 5006,19 , 4925,28 , 4953,53 , 5006,19 , 0,2 , 0,2 , {73,78,82}, 123,1 , 7225,20 , 4,4 , 8,6 , 2409,5 , 2414,4 , 2, 1, 7, 7, 7 }, // Kannada/Kannada/India + { 62, 1, 100, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 518,6 , 35,18 , 18,7 , 25,12 , 9953,72 , 9953,72 , 10025,24 , 9953,72 , 9953,72 , 10025,24 , 5025,54 , 5079,56 , 5135,14 , 5025,54 , 5079,56 , 5135,14 , 0,2 , 0,2 , {73,78,82}, 123,1 , 7245,23 , 14,5 , 4,0 , 2418,5 , 2423,10 , 2, 1, 7, 7, 7 }, // Kashmiri/Arabic/India + { 63, 2, 110, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 187,8 , 670,22 , 37,5 , 8,10 , 10049,61 , 10110,83 , 158,27 , 10049,61 , 10110,83 , 158,27 , 5149,28 , 5177,54 , 85,14 , 5149,28 , 5177,54 , 85,14 , 0,2 , 0,2 , {75,90,84}, 241,1 , 7268,24 , 25,5 , 4,0 , 2433,10 , 2443,9 , 2, 1, 1, 6, 7 }, // Kazakh/Cyrillic/Kazakhstan + { 64, 7, 179, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 10193,60 , 10253,101 , 158,27 , 10193,60 , 10253,101 , 158,27 , 5231,35 , 5266,84 , 85,14 , 5231,35 , 5266,84 , 85,14 , 0,2 , 0,2 , {82,87,70}, 228,2 , 0,7 , 14,5 , 4,0 , 2452,11 , 1921,6 , 0, 0, 1, 6, 7 }, // Kinyarwanda/Latin/Rwanda + { 65, 2, 116, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 0,6 , 0,6 , 187,8 , 670,22 , 37,5 , 8,10 , 10354,60 , 10414,80 , 158,27 , 10494,59 , 10553,80 , 158,27 , 5350,28 , 5378,57 , 85,14 , 5435,28 , 5463,57 , 85,14 , 0,2 , 0,2 , {75,71,83}, 242,3 , 0,7 , 14,5 , 4,0 , 2463,6 , 2469,10 , 2, 1, 1, 6, 7 }, // Kirghiz/Cyrillic/Kyrgyzstan + { 66, 22, 114, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 340,7 , 340,7 , 692,9 , 701,16 , 329,7 , 336,13 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 5520,14 , 5534,28 , 5520,14 , 5520,14 , 5534,28 , 5520,14 , 127,2 , 124,2 , {75,82,87}, 245,1 , 7292,13 , 4,4 , 8,6 , 2479,3 , 2482,4 , 0, 0, 7, 6, 7 }, // Korean/Korean/SouthKorea + { 66, 22, 113, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 340,7 , 340,7 , 692,9 , 701,16 , 329,7 , 336,13 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 10633,39 , 5520,14 , 5534,28 , 5520,14 , 5520,14 , 5534,28 , 5520,14 , 127,2 , 124,2 , {75,80,87}, 0,0 , 7305,23 , 4,4 , 8,6 , 2479,3 , 2486,14 , 0, 0, 1, 6, 7 }, // Korean/Korean/NorthKorea + { 68, 7, 35, 44, 46, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 10672,60 , 10732,106 , 158,27 , 10672,60 , 10732,106 , 158,27 , 5562,34 , 5596,89 , 85,14 , 5562,34 , 5596,89 , 85,14 , 129,5 , 126,5 , {66,73,70}, 212,3 , 7328,27 , 0,4 , 4,0 , 2500,8 , 2508,8 , 0, 0, 1, 6, 7 }, // Rundi/Latin/Burundi + { 69, 23, 117, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 717,18 , 61,4 , 349,24 , 10838,62 , 10900,75 , 158,27 , 10975,61 , 10900,75 , 158,27 , 5685,23 , 5708,57 , 5765,18 , 5783,24 , 5708,57 , 1765,14 , 134,8 , 131,8 , {76,65,75}, 246,1 , 7355,14 , 4,4 , 48,5 , 2516,3 , 2519,9 , 0, 0, 7, 6, 7 }, // Lao/Lao/Laos + { 71, 7, 118, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 347,8 , 347,8 , 187,8 , 735,26 , 37,5 , 8,10 , 11036,65 , 11101,101 , 134,24 , 11202,65 , 11267,101 , 134,24 , 5807,21 , 5828,72 , 5900,14 , 5807,21 , 5914,72 , 5900,14 , 142,14 , 139,11 , {76,86,76}, 247,2 , 7369,59 , 4,4 , 8,6 , 2528,8 , 2536,7 , 2, 1, 1, 6, 7 }, // Latvian/Latin/Latvia + { 72, 7, 49, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {67,68,70}, 217,2 , 7428,23 , 25,5 , 4,0 , 2543,7 , 2550,29 , 2, 1, 1, 6, 7 }, // Lingala/Latin/CongoKinshasa + { 72, 7, 6, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {65,79,65}, 249,2 , 7451,23 , 25,5 , 4,0 , 2543,7 , 2579,6 , 2, 1, 1, 6, 7 }, // Lingala/Latin/Angola + { 72, 7, 41, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {88,65,70}, 37,4 , 7474,23 , 25,5 , 4,0 , 2543,7 , 2585,26 , 0, 0, 1, 6, 7 }, // Lingala/Latin/CentralAfricanRepublic + { 72, 7, 50, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 355,9 , 355,9 , 364,8 , 99,16 , 37,5 , 8,10 , 11368,48 , 11416,203 , 11619,24 , 11368,48 , 11416,203 , 11619,24 , 5986,28 , 6014,100 , 6114,14 , 5986,28 , 6014,100 , 6114,14 , 156,8 , 150,6 , {88,65,70}, 37,4 , 7474,23 , 25,5 , 4,0 , 2543,7 , 2611,5 , 0, 0, 1, 6, 7 }, // Lingala/Latin/CongoBrazzaville + { 73, 7, 124, 44, 160, 59, 37, 48, 8211, 43, 101, 8222, 8220, 8222, 8220, 0,6 , 0,6 , 364,8 , 364,8 , 72,10 , 761,27 , 37,5 , 8,10 , 11643,70 , 11713,96 , 11809,24 , 11643,70 , 11713,96 , 11809,24 , 6128,21 , 6149,89 , 6238,14 , 6128,21 , 6149,89 , 6238,14 , 164,9 , 156,6 , {76,84,76}, 251,2 , 7497,62 , 25,5 , 4,0 , 2616,8 , 2624,7 , 2, 1, 1, 6, 7 }, // Lithuanian/Latin/Lithuania + { 74, 2, 127, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 0,6 , 0,6 , 788,7 , 123,18 , 37,5 , 8,10 , 11833,63 , 11896,85 , 11981,24 , 11833,63 , 11896,85 , 11981,24 , 6252,34 , 6286,54 , 1521,14 , 6252,34 , 6286,54 , 1521,14 , 173,10 , 162,8 , {77,75,68}, 253,3 , 7559,23 , 14,5 , 4,0 , 2631,10 , 2641,10 , 2, 1, 1, 6, 7 }, // Macedonian/Cyrillic/Macedonia + { 75, 7, 128, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 12005,48 , 12053,92 , 134,24 , 12005,48 , 12053,92 , 134,24 , 6340,34 , 6374,60 , 6434,14 , 6340,34 , 6374,60 , 6434,14 , 0,2 , 0,2 , {77,71,65}, 176,2 , 7582,13 , 4,4 , 4,0 , 2651,8 , 2659,12 , 0, 0, 1, 6, 7 }, // Malagasy/Latin/Madagascar + { 76, 7, 130, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 511,7 , 10,17 , 18,7 , 25,12 , 12145,49 , 12194,82 , 12276,24 , 12145,49 , 12194,82 , 12276,24 , 6448,28 , 6476,43 , 6519,14 , 6448,28 , 6476,43 , 6519,14 , 183,2 , 170,3 , {77,89,82}, 256,2 , 7595,23 , 4,4 , 8,6 , 2671,13 , 2684,8 , 2, 1, 1, 6, 7 }, // Malay/Latin/Malaysia + { 76, 7, 32, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 511,7 , 524,12 , 18,7 , 25,12 , 12145,49 , 12194,82 , 12276,24 , 12145,49 , 12194,82 , 12276,24 , 6448,28 , 6476,43 , 6519,14 , 6448,28 , 6476,43 , 6519,14 , 183,2 , 170,3 , {66,78,68}, 12,1 , 7618,19 , 14,5 , 4,0 , 2671,13 , 2692,6 , 2, 1, 1, 6, 7 }, // Malay/Latin/Brunei + { 76, 7, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 290,10 , 300,9 , 511,7 , 10,17 , 18,7 , 25,12 , 12145,49 , 12194,82 , 12276,24 , 12145,49 , 12194,82 , 12276,24 , 6448,28 , 6476,43 , 6519,14 , 6448,28 , 6476,43 , 6519,14 , 183,2 , 170,3 , {83,71,68}, 12,1 , 7637,22 , 4,4 , 8,6 , 2671,13 , 2698,9 , 2, 1, 7, 6, 7 }, // Malay/Latin/Singapore + { 77, 24, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 372,13 , 385,12 , 27,8 , 795,18 , 18,7 , 25,12 , 12300,62 , 12362,87 , 12449,31 , 12300,62 , 12362,87 , 12449,31 , 6533,41 , 6574,70 , 6644,22 , 6533,41 , 6574,70 , 6644,22 , 0,2 , 0,2 , {73,78,82}, 123,1 , 7659,40 , 0,4 , 4,0 , 2707,6 , 2713,6 , 2, 1, 7, 7, 7 }, // Malayalam/Malayalam/India + { 78, 7, 133, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 397,8 , 405,7 , 141,10 , 813,23 , 37,5 , 8,10 , 12480,48 , 12528,86 , 12614,24 , 12480,48 , 12528,86 , 12614,24 , 6666,28 , 6694,63 , 6757,14 , 6666,28 , 6694,63 , 6757,14 , 185,2 , 173,2 , {69,85,82}, 19,1 , 7699,11 , 4,4 , 4,0 , 2719,5 , 1055,5 , 2, 1, 7, 6, 7 }, // Maltese/Latin/Malta + { 80, 13, 100, 46, 44, 59, 37, 2406, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 412,9 , 412,9 , 634,6 , 99,16 , 373,7 , 380,12 , 12638,66 , 12704,86 , 12790,32 , 12638,66 , 12704,86 , 12790,32 , 6771,32 , 6803,53 , 4187,19 , 6771,32 , 6803,53 , 4187,19 , 0,2 , 0,2 , {73,78,82}, 123,1 , 7710,19 , 4,4 , 8,6 , 2724,5 , 2282,4 , 2, 1, 7, 7, 7 }, // Marathi/Devanagari/India + { 82, 2, 143, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 836,31 , 37,5 , 8,10 , 12822,48 , 12870,66 , 158,27 , 12822,48 , 12870,66 , 158,27 , 6856,21 , 6877,43 , 1765,14 , 6856,21 , 6877,43 , 1765,14 , 187,2 , 175,2 , {77,78,84}, 258,1 , 7729,25 , 14,5 , 4,0 , 2729,6 , 2735,6 , 0, 0, 1, 6, 7 }, // Mongolian/Cyrillic/Mongolia + { 84, 13, 150, 46, 44, 59, 37, 2406, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 12936,56 , 12992,85 , 13077,27 , 12936,56 , 12992,85 , 13077,27 , 6920,33 , 6953,54 , 7007,14 , 6920,33 , 6953,54 , 7007,14 , 189,14 , 177,14 , {78,80,82}, 259,4 , 7754,52 , 14,5 , 4,0 , 2741,6 , 2747,5 , 2, 1, 7, 6, 7 }, // Nepali/Devanagari/Nepal + { 84, 13, 100, 46, 44, 59, 37, 2406, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 12936,56 , 12992,85 , 13077,27 , 12936,56 , 13104,80 , 13077,27 , 6920,33 , 6953,54 , 7007,14 , 6920,33 , 7021,54 , 7007,14 , 109,9 , 108,7 , {73,78,82}, 123,1 , 7806,49 , 14,5 , 4,0 , 2741,6 , 2282,4 , 2, 1, 7, 7, 7 }, // Nepali/Devanagari/India + { 85, 7, 161, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 187,8 , 554,17 , 37,5 , 392,16 , 5815,48 , 13184,83 , 134,24 , 13267,59 , 13184,83 , 134,24 , 7075,28 , 2258,51 , 2309,14 , 2323,35 , 2258,51 , 2309,14 , 0,2 , 0,2 , {78,79,75}, 157,2 , 7855,44 , 14,5 , 4,0 , 2752,12 , 2764,5 , 2, 1, 1, 6, 7 }, // NorwegianBokmal/Latin/Norway + { 87, 26, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 634,6 , 10,17 , 18,7 , 25,12 , 13326,89 , 13326,89 , 13415,32 , 13326,89 , 13326,89 , 13415,32 , 7103,33 , 7136,54 , 7190,18 , 7103,33 , 7136,54 , 7190,18 , 89,2 , 88,2 , {73,78,82}, 123,1 , 7899,11 , 14,5 , 4,0 , 2769,5 , 2774,4 , 2, 1, 7, 7, 7 }, // Oriya/Oriya/India + { 88, 1, 1, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 179,8 , 867,20 , 61,4 , 408,11 , 13447,68 , 13447,68 , 158,27 , 13447,68 , 13447,68 , 158,27 , 7208,49 , 7208,49 , 85,14 , 7208,49 , 7208,49 , 85,14 , 203,4 , 191,4 , {65,70,78}, 263,1 , 7910,13 , 25,5 , 4,0 , 2778,4 , 2782,9 , 0, 0, 6, 4, 5 }, // Pashto/Arabic/Afghanistan + { 89, 1, 102, 1643, 1644, 1563, 1642, 1776, 8722, 43, 101, 171, 187, 8249, 8250, 421,7 , 421,7 , 43,8 , 51,7 , 179,8 , 99,16 , 61,4 , 408,11 , 13515,70 , 13515,70 , 13585,24 , 13609,74 , 13609,74 , 13585,24 , 7208,49 , 7208,49 , 7257,14 , 7208,49 , 7208,49 , 7257,14 , 207,9 , 195,8 , {73,82,82}, 264,1 , 7923,17 , 53,5 , 58,7 , 2791,5 , 2796,5 , 0, 0, 6, 4, 5 }, // Persian/Arabic/Iran + { 89, 1, 1, 1643, 1644, 1563, 1642, 1776, 8722, 43, 101, 171, 187, 8249, 8250, 421,7 , 421,7 , 43,8 , 51,7 , 179,8 , 99,16 , 61,4 , 408,11 , 13515,70 , 13515,70 , 13683,24 , 13707,64 , 13771,68 , 13585,24 , 7208,49 , 7208,49 , 7257,14 , 7208,49 , 7208,49 , 7257,14 , 207,9 , 195,8 , {65,70,78}, 263,1 , 7940,23 , 53,5 , 58,7 , 2801,3 , 2782,9 , 0, 0, 6, 4, 5 }, // Persian/Arabic/Afghanistan + { 90, 7, 172, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 118,7 , 118,7 , 887,10 , 10,17 , 37,5 , 8,10 , 13839,48 , 13887,97 , 13984,24 , 13839,48 , 14008,99 , 13984,24 , 7271,34 , 7305,59 , 7364,14 , 7271,34 , 7305,59 , 7364,14 , 0,2 , 0,2 , {80,76,78}, 265,2 , 7963,77 , 25,5 , 30,7 , 2804,6 , 2810,6 , 2, 1, 1, 6, 7 }, // Polish/Latin/Poland + { 91, 7, 30, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14107,48 , 14155,89 , 134,24 , 14107,48 , 14155,89 , 134,24 , 7378,28 , 7406,79 , 7485,14 , 7378,28 , 7406,79 , 7485,14 , 0,2 , 0,2 , {66,82,76}, 267,2 , 8040,54 , 4,4 , 8,6 , 2816,19 , 2835,6 , 2, 1, 7, 6, 7 }, // Portuguese/Latin/Brazil + { 91, 7, 6, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {65,79,65}, 249,2 , 8094,54 , 25,5 , 4,0 , 2841,9 , 2850,6 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/Angola + { 91, 7, 39, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {67,86,69}, 0,0 , 8148,69 , 25,5 , 4,0 , 2841,9 , 2856,10 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/CapeVerde + { 91, 7, 62, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 8217,81 , 25,5 , 4,0 , 2841,9 , 2866,11 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/EastTimor + { 91, 7, 92, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 8298,62 , 25,5 , 4,0 , 2841,9 , 2877,12 , 0, 0, 1, 6, 7 }, // Portuguese/Latin/GuineaBissau + { 91, 7, 126, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {77,79,80}, 144,4 , 8360,53 , 25,5 , 4,0 , 2841,9 , 2889,19 , 2, 1, 7, 6, 7 }, // Portuguese/Latin/Macau + { 91, 7, 146, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {77,90,78}, 269,3 , 8413,72 , 25,5 , 4,0 , 2841,9 , 2908,10 , 2, 1, 7, 6, 7 }, // Portuguese/Latin/Mozambique + { 91, 7, 173, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 8485,20 , 25,5 , 4,0 , 2918,17 , 2935,8 , 2, 1, 1, 6, 7 }, // Portuguese/Latin/Portugal + { 91, 7, 185, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 897,27 , 37,5 , 8,10 , 14244,48 , 14292,89 , 134,24 , 14244,48 , 14292,89 , 134,24 , 7378,28 , 7499,79 , 7485,14 , 7378,28 , 7499,79 , 7485,14 , 0,2 , 0,2 , {83,84,68}, 272,2 , 8505,92 , 25,5 , 4,0 , 2841,9 , 2943,19 , 0, 0, 1, 6, 7 }, // Portuguese/Latin/SaoTomeAndPrincipe + { 92, 4, 100, 46, 44, 59, 37, 48, 45, 43, 101, 39, 39, 34, 34, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 123,18 , 18,7 , 25,12 , 14381,68 , 14381,68 , 14449,27 , 14381,68 , 14381,68 , 14449,27 , 7578,38 , 7616,55 , 7671,23 , 7578,38 , 7616,55 , 7671,23 , 216,11 , 203,11 , {73,78,82}, 123,1 , 8597,12 , 14,5 , 4,0 , 2962,6 , 2968,4 , 2, 1, 7, 7, 7 }, // Punjabi/Gurmukhi/India + { 92, 1, 163, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 123,18 , 18,7 , 25,12 , 14476,67 , 14476,67 , 158,27 , 14476,67 , 14476,67 , 158,27 , 7694,37 , 7694,37 , 85,14 , 7694,37 , 7694,37 , 85,14 , 0,2 , 0,2 , {80,75,82}, 274,1 , 8609,13 , 14,5 , 4,0 , 2972,5 , 2977,6 , 0, 0, 7, 6, 7 }, // Punjabi/Arabic/Pakistan + { 94, 7, 206, 46, 8217, 59, 37, 48, 8722, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 503,8 , 924,28 , 37,5 , 8,10 , 14543,67 , 14610,92 , 14702,24 , 14543,67 , 14610,92 , 14702,24 , 7731,23 , 7754,56 , 7810,14 , 7731,23 , 7754,56 , 7810,14 , 89,2 , 214,2 , {67,72,70}, 230,3 , 8622,20 , 25,5 , 4,0 , 2983,9 , 2992,6 , 2, 0, 1, 6, 7 }, // Romansh/Latin/Switzerland + { 95, 7, 177, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 428,8 , 428,8 , 887,10 , 10,17 , 37,5 , 8,10 , 14726,60 , 14786,98 , 14884,24 , 14726,60 , 14786,98 , 14884,24 , 7824,21 , 7845,48 , 3070,14 , 7824,21 , 7845,48 , 3070,14 , 0,2 , 0,2 , {82,79,78}, 0,0 , 8642,57 , 25,5 , 4,0 , 2998,6 , 3004,7 , 2, 1, 1, 6, 7 }, // Romanian/Latin/Romania + { 95, 7, 141, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 428,8 , 428,8 , 887,10 , 10,17 , 37,5 , 8,10 , 14726,60 , 14786,98 , 14884,24 , 14726,60 , 14786,98 , 14884,24 , 7824,21 , 7845,48 , 3070,14 , 7824,21 , 7845,48 , 3070,14 , 0,2 , 0,2 , {77,68,76}, 0,0 , 8699,69 , 25,5 , 4,0 , 2998,6 , 3011,17 , 2, 1, 1, 6, 7 }, // Romanian/Latin/Moldova + { 96, 2, 178, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {82,85,66}, 275,4 , 8768,89 , 25,5 , 4,0 , 3028,7 , 3035,6 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Russia + { 96, 2, 20, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {66,89,82}, 140,2 , 8857,94 , 25,5 , 4,0 , 3028,7 , 470,8 , 0, 0, 7, 6, 7 }, // Russian/Cyrillic/Belarus + { 96, 2, 110, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {75,90,84}, 241,1 , 8951,83 , 25,5 , 4,0 , 3028,7 , 3041,9 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Kazakhstan + { 96, 2, 116, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {75,71,83}, 242,3 , 9034,81 , 25,5 , 4,0 , 3028,7 , 3050,8 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Kyrgyzstan + { 96, 2, 141, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 61,4 , 219,9 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {77,68,76}, 0,0 , 9115,79 , 25,5 , 4,0 , 3028,7 , 3058,7 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Moldova + { 96, 2, 222, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 102,7 , 102,7 , 187,8 , 952,22 , 37,5 , 8,10 , 14908,62 , 10414,80 , 14970,24 , 14994,63 , 15057,82 , 14970,24 , 7893,21 , 7914,62 , 7976,14 , 7990,21 , 8011,62 , 7990,21 , 227,10 , 216,13 , {85,65,72}, 279,1 , 9194,92 , 25,5 , 4,0 , 3028,7 , 3065,7 , 2, 1, 1, 6, 7 }, // Russian/Cyrillic/Ukraine + { 98, 7, 41, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 15139,48 , 15187,91 , 15278,24 , 15139,48 , 15187,91 , 15278,24 , 8073,28 , 8101,66 , 8167,14 , 8073,28 , 8101,66 , 8167,14 , 237,2 , 229,2 , {88,65,70}, 37,4 , 9286,25 , 4,4 , 48,5 , 3072,5 , 3077,22 , 0, 0, 1, 6, 7 }, // Sango/Latin/CentralAfricanRepublic + { 100, 2, 243, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15302,48 , 15350,81 , 11981,24 , 15302,48 , 15350,81 , 11981,24 , 8181,28 , 8209,52 , 8261,14 , 8181,28 , 8209,52 , 8261,14 , 239,9 , 231,7 , {82,83,68}, 280,4 , 9311,72 , 25,5 , 4,0 , 3099,6 , 3105,6 , 0, 0, 1, 6, 7 }, // Serbian/Cyrillic/Serbia + { 100, 7, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15431,48 , 15479,81 , 15560,24 , 15431,48 , 15479,81 , 15560,24 , 8275,28 , 8303,54 , 2118,14 , 8275,28 , 8303,54 , 2118,14 , 248,9 , 238,7 , {66,65,77}, 153,2 , 9383,196 , 25,5 , 4,0 , 3111,6 , 587,19 , 2, 1, 1, 6, 7 }, // Serbian/Latin/BosniaAndHerzegowina + { 100, 7, 242, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15431,48 , 15479,81 , 15560,24 , 15431,48 , 15479,81 , 15560,24 , 8275,28 , 8303,54 , 2118,14 , 8275,28 , 8303,54 , 2118,14 , 248,9 , 238,7 , {69,85,82}, 19,1 , 9579,27 , 25,5 , 4,0 , 3111,6 , 3117,9 , 2, 1, 1, 6, 7 }, // Serbian/Latin/Montenegro + { 100, 7, 243, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15431,48 , 15479,81 , 15560,24 , 15431,48 , 15479,81 , 15560,24 , 8275,28 , 8303,54 , 2118,14 , 8275,28 , 8303,54 , 2118,14 , 248,9 , 238,7 , {82,83,68}, 284,4 , 9606,72 , 25,5 , 4,0 , 3111,6 , 3126,6 , 0, 0, 1, 6, 7 }, // Serbian/Latin/Serbia + { 100, 2, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 115,8 , 981,20 , 37,5 , 419,40 , 15302,48 , 15350,81 , 11981,24 , 15302,48 , 15584,83 , 11981,24 , 8181,28 , 8209,52 , 8261,14 , 8357,28 , 8385,54 , 8261,14 , 239,9 , 231,7 , {66,65,77}, 288,2 , 9678,196 , 25,5 , 4,0 , 3132,6 , 3138,19 , 2, 1, 1, 6, 7 }, // Serbian/Cyrillic/BosniaAndHerzegowina + { 100, 2, 242, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15302,48 , 15350,81 , 11981,24 , 15302,48 , 15350,81 , 11981,24 , 8181,28 , 8209,52 , 8261,14 , 8181,28 , 8209,52 , 8261,14 , 239,9 , 231,7 , {69,85,82}, 19,1 , 9874,27 , 25,5 , 4,0 , 3099,6 , 3157,9 , 2, 1, 1, 6, 7 }, // Serbian/Cyrillic/Montenegro + { 100, 2, 257, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15302,48 , 15350,81 , 11981,24 , 15302,48 , 15350,81 , 11981,24 , 8181,28 , 8209,52 , 8261,14 , 8181,28 , 8209,52 , 8261,14 , 239,9 , 231,7 , {69,85,82}, 19,1 , 9874,27 , 25,5 , 4,0 , 3099,6 , 3166,6 , 2, 1, 1, 6, 7 }, // Serbian/Cyrillic/Kosovo + { 100, 7, 257, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 118,7 , 118,7 , 974,7 , 981,20 , 144,5 , 149,10 , 15431,48 , 15479,81 , 15560,24 , 15431,48 , 15479,81 , 15560,24 , 8275,28 , 8303,54 , 2118,14 , 8275,28 , 8303,54 , 2118,14 , 248,9 , 238,7 , {69,85,82}, 19,1 , 9579,27 , 25,5 , 4,0 , 3111,6 , 3172,6 , 2, 1, 1, 6, 7 }, // Serbian/Latin/Kosovo + { 101, 2, 81, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 436,9 , 436,9 , 187,8 , 1001,23 , 37,5 , 8,10 , 14908,62 , 15667,82 , 14970,24 , 15749,59 , 15808,86 , 14970,24 , 8439,28 , 8467,61 , 8528,14 , 8542,28 , 8570,61 , 8528,14 , 0,2 , 0,2 , {71,69,76}, 0,0 , 9901,17 , 14,5 , 4,0 , 3178,4 , 3182,11 , 2, 1, 1, 6, 7 }, // Ossetic/Cyrillic/Georgia + { 101, 2, 178, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 436,9 , 436,9 , 187,8 , 1001,23 , 37,5 , 8,10 , 14908,62 , 15667,82 , 14970,24 , 15749,59 , 15808,86 , 14970,24 , 8439,28 , 8467,61 , 8528,14 , 8542,28 , 8570,61 , 8528,14 , 0,2 , 0,2 , {82,85,66}, 275,4 , 9918,17 , 14,5 , 4,0 , 3178,4 , 3193,6 , 2, 1, 1, 6, 7 }, // Ossetic/Cyrillic/Russia + { 102, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 15894,48 , 15942,105 , 158,27 , 15894,48 , 15942,105 , 158,27 , 8631,27 , 8658,61 , 85,14 , 8631,27 , 8658,61 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3199,7 , 0,0 , 2, 1, 7, 6, 7 }, // Southern Sotho/Latin/SouthAfrica + { 102, 7, 120, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 15894,48 , 15942,105 , 158,27 , 15894,48 , 15942,105 , 158,27 , 8631,27 , 8658,61 , 85,14 , 8631,27 , 8658,61 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3199,7 , 0,0 , 2, 1, 1, 6, 7 }, // Southern Sotho/Latin/Lesotho + { 103, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16047,48 , 16095,117 , 158,27 , 16047,48 , 16095,117 , 158,27 , 8719,27 , 8746,64 , 85,14 , 8719,27 , 8746,64 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3206,8 , 0,0 , 2, 1, 7, 6, 7 }, // Tswana/Latin/SouthAfrica + { 103, 7, 28, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16047,48 , 16095,117 , 158,27 , 16047,48 , 16095,117 , 158,27 , 8719,27 , 8746,64 , 85,14 , 8719,27 , 8746,64 , 85,14 , 0,2 , 0,2 , {66,87,80}, 170,1 , 0,7 , 4,4 , 4,0 , 3206,8 , 0,0 , 2, 1, 7, 6, 7 }, // Tswana/Latin/Botswana + { 104, 7, 240, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 16212,47 , 16259,100 , 16359,24 , 16212,47 , 16259,100 , 16359,24 , 8810,32 , 8842,55 , 8897,14 , 8810,32 , 8842,55 , 8897,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 9935,22 , 4,4 , 8,6 , 3214,8 , 1497,8 , 2, 1, 7, 6, 7 }, // Shona/Latin/Zimbabwe + { 106, 32, 198, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 536,10 , 323,17 , 459,7 , 466,13 , 16383,59 , 16442,96 , 16538,32 , 16570,61 , 16442,96 , 16538,32 , 8911,30 , 8941,62 , 9003,19 , 8911,30 , 8941,62 , 9003,19 , 257,5 , 245,4 , {76,75,82}, 290,3 , 9957,19 , 14,5 , 4,0 , 3222,5 , 3227,11 , 2, 1, 1, 6, 7 }, // Sinhala/Sinhala/SriLanka + { 107, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16631,48 , 16679,114 , 158,27 , 16631,48 , 16679,114 , 158,27 , 9022,27 , 9049,68 , 85,14 , 9022,27 , 9049,68 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3238,7 , 0,0 , 2, 1, 7, 6, 7 }, // Swati/Latin/SouthAfrica + { 107, 7, 204, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 16631,48 , 16679,114 , 158,27 , 16631,48 , 16679,114 , 158,27 , 9022,27 , 9049,68 , 85,14 , 9022,27 , 9049,68 , 85,14 , 0,2 , 0,2 , {83,90,76}, 191,1 , 0,7 , 4,4 , 4,0 , 3238,7 , 0,0 , 2, 1, 1, 6, 7 }, // Swati/Latin/Swaziland + { 108, 7, 191, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 135,7 , 135,7 , 546,8 , 462,18 , 61,4 , 219,9 , 16793,48 , 16841,82 , 15560,24 , 16793,48 , 16923,89 , 15560,24 , 9117,21 , 9138,52 , 9190,14 , 9117,21 , 9138,52 , 9190,14 , 262,10 , 249,9 , {69,85,82}, 19,1 , 9976,28 , 25,5 , 4,0 , 3245,10 , 3255,9 , 2, 1, 1, 6, 7 }, // Slovak/Latin/Slovakia + { 109, 7, 192, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 445,8 , 445,8 , 1024,9 , 590,19 , 37,5 , 8,10 , 15431,48 , 17012,86 , 15560,24 , 17098,59 , 17012,86 , 15560,24 , 9204,28 , 9232,52 , 9284,14 , 9298,35 , 9232,52 , 9284,14 , 81,4 , 258,4 , {69,85,82}, 19,1 , 10004,28 , 4,4 , 8,6 , 3264,11 , 3275,9 , 2, 1, 1, 6, 7 }, // Slovenian/Latin/Slovenia + { 110, 7, 194, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {83,79,83}, 99,1 , 10032,22 , 4,4 , 4,0 , 3284,8 , 3292,10 , 0, 0, 1, 6, 7 }, // Somali/Latin/Somalia + { 110, 7, 59, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {68,74,70}, 5,3 , 10054,21 , 4,4 , 4,0 , 3284,8 , 3302,7 , 0, 0, 6, 6, 7 }, // Somali/Latin/Djibouti + { 110, 7, 69, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {69,84,66}, 0,2 , 10075,22 , 4,4 , 4,0 , 3284,8 , 3309,8 , 2, 1, 7, 6, 7 }, // Somali/Latin/Ethiopia + { 110, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 17157,48 , 17205,189 , 17394,24 , 17157,48 , 17205,189 , 17394,24 , 9333,28 , 9361,47 , 9408,14 , 9333,28 , 9361,47 , 9408,14 , 272,3 , 262,3 , {75,69,83}, 2,3 , 0,7 , 4,4 , 4,0 , 3284,8 , 3317,7 , 2, 1, 7, 6, 7 }, // Somali/Latin/Kenya + { 111, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 4,0 , 3324,17 , 2054,6 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Spain + { 111, 7, 10, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 479,14 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {65,82,83}, 12,1 , 10097,51 , 4,4 , 4,0 , 3341,7 , 3348,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Argentina + { 111, 7, 26, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {66,79,66}, 293,2 , 10148,35 , 4,4 , 4,0 , 3341,7 , 3357,7 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Bolivia + { 111, 7, 43, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 503,8 , 897,27 , 61,4 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,76,80}, 12,1 , 10183,45 , 4,4 , 48,5 , 3341,7 , 3364,5 , 0, 0, 1, 6, 7 }, // Spanish/Latin/Chile + { 111, 7, 47, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 511,7 , 897,27 , 61,4 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,79,80}, 12,1 , 10228,54 , 4,4 , 4,0 , 3341,7 , 3369,8 , 0, 0, 7, 6, 7 }, // Spanish/Latin/Colombia + { 111, 7, 52, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,82,67}, 295,1 , 10282,67 , 4,4 , 4,0 , 3341,7 , 3377,10 , 0, 0, 1, 6, 7 }, // Spanish/Latin/CostaRica + { 111, 7, 55, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {67,85,80}, 12,1 , 10349,42 , 4,4 , 4,0 , 3341,7 , 3387,4 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Cuba + { 111, 7, 61, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {68,79,80}, 12,1 , 10391,54 , 4,4 , 4,0 , 3341,7 , 3391,20 , 2, 1, 7, 6, 7 }, // Spanish/Latin/DominicanRepublic + { 111, 7, 63, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 61,4 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,83,68}, 12,1 , 10445,70 , 4,4 , 48,5 , 3341,7 , 3411,7 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Ecuador + { 111, 7, 65, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,83,68}, 204,3 , 10445,70 , 4,4 , 4,0 , 3341,7 , 3418,11 , 2, 1, 7, 6, 7 }, // Spanish/Latin/ElSalvador + { 111, 7, 66, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {88,65,70}, 37,4 , 10515,53 , 4,4 , 4,0 , 3341,7 , 3429,17 , 0, 0, 1, 6, 7 }, // Spanish/Latin/EquatorialGuinea + { 111, 7, 90, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 511,7 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {71,84,81}, 296,1 , 10568,70 , 4,4 , 4,0 , 3341,7 , 3446,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Guatemala + { 111, 7, 96, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 1033,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {72,78,76}, 297,1 , 10638,60 , 4,4 , 4,0 , 3341,7 , 3455,8 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Honduras + { 111, 7, 139, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {77,88,78}, 12,1 , 10698,48 , 4,4 , 4,0 , 3341,7 , 3463,6 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Mexico + { 111, 7, 155, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {78,73,79}, 298,2 , 10746,69 , 4,4 , 4,0 , 3341,7 , 3469,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Nicaragua + { 111, 7, 166, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 1060,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {80,65,66}, 300,3 , 10815,54 , 4,4 , 4,0 , 3341,7 , 3478,6 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Panama + { 111, 7, 168, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {80,89,71}, 303,1 , 10869,61 , 14,5 , 65,6 , 3341,7 , 3484,8 , 0, 0, 7, 6, 7 }, // Spanish/Latin/Paraguay + { 111, 7, 169, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 511,7 , 897,27 , 37,5 , 493,15 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {80,69,78}, 304,3 , 10930,62 , 4,4 , 4,0 , 3341,7 , 3492,4 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Peru + { 111, 7, 170, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {80,72,80}, 183,1 , 10992,48 , 25,5 , 4,0 , 3341,7 , 3496,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Philippines + { 111, 7, 174, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 1060,8 , 897,27 , 18,7 , 25,12 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,83,68}, 12,1 , 10445,70 , 4,4 , 4,0 , 3341,7 , 1184,11 , 2, 1, 7, 6, 7 }, // Spanish/Latin/PuertoRico + { 111, 7, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 518,6 , 897,27 , 18,7 , 25,12 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 10445,70 , 4,4 , 4,0 , 3341,7 , 3505,14 , 2, 1, 7, 6, 7 }, // Spanish/Latin/UnitedStates + { 111, 7, 227, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {85,89,85}, 12,1 , 11040,48 , 14,5 , 71,7 , 3341,7 , 3519,7 , 2, 1, 1, 6, 7 }, // Spanish/Latin/Uruguay + { 111, 7, 231, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {86,69,70}, 307,3 , 11088,64 , 4,4 , 48,5 , 3341,7 , 3526,9 , 2, 1, 7, 6, 7 }, // Spanish/Latin/Venezuela + { 111, 7, 238, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 4,0 , 3341,7 , 3535,14 , 2, 1, 1, 6, 7 }, // Spanish/Latin/CanaryIslands + { 111, 7, 246, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 3070,14 , 9422,28 , 9450,53 , 3070,14 , 75,4 , 74,4 , {0,0,0}, 0,0 , 11152,0 , 4,4 , 4,0 , 3549,23 , 3572,13 , 2, 1, 1, 6, 7 }, // Spanish/Latin/LatinAmericaAndTheCaribbean + { 111, 7, 250, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 171, 187, 0,6 , 0,6 , 453,7 , 453,7 , 27,8 , 897,27 , 37,5 , 8,10 , 17418,49 , 17467,89 , 17556,24 , 17580,48 , 17467,89 , 17556,24 , 9422,28 , 9450,53 , 9503,14 , 9422,28 , 9450,53 , 9503,14 , 75,4 , 74,4 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 4,0 , 3341,7 , 3585,15 , 2, 1, 1, 6, 7 }, // Spanish/Latin/CeutaAndMelilla + { 113, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 460,9 , 469,8 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 17676,84 , 134,24 , 17628,48 , 17676,84 , 134,24 , 9517,22 , 9539,60 , 9599,14 , 9517,22 , 9539,60 , 9599,14 , 275,7 , 265,7 , {84,90,83}, 192,3 , 11152,27 , 4,4 , 8,6 , 3600,9 , 1331,8 , 0, 0, 1, 6, 7 }, // Swahili/Latin/Tanzania + { 113, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 460,9 , 469,8 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 17676,84 , 134,24 , 17628,48 , 17676,84 , 134,24 , 9517,22 , 9539,60 , 9599,14 , 9517,22 , 9539,60 , 9599,14 , 275,7 , 265,7 , {75,69,83}, 2,3 , 11179,24 , 4,4 , 4,0 , 3600,9 , 1012,5 , 2, 1, 7, 6, 7 }, // Swahili/Latin/Kenya + { 113, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 460,9 , 469,8 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 17676,84 , 134,24 , 17628,48 , 17676,84 , 134,24 , 9517,22 , 9539,60 , 9599,14 , 9517,22 , 9539,60 , 9599,14 , 275,7 , 265,7 , {85,71,88}, 197,3 , 11203,25 , 4,4 , 8,6 , 3600,9 , 1387,6 , 0, 0, 1, 6, 7 }, // Swahili/Latin/Uganda + { 114, 7, 205, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 477,9 , 477,9 , 72,10 , 1068,30 , 37,5 , 392,16 , 17760,48 , 17808,86 , 134,24 , 4985,48 , 17894,86 , 134,24 , 9613,28 , 9641,50 , 2309,14 , 9691,29 , 9720,50 , 2309,14 , 282,2 , 272,2 , {83,69,75}, 157,2 , 11228,45 , 25,5 , 4,0 , 3609,7 , 3616,7 , 2, 1, 1, 6, 7 }, // Swedish/Latin/Sweden + { 114, 7, 73, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 477,9 , 477,9 , 72,10 , 1068,30 , 37,5 , 392,16 , 17760,48 , 17808,86 , 134,24 , 4985,48 , 17894,86 , 134,24 , 9613,28 , 9641,50 , 2309,14 , 9691,29 , 9720,50 , 2309,14 , 282,2 , 272,2 , {69,85,82}, 19,1 , 11273,19 , 25,5 , 4,0 , 3609,7 , 3623,7 , 2, 1, 1, 6, 7 }, // Swedish/Latin/Finland + { 114, 7, 248, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 477,9 , 477,9 , 72,10 , 1068,30 , 37,5 , 392,16 , 17760,48 , 17808,86 , 134,24 , 4985,48 , 17894,86 , 134,24 , 9613,28 , 9641,50 , 2309,14 , 9691,29 , 9720,50 , 2309,14 , 282,2 , 272,2 , {69,85,82}, 19,1 , 11273,19 , 25,5 , 4,0 , 3609,7 , 3630,5 , 2, 1, 1, 6, 7 }, // Swedish/Latin/AlandIslands + { 116, 2, 209, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 171, 8222, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 17980,48 , 18028,71 , 158,27 , 17980,48 , 18028,71 , 158,27 , 9770,28 , 9798,55 , 85,14 , 9770,28 , 9798,55 , 85,14 , 0,2 , 0,2 , {84,74,83}, 242,3 , 11292,13 , 14,5 , 4,0 , 3635,6 , 3641,10 , 2, 1, 1, 6, 7 }, // Tajik/Cyrillic/Tajikistan + { 117, 27, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {73,78,82}, 123,1 , 11305,13 , 14,5 , 4,0 , 3651,5 , 3656,7 , 2, 1, 7, 7, 7 }, // Tamil/Tamil/India + { 117, 27, 130, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {77,89,82}, 256,2 , 11318,22 , 14,5 , 4,0 , 3651,5 , 3663,7 , 2, 1, 1, 6, 7 }, // Tamil/Tamil/Malaysia + { 117, 27, 190, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {83,71,68}, 12,1 , 11340,24 , 14,5 , 4,0 , 3651,5 , 3670,11 , 2, 1, 7, 6, 7 }, // Tamil/Tamil/Singapore + { 117, 27, 198, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 486,13 , 486,13 , 634,6 , 224,18 , 18,7 , 25,12 , 18099,58 , 18157,86 , 18243,31 , 18099,58 , 18274,86 , 18243,31 , 9853,20 , 9873,49 , 9853,20 , 9853,20 , 9873,49 , 9853,20 , 0,2 , 0,2 , {76,75,82}, 310,3 , 11364,20 , 14,5 , 4,0 , 3651,5 , 3681,6 , 2, 1, 1, 6, 7 }, // Tamil/Tamil/SriLanka + { 119, 28, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 499,11 , 499,11 , 503,8 , 99,16 , 18,7 , 25,12 , 18360,66 , 18426,86 , 18512,31 , 18543,78 , 18426,86 , 18621,31 , 9922,32 , 9954,60 , 10014,18 , 9922,32 , 9954,60 , 10014,18 , 0,2 , 0,2 , {73,78,82}, 123,1 , 11384,26 , 4,4 , 8,6 , 3687,6 , 3693,9 , 2, 1, 7, 7, 7 }, // Telugu/Telugu/India + { 120, 30, 211, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 510,5 , 510,5 , 515,8 , 523,7 , 287,6 , 1098,19 , 37,5 , 508,28 , 18652,63 , 18715,98 , 18652,63 , 18652,63 , 18715,98 , 18813,62 , 10032,23 , 10055,68 , 10032,23 , 10032,23 , 10055,68 , 10032,23 , 284,10 , 274,10 , {84,72,66}, 313,1 , 11410,13 , 4,4 , 8,6 , 3702,3 , 3702,3 , 2, 1, 7, 6, 7 }, // Thai/Thai/Thailand + { 121, 31, 44, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 2663,63 , 18875,158 , 158,27 , 2663,63 , 18875,158 , 158,27 , 10123,49 , 10172,77 , 10249,21 , 10123,49 , 10172,77 , 10270,22 , 294,7 , 284,8 , {67,78,89}, 314,1 , 11423,13 , 14,5 , 4,0 , 3705,8 , 3713,6 , 2, 1, 7, 6, 7 }, // Tibetan/Tibetan/China + { 121, 31, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 2663,63 , 18875,158 , 158,27 , 2663,63 , 18875,158 , 158,27 , 10123,49 , 10172,77 , 10249,21 , 10123,49 , 10172,77 , 10270,22 , 294,7 , 284,8 , {73,78,82}, 123,1 , 11436,22 , 14,5 , 4,0 , 3705,8 , 3719,7 , 2, 1, 7, 7, 7 }, // Tibetan/Tibetan/India + { 122, 14, 69, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1117,23 , 18,7 , 25,12 , 19033,46 , 19079,62 , 1050,24 , 19033,46 , 19079,62 , 1050,24 , 10292,29 , 10292,29 , 10321,14 , 10292,29 , 10292,29 , 10321,14 , 301,7 , 292,7 , {69,84,66}, 0,2 , 11458,16 , 4,4 , 4,0 , 3726,4 , 109,5 , 2, 1, 7, 6, 7 }, // Tigrinya/Ethiopic/Ethiopia + { 122, 14, 67, 46, 44, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1140,23 , 18,7 , 25,12 , 19141,46 , 19187,54 , 1050,24 , 19141,46 , 19187,54 , 1050,24 , 10335,29 , 10335,29 , 10321,14 , 10335,29 , 10335,29 , 10321,14 , 301,7 , 292,7 , {69,82,78}, 8,3 , 0,7 , 4,4 , 4,0 , 3726,4 , 3730,4 , 2, 1, 1, 6, 7 }, // Tigrinya/Ethiopic/Eritrea + { 123, 7, 214, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 530,8 , 530,8 , 530,8 , 530,8 , 287,6 , 99,16 , 37,5 , 8,10 , 19241,51 , 19292,87 , 19379,24 , 19241,51 , 19292,87 , 19379,24 , 10364,29 , 10393,60 , 10453,14 , 10364,29 , 10393,60 , 10453,14 , 0,2 , 0,2 , {84,79,80}, 195,2 , 0,7 , 14,5 , 4,0 , 3734,13 , 1339,5 , 2, 1, 1, 6, 7 }, // Tongan/Latin/Tonga + { 124, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 19403,48 , 19451,122 , 158,27 , 19403,48 , 19451,122 , 158,27 , 10467,27 , 10494,72 , 85,14 , 10467,27 , 10494,72 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3747,8 , 0,0 , 2, 1, 7, 6, 7 }, // Tsonga/Latin/SouthAfrica + { 125, 7, 217, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 538,8 , 538,8 , 1163,9 , 1172,16 , 37,5 , 8,10 , 19573,48 , 19621,75 , 19696,24 , 19573,48 , 19621,75 , 19696,24 , 10566,28 , 10594,54 , 10648,14 , 10566,28 , 10594,54 , 10648,14 , 308,2 , 299,2 , {84,82,89}, 315,1 , 11474,18 , 25,5 , 30,7 , 3755,6 , 3761,7 , 2, 1, 1, 6, 7 }, // Turkish/Latin/Turkey + { 125, 7, 56, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 538,8 , 538,8 , 1163,9 , 1172,16 , 37,5 , 8,10 , 19573,48 , 19621,75 , 19696,24 , 19573,48 , 19621,75 , 19696,24 , 10566,28 , 10594,54 , 10648,14 , 10566,28 , 10594,54 , 10648,14 , 308,2 , 299,2 , {69,85,82}, 19,1 , 81,11 , 25,5 , 30,7 , 3755,6 , 3768,23 , 2, 1, 1, 6, 7 }, // Turkish/Latin/Cyprus + { 129, 2, 222, 44, 160, 59, 37, 48, 45, 43, 1077, 171, 187, 8222, 8220, 0,6 , 0,6 , 546,8 , 546,8 , 187,8 , 1188,22 , 37,5 , 8,10 , 19720,48 , 19768,95 , 19863,24 , 19887,67 , 19954,87 , 19863,24 , 10662,21 , 10683,56 , 10739,14 , 10662,21 , 10683,56 , 10739,14 , 310,2 , 301,2 , {85,65,72}, 279,1 , 11492,49 , 25,5 , 4,0 , 3791,10 , 3801,7 , 2, 1, 1, 6, 7 }, // Ukrainian/Cyrillic/Ukraine + { 130, 1, 163, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 554,10 , 564,9 , 287,6 , 161,18 , 18,7 , 25,12 , 20041,66 , 20041,66 , 134,24 , 20041,66 , 20041,66 , 134,24 , 10753,36 , 10753,36 , 85,14 , 10753,36 , 10753,36 , 85,14 , 312,9 , 303,9 , {80,75,82}, 180,2 , 11541,21 , 4,4 , 4,0 , 3808,4 , 3812,7 , 0, 0, 7, 6, 7 }, // Urdu/Arabic/Pakistan + { 130, 1, 100, 46, 44, 59, 37, 1776, 45, 43, 1602, 8221, 8220, 8217, 8216, 37,6 , 37,6 , 554,10 , 564,9 , 287,6 , 161,18 , 18,7 , 25,12 , 20041,66 , 20041,66 , 134,24 , 20041,66 , 20041,66 , 134,24 , 10753,36 , 10753,36 , 85,14 , 10753,36 , 10753,36 , 85,14 , 312,9 , 303,9 , {73,78,82}, 123,1 , 11562,18 , 14,5 , 4,0 , 3808,4 , 3819,5 , 2, 1, 7, 7, 7 }, // Urdu/Arabic/India + { 131, 2, 228, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 17980,48 , 18028,71 , 14970,24 , 17980,48 , 18028,71 , 14970,24 , 10789,28 , 10817,53 , 10870,14 , 10789,28 , 10817,53 , 10870,14 , 0,2 , 0,2 , {85,90,83}, 316,3 , 11580,21 , 14,5 , 4,0 , 3824,5 , 3829,10 , 0, 0, 1, 6, 7 }, // Uzbek/Cyrillic/Uzbekistan + { 131, 1, 1, 1643, 1644, 1563, 1642, 1776, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 179,8 , 1210,33 , 61,4 , 408,11 , 20107,48 , 13771,68 , 158,27 , 20107,48 , 13771,68 , 158,27 , 10884,21 , 7208,49 , 85,14 , 10884,21 , 7208,49 , 85,14 , 0,2 , 0,2 , {65,70,78}, 263,1 , 11601,13 , 25,5 , 4,0 , 3839,6 , 2782,9 , 0, 0, 6, 4, 5 }, // Uzbek/Arabic/Afghanistan + { 131, 7, 228, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 20155,52 , 20207,77 , 20284,24 , 20155,52 , 20207,77 , 20284,24 , 10905,34 , 10939,61 , 11000,14 , 10905,34 , 10939,61 , 11000,14 , 0,2 , 0,2 , {85,90,83}, 319,4 , 11614,23 , 14,5 , 4,0 , 3845,9 , 3854,11 , 0, 0, 1, 6, 7 }, // Uzbek/Latin/Uzbekistan + { 132, 7, 232, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 573,8 , 573,8 , 141,10 , 1243,31 , 37,5 , 8,10 , 20308,75 , 20383,130 , 158,27 , 20308,75 , 20383,130 , 158,27 , 11014,33 , 11047,55 , 11102,21 , 11014,33 , 11047,55 , 11102,21 , 321,2 , 312,2 , {86,78,68}, 323,1 , 11637,20 , 25,5 , 4,0 , 3865,10 , 3875,8 , 0, 0, 1, 6, 7 }, // Vietnamese/Latin/Vietnam + { 134, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 135,7 , 135,7 , 141,10 , 10,17 , 37,5 , 8,10 , 20513,52 , 20565,87 , 20652,26 , 20678,62 , 20565,87 , 20652,26 , 11123,29 , 11152,77 , 11229,15 , 11244,30 , 11152,77 , 11229,15 , 0,2 , 0,2 , {71,66,80}, 171,1 , 11657,154 , 4,4 , 4,0 , 3883,7 , 3890,16 , 2, 1, 1, 6, 7 }, // Welsh/Latin/UnitedKingdom + { 136, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 20740,48 , 20788,91 , 158,27 , 20740,48 , 20788,91 , 158,27 , 11274,28 , 11302,61 , 85,14 , 11274,28 , 11302,61 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 3906,8 , 0,0 , 2, 1, 7, 6, 7 }, // Xhosa/Latin/SouthAfrica + { 138, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 20879,73 , 20952,121 , 158,27 , 20879,73 , 20952,121 , 158,27 , 11363,44 , 11407,69 , 85,14 , 11363,44 , 11407,69 , 85,14 , 323,5 , 314,5 , {78,71,78}, 182,1 , 11811,34 , 4,4 , 8,6 , 3914,10 , 3924,18 , 2, 1, 1, 6, 7 }, // Yoruba/Latin/Nigeria + { 140, 7, 195, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 581,9 , 590,10 , 72,10 , 82,17 , 18,7 , 25,12 , 21073,48 , 21121,104 , 134,24 , 21073,48 , 21225,90 , 134,24 , 11476,28 , 11504,68 , 11572,14 , 11476,28 , 11504,68 , 11572,14 , 328,7 , 319,8 , {90,65,82}, 11,1 , 11845,27 , 4,4 , 8,6 , 3942,7 , 3949,17 , 2, 1, 7, 6, 7 }, // Zulu/Latin/SouthAfrica + { 141, 7, 161, 44, 160, 59, 37, 48, 8722, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 142,8 , 142,8 , 187,8 , 554,17 , 37,5 , 392,16 , 5815,48 , 13184,83 , 134,24 , 13267,59 , 13184,83 , 134,24 , 11586,28 , 11614,51 , 2309,14 , 11665,28 , 11614,51 , 2309,14 , 335,9 , 327,11 , {78,79,75}, 157,2 , 11872,42 , 25,5 , 4,0 , 3966,7 , 3973,5 , 2, 1, 1, 6, 7 }, // NorwegianNynorsk/Latin/Norway + { 142, 7, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 118,7 , 118,7 , 1274,9 , 981,20 , 37,5 , 8,10 , 15431,48 , 21315,83 , 15560,24 , 15431,48 , 21315,83 , 15560,24 , 2032,28 , 2060,58 , 85,14 , 2032,28 , 2060,58 , 85,14 , 248,9 , 238,7 , {66,65,77}, 153,2 , 11914,218 , 14,5 , 4,0 , 3978,8 , 587,19 , 2, 1, 1, 6, 7 }, // Bosnian/Latin/BosniaAndHerzegowina + { 142, 2, 27, 44, 46, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 102,7 , 102,7 , 974,7 , 981,20 , 37,5 , 8,10 , 15302,48 , 15584,83 , 11981,24 , 15302,48 , 15584,83 , 11981,24 , 8357,28 , 8385,54 , 8261,14 , 8357,28 , 8385,54 , 8261,14 , 239,9 , 231,7 , {66,65,77}, 288,2 , 12132,195 , 25,5 , 4,0 , 3986,8 , 3138,19 , 2, 1, 1, 6, 7 }, // Bosnian/Cyrillic/BosniaAndHerzegowina + { 144, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 82,17 , 37,5 , 8,10 , 21398,102 , 21500,140 , 158,27 , 21398,102 , 21500,140 , 158,27 , 11693,30 , 11723,57 , 85,14 , 11693,30 , 11723,57 , 85,14 , 75,4 , 74,4 , {71,66,80}, 171,1 , 0,7 , 4,4 , 4,0 , 3994,5 , 3999,14 , 2, 1, 1, 6, 7 }, // Manx/Latin/UnitedKingdom + { 145, 7, 224, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 99,16 , 37,5 , 8,10 , 21640,46 , 21686,124 , 158,27 , 21640,46 , 21686,124 , 158,27 , 11780,28 , 11808,60 , 85,14 , 11780,28 , 11808,60 , 85,14 , 75,4 , 74,4 , {71,66,80}, 171,1 , 0,7 , 4,4 , 4,0 , 4013,8 , 3999,14 , 2, 1, 1, 6, 7 }, // Cornish/Latin/UnitedKingdom + { 146, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 242,8 , 269,18 , 37,5 , 8,10 , 21810,48 , 21858,192 , 158,27 , 21810,48 , 21858,192 , 158,27 , 11868,28 , 11896,49 , 11945,14 , 11868,28 , 11896,49 , 11945,14 , 344,2 , 338,2 , {71,72,83}, 173,3 , 12327,17 , 4,4 , 4,0 , 4021,4 , 4025,5 , 2, 1, 1, 6, 7 }, // Akan/Latin/Ghana + { 147, 13, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 634,6 , 99,16 , 18,7 , 25,12 , 22050,87 , 22050,87 , 158,27 , 22050,87 , 22050,87 , 158,27 , 6771,32 , 11959,55 , 85,14 , 6771,32 , 11959,55 , 85,14 , 346,5 , 340,5 , {73,78,82}, 123,1 , 0,7 , 14,5 , 4,0 , 4030,6 , 2282,4 , 2, 1, 7, 7, 7 }, // Konkani/Devanagari/India + { 149, 7, 157, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 22137,48 , 22185,86 , 158,27 , 22137,48 , 22185,86 , 158,27 , 12014,29 , 12043,57 , 85,14 , 12014,29 , 12043,57 , 85,14 , 351,4 , 345,4 , {78,71,78}, 182,1 , 12344,12 , 4,4 , 8,6 , 4036,4 , 1113,7 , 2, 1, 1, 6, 7 }, // Igbo/Latin/Nigeria + { 150, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 22271,48 , 22319,189 , 22508,24 , 22271,48 , 22319,189 , 22508,24 , 12100,28 , 12128,74 , 12202,14 , 12100,28 , 12128,74 , 12202,14 , 355,9 , 349,7 , {75,69,83}, 2,3 , 12356,23 , 4,4 , 8,6 , 4040,7 , 1012,5 , 2, 1, 7, 6, 7 }, // Kamba/Latin/Kenya + { 152, 14, 67, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1283,22 , 18,7 , 25,12 , 22532,47 , 22579,77 , 22656,24 , 22532,47 , 22579,77 , 22656,24 , 12216,26 , 12242,43 , 12285,14 , 12216,26 , 12242,43 , 12285,14 , 0,2 , 0,2 , {69,82,78}, 8,3 , 0,7 , 4,4 , 4,0 , 4047,3 , 3730,4 , 2, 1, 1, 6, 7 }, // Blin/Ethiopic/Eritrea + { 157, 14, 67, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1305,21 , 18,7 , 25,12 , 19033,46 , 19079,62 , 1050,24 , 19033,46 , 19079,62 , 1050,24 , 12299,27 , 12326,41 , 12367,14 , 12299,27 , 12326,41 , 12367,14 , 0,2 , 0,2 , {69,82,78}, 8,3 , 0,7 , 4,4 , 4,0 , 4050,3 , 3730,4 , 2, 1, 1, 6, 7 }, // Tigre/Ethiopic/Eritrea + { 159, 7, 106, 44, 46, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 206,7 , 206,7 , 27,8 , 1326,27 , 37,5 , 8,10 , 22680,48 , 22728,77 , 22805,24 , 22680,48 , 22728,77 , 22805,24 , 12381,28 , 12409,50 , 3070,14 , 12381,28 , 12409,50 , 3070,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 14,5 , 4,0 , 4053,6 , 4059,6 , 2, 1, 1, 6, 7 }, // Friulian/Latin/Italy + { 160, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 22829,48 , 22877,111 , 158,27 , 22829,48 , 22877,111 , 158,27 , 12459,27 , 12486,70 , 85,14 , 12459,27 , 12486,70 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 4065,9 , 0,0 , 2, 1, 7, 6, 7 }, // Venda/Latin/SouthAfrica + { 161, 7, 83, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 600,11 , 611,10 , 518,6 , 1353,23 , 536,12 , 548,12 , 22988,48 , 23036,87 , 23123,24 , 22988,48 , 23036,87 , 23123,24 , 12556,28 , 12584,44 , 12628,14 , 12556,28 , 12584,44 , 12628,14 , 364,3 , 356,5 , {71,72,83}, 173,3 , 12379,37 , 4,4 , 8,6 , 4074,6 , 4080,12 , 2, 1, 1, 6, 7 }, // Ewe/Latin/Ghana + { 161, 7, 212, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 600,11 , 611,10 , 518,6 , 1353,23 , 536,12 , 548,12 , 22988,48 , 23036,87 , 23123,24 , 22988,48 , 23036,87 , 23123,24 , 12556,28 , 12584,44 , 12628,14 , 12556,28 , 12584,44 , 12628,14 , 364,3 , 356,5 , {88,79,70}, 209,3 , 12416,106 , 4,4 , 8,6 , 4074,6 , 4092,11 , 0, 0, 1, 6, 7 }, // Ewe/Latin/Togo + { 162, 14, 69, 46, 8217, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1376,22 , 18,7 , 25,12 , 19033,46 , 19079,62 , 1050,24 , 19033,46 , 19079,62 , 1050,24 , 12642,27 , 12642,27 , 12669,14 , 12642,27 , 12642,27 , 12669,14 , 0,2 , 0,2 , {69,84,66}, 0,2 , 11458,16 , 4,4 , 4,0 , 4103,5 , 109,5 , 2, 1, 7, 6, 7 }, // Walamo/Ethiopic/Ethiopia + { 163, 7, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 287,6 , 10,17 , 18,7 , 25,12 , 23147,59 , 23206,95 , 158,27 , 23147,59 , 23206,95 , 158,27 , 12683,21 , 12704,57 , 85,14 , 12683,21 , 12704,57 , 85,14 , 0,2 , 0,2 , {85,83,68}, 12,1 , 0,7 , 4,4 , 8,6 , 4108,14 , 4122,19 , 2, 1, 7, 6, 7 }, // Hawaiian/Latin/UnitedStates + { 166, 7, 170, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 621,8 , 621,8 , 518,6 , 1398,18 , 37,5 , 8,10 , 23301,48 , 23349,88 , 23437,24 , 23301,48 , 23349,88 , 23437,24 , 12761,28 , 12789,55 , 12844,14 , 12858,28 , 12789,55 , 12844,14 , 0,2 , 0,2 , {80,72,80}, 183,1 , 12522,22 , 4,4 , 8,6 , 4141,8 , 4149,9 , 2, 1, 7, 6, 7 }, // Filipino/Latin/Philippines + { 167, 7, 206, 46, 8217, 59, 37, 48, 8722, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 221,9 , 221,9 , 187,8 , 462,18 , 37,5 , 8,10 , 6990,48 , 23461,86 , 134,24 , 6990,48 , 23461,86 , 134,24 , 12886,28 , 12914,63 , 3471,14 , 12886,28 , 12914,63 , 3471,14 , 94,5 , 361,4 , {67,72,70}, 230,3 , 12544,55 , 25,5 , 4,0 , 4158,16 , 4174,7 , 2, 0, 1, 6, 7 }, // Swiss German/Latin/Switzerland + { 168, 34, 44, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 158,27 , 23547,38 , 158,27 , 158,27 , 23547,38 , 158,27 , 12977,21 , 12998,28 , 13026,14 , 12977,21 , 12998,28 , 13026,14 , 367,2 , 365,2 , {67,78,89}, 314,1 , 0,7 , 14,5 , 4,0 , 4181,3 , 4184,2 , 2, 1, 7, 6, 7 }, // Sichuan Yi/Yi/China + { 171, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 23585,48 , 23633,100 , 158,27 , 23585,48 , 23633,100 , 158,27 , 13040,27 , 13067,66 , 85,14 , 13040,27 , 13067,66 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 4186,10 , 0,0 , 2, 1, 7, 6, 7 }, // South Ndebele/Latin/SouthAfrica + { 172, 7, 195, 44, 160, 59, 37, 48, 45, 43, 101, 8216, 8217, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 323,17 , 37,5 , 8,10 , 23733,48 , 23781,94 , 158,27 , 23733,48 , 23781,94 , 158,27 , 13133,27 , 13160,63 , 85,14 , 13133,27 , 13160,63 , 85,14 , 0,2 , 0,2 , {90,65,82}, 11,1 , 0,7 , 4,4 , 4,0 , 4196,16 , 0,0 , 2, 1, 7, 6, 7 }, // Northern Sotho/Latin/SouthAfrica + { 173, 7, 161, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 169,8 , 169,8 , 72,10 , 323,17 , 37,5 , 8,10 , 23875,59 , 23934,145 , 24079,24 , 23875,59 , 23934,145 , 24079,24 , 13223,33 , 13256,75 , 13331,14 , 13223,33 , 13256,75 , 13331,14 , 0,2 , 0,2 , {78,79,75}, 157,2 , 12599,63 , 25,5 , 4,0 , 4212,15 , 4227,5 , 2, 1, 1, 6, 7 }, // Northern Sami/Latin/Norway + { 173, 7, 73, 44, 160, 59, 37, 48, 8722, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 169,8 , 169,8 , 72,10 , 323,17 , 37,5 , 8,10 , 24103,85 , 23934,145 , 24079,24 , 24103,85 , 23934,145 , 24079,24 , 13223,33 , 13345,65 , 13410,14 , 13223,33 , 13345,65 , 13410,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 12662,23 , 25,5 , 4,0 , 4212,15 , 4232,6 , 2, 1, 1, 6, 7 }, // Northern Sami/Latin/Finland + { 175, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 24188,48 , 24236,88 , 24324,24 , 24188,48 , 24236,88 , 24324,24 , 13424,28 , 13452,62 , 13514,14 , 13424,28 , 13452,62 , 13514,14 , 369,5 , 367,10 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4238,8 , 1012,5 , 2, 1, 7, 6, 7 }, // Gusii/Latin/Kenya + { 176, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 24348,48 , 24396,221 , 24617,24 , 24348,48 , 24396,221 , 24617,24 , 13528,28 , 13556,105 , 13661,14 , 13528,28 , 13556,105 , 13661,14 , 374,10 , 377,10 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4246,7 , 1012,5 , 2, 1, 7, 6, 7 }, // Taita/Latin/Kenya + { 177, 7, 187, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 8218, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 24641,48 , 24689,77 , 24766,24 , 24641,48 , 24689,77 , 24766,24 , 13675,28 , 13703,59 , 13762,14 , 13675,28 , 13703,59 , 13762,14 , 384,6 , 387,7 , {88,79,70}, 209,3 , 12709,26 , 25,5 , 4,0 , 4253,6 , 4259,8 , 0, 0, 1, 6, 7 }, // Fulah/Latin/Senegal + { 178, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 24790,48 , 24838,185 , 25023,24 , 24790,48 , 24838,185 , 25023,24 , 13776,28 , 13804,63 , 13867,14 , 13776,28 , 13804,63 , 13867,14 , 390,6 , 394,8 , {75,69,83}, 2,3 , 12735,23 , 4,4 , 8,6 , 4267,6 , 1012,5 , 2, 1, 7, 6, 7 }, // Kikuyu/Latin/Kenya + { 179, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 25047,48 , 25095,173 , 25268,24 , 25047,48 , 25095,173 , 25268,24 , 13881,28 , 13909,105 , 14014,14 , 13881,28 , 13909,105 , 14014,14 , 396,7 , 402,5 , {75,69,83}, 2,3 , 12758,25 , 4,4 , 8,6 , 4273,8 , 1012,5 , 2, 1, 7, 6, 7 }, // Samburu/Latin/Kenya + { 180, 7, 146, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 897,27 , 37,5 , 8,10 , 25292,48 , 25340,88 , 134,24 , 25292,48 , 25340,88 , 134,24 , 14028,28 , 14056,55 , 14111,14 , 14028,28 , 14056,55 , 14111,14 , 0,2 , 0,2 , {77,90,78}, 269,3 , 12783,28 , 0,4 , 4,0 , 4281,4 , 2908,10 , 2, 1, 7, 6, 7 }, // Sena/Latin/Mozambique + { 181, 7, 240, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 25428,52 , 25480,112 , 25592,24 , 25428,52 , 25480,112 , 25592,24 , 14125,28 , 14153,50 , 14203,14 , 14125,28 , 14153,50 , 14203,14 , 0,2 , 0,2 , {85,83,68}, 204,3 , 12811,24 , 4,4 , 8,6 , 4186,10 , 1497,8 , 2, 1, 7, 6, 7 }, // North Ndebele/Latin/Zimbabwe + { 182, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 25616,39 , 25655,194 , 25849,24 , 25616,39 , 25655,194 , 25849,24 , 14217,29 , 14246,65 , 14311,14 , 14217,29 , 14246,65 , 14311,14 , 403,8 , 407,7 , {84,90,83}, 192,3 , 12835,25 , 4,4 , 4,0 , 4285,9 , 1331,8 , 0, 0, 1, 6, 7 }, // Rombo/Latin/Tanzania + { 183, 9, 145, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 25873,48 , 25921,81 , 26002,24 , 25873,48 , 25921,81 , 26002,24 , 14325,30 , 14355,47 , 85,14 , 14325,30 , 14355,47 , 85,14 , 411,6 , 414,8 , {77,65,68}, 0,0 , 12860,21 , 0,4 , 4,0 , 4294,8 , 4302,6 , 2, 1, 6, 5, 6 }, // Tachelhit/Tifinagh/Morocco + { 183, 7, 145, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 26026,48 , 26074,81 , 26155,24 , 26026,48 , 26074,81 , 26155,24 , 14402,30 , 14432,48 , 85,14 , 14402,30 , 14432,48 , 85,14 , 417,6 , 422,8 , {77,65,68}, 0,0 , 12881,21 , 0,4 , 4,0 , 4308,9 , 4317,6 , 2, 1, 6, 5, 6 }, // Tachelhit/Latin/Morocco + { 184, 7, 3, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 26179,48 , 26227,84 , 26311,24 , 26179,48 , 26227,84 , 26311,24 , 14480,30 , 14510,51 , 14561,14 , 14480,30 , 14510,51 , 14561,14 , 423,7 , 430,9 , {68,90,68}, 207,2 , 12902,21 , 0,4 , 4,0 , 4323,9 , 4332,8 , 2, 1, 6, 4, 5 }, // Kabyle/Latin/Algeria + { 185, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 26335,48 , 26383,152 , 134,24 , 26335,48 , 26383,152 , 134,24 , 14575,28 , 14603,74 , 14677,14 , 14575,28 , 14603,74 , 14677,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 12923,26 , 4,4 , 78,5 , 4340,10 , 1387,6 , 0, 0, 1, 6, 7 }, // Nyankole/Latin/Uganda + { 186, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 26535,48 , 26583,254 , 26837,24 , 26535,48 , 26583,254 , 26837,24 , 14691,28 , 14719,82 , 14801,14 , 14691,28 , 14719,82 , 14801,14 , 430,7 , 439,7 , {84,90,83}, 192,3 , 12949,29 , 0,4 , 4,0 , 4350,6 , 4356,10 , 0, 0, 1, 6, 7 }, // Bena/Latin/Tanzania + { 187, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 26861,87 , 134,24 , 17628,48 , 26861,87 , 134,24 , 14815,28 , 14843,62 , 14905,14 , 14815,28 , 14843,62 , 14905,14 , 437,5 , 446,9 , {84,90,83}, 192,3 , 12978,27 , 4,4 , 4,0 , 4366,8 , 1331,8 , 0, 0, 1, 6, 7 }, // Vunjo/Latin/Tanzania + { 188, 7, 132, 46, 44, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 26948,47 , 26995,92 , 27087,24 , 26948,47 , 26995,92 , 27087,24 , 14919,28 , 14947,44 , 14991,14 , 14919,28 , 14947,44 , 14991,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 13005,24 , 4,4 , 8,6 , 4374,9 , 1842,4 , 0, 0, 1, 6, 7 }, // Bambara/Latin/Mali + { 189, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 27111,48 , 27159,207 , 27366,24 , 27111,48 , 27159,207 , 27366,24 , 15005,28 , 15033,64 , 15097,14 , 15005,28 , 15033,64 , 15097,14 , 442,2 , 455,2 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4383,6 , 1012,5 , 2, 1, 7, 6, 7 }, // Embu/Latin/Kenya + { 190, 12, 225, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 518,6 , 35,18 , 18,7 , 25,12 , 27390,36 , 27426,58 , 27484,24 , 27390,36 , 27426,58 , 27484,24 , 15111,28 , 15139,49 , 15188,14 , 15111,28 , 15139,49 , 15188,14 , 444,3 , 457,6 , {85,83,68}, 12,1 , 13029,19 , 4,4 , 8,6 , 4389,3 , 4392,4 , 2, 1, 7, 6, 7 }, // Cherokee/Cherokee/UnitedStates + { 191, 7, 137, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 27508,47 , 27555,68 , 27623,24 , 27508,47 , 27555,68 , 27623,24 , 15202,27 , 15229,48 , 15277,14 , 15202,27 , 15229,48 , 15277,14 , 0,2 , 0,2 , {77,85,82}, 180,2 , 13048,21 , 14,5 , 4,0 , 4396,14 , 4410,5 , 0, 0, 1, 6, 7 }, // Morisyen/Latin/Mauritius + { 192, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 27647,264 , 134,24 , 17628,48 , 27647,264 , 134,24 , 15291,28 , 15319,133 , 14311,14 , 15291,28 , 15319,133 , 14311,14 , 447,4 , 463,5 , {84,90,83}, 192,3 , 12978,27 , 4,4 , 8,6 , 4415,10 , 1331,8 , 0, 0, 1, 6, 7 }, // Makonde/Latin/Tanzania + { 193, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8221, 8221, 8217, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 27911,83 , 27994,111 , 28105,24 , 27911,83 , 27994,111 , 28105,24 , 15452,36 , 15488,63 , 15551,14 , 15452,36 , 15488,63 , 15551,14 , 451,3 , 468,3 , {84,90,83}, 192,3 , 13069,29 , 14,5 , 4,0 , 4425,8 , 4433,9 , 0, 0, 1, 6, 7 }, // Langi/Latin/Tanzania + { 194, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28129,48 , 28177,97 , 134,24 , 28129,48 , 28177,97 , 134,24 , 15565,28 , 15593,66 , 15659,14 , 15565,28 , 15593,66 , 15659,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 13098,26 , 0,4 , 4,0 , 4442,7 , 4449,7 , 0, 0, 1, 6, 7 }, // Ganda/Latin/Uganda + { 195, 7, 239, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28274,48 , 28322,83 , 28405,24 , 28274,48 , 28322,83 , 28405,24 , 15673,80 , 15673,80 , 85,14 , 15673,80 , 15673,80 , 85,14 , 454,8 , 471,7 , {90,77,87}, 202,2 , 0,7 , 4,4 , 8,6 , 4456,9 , 1491,6 , 2, 1, 1, 6, 7 }, // Bemba/Latin/Zambia + { 196, 7, 39, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 453,7 , 453,7 , 364,8 , 1416,27 , 37,5 , 8,10 , 28429,48 , 28477,86 , 134,24 , 28429,48 , 28477,86 , 134,24 , 15753,28 , 15781,73 , 15854,14 , 15753,28 , 15781,73 , 15854,14 , 89,2 , 88,2 , {67,86,69}, 0,0 , 13124,25 , 0,4 , 4,0 , 4465,12 , 4477,10 , 2, 1, 1, 6, 7 }, // Kabuverdianu/Latin/CapeVerde + { 197, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28563,48 , 28611,86 , 28697,24 , 28563,48 , 28611,86 , 28697,24 , 15868,28 , 15896,51 , 15947,14 , 15868,28 , 15896,51 , 15947,14 , 462,2 , 478,2 , {75,69,83}, 2,3 , 12685,24 , 4,4 , 8,6 , 4487,6 , 1012,5 , 2, 1, 7, 6, 7 }, // Meru/Latin/Kenya + { 198, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28721,48 , 28769,111 , 28880,24 , 28721,48 , 28769,111 , 28880,24 , 15961,28 , 15989,93 , 16082,14 , 15961,28 , 15989,93 , 16082,14 , 464,4 , 480,4 , {75,69,83}, 2,3 , 13149,26 , 4,4 , 8,6 , 4493,8 , 4501,12 , 2, 1, 7, 6, 7 }, // Kalenjin/Latin/Kenya + { 199, 7, 148, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 0,48 , 28904,136 , 134,24 , 0,48 , 28904,136 , 134,24 , 16096,23 , 16119,92 , 16211,14 , 16096,23 , 16119,92 , 16211,14 , 468,7 , 484,5 , {78,65,68}, 12,1 , 13175,22 , 4,4 , 4,0 , 4513,13 , 4526,8 , 2, 1, 1, 6, 7 }, // Nama/Latin/Namibia + { 200, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 26861,87 , 134,24 , 17628,48 , 26861,87 , 134,24 , 14815,28 , 14843,62 , 14905,14 , 14815,28 , 14843,62 , 14905,14 , 437,5 , 446,9 , {84,90,83}, 192,3 , 12978,27 , 4,4 , 4,0 , 4534,9 , 1331,8 , 0, 0, 1, 6, 7 }, // Machame/Latin/Tanzania + { 201, 7, 82, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 347,8 , 347,8 , 1443,10 , 1453,23 , 37,5 , 8,10 , 29040,59 , 29099,87 , 134,24 , 29186,48 , 29099,87 , 134,24 , 16225,28 , 16253,72 , 3471,14 , 16225,28 , 16253,72 , 3471,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 81,11 , 25,5 , 4,0 , 4543,6 , 4549,11 , 2, 1, 1, 6, 7 }, // Colognian/Latin/Germany + { 202, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29234,51 , 29285,132 , 158,27 , 29234,51 , 29285,132 , 158,27 , 14815,28 , 16325,58 , 14311,14 , 14815,28 , 16325,58 , 14311,14 , 475,9 , 489,6 , {75,69,83}, 2,3 , 13197,25 , 4,4 , 8,6 , 4560,3 , 1012,5 , 2, 1, 7, 6, 7 }, // Masai/Latin/Kenya + { 202, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29234,51 , 29285,132 , 158,27 , 29234,51 , 29285,132 , 158,27 , 14815,28 , 16325,58 , 14311,14 , 14815,28 , 16325,58 , 14311,14 , 475,9 , 489,6 , {84,90,83}, 192,3 , 13222,28 , 4,4 , 8,6 , 4560,3 , 4563,8 , 0, 0, 1, 6, 7 }, // Masai/Latin/Tanzania + { 203, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 28129,48 , 28177,97 , 134,24 , 28129,48 , 28177,97 , 134,24 , 16383,35 , 16418,65 , 16483,14 , 16383,35 , 16418,65 , 16483,14 , 484,6 , 495,6 , {85,71,88}, 197,3 , 13098,26 , 25,5 , 4,0 , 4571,7 , 4449,7 , 0, 0, 1, 6, 7 }, // Soga/Latin/Uganda + { 204, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29417,48 , 17676,84 , 134,24 , 29417,48 , 17676,84 , 134,24 , 16497,21 , 16518,75 , 85,14 , 16497,21 , 16518,75 , 85,14 , 75,4 , 74,4 , {75,69,83}, 2,3 , 13250,23 , 4,4 , 83,6 , 4578,7 , 1012,5 , 2, 1, 7, 6, 7 }, // Luyia/Latin/Kenya + { 205, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29465,48 , 17676,84 , 134,24 , 29465,48 , 17676,84 , 134,24 , 16593,28 , 9539,60 , 14905,14 , 16593,28 , 9539,60 , 14905,14 , 490,9 , 501,8 , {84,90,83}, 192,3 , 13273,28 , 25,5 , 4,0 , 4585,6 , 4591,8 , 0, 0, 1, 6, 7 }, // Asu/Latin/Tanzania + { 206, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29513,48 , 29561,94 , 29655,24 , 29513,48 , 29561,94 , 29655,24 , 16621,28 , 16649,69 , 16718,14 , 16621,28 , 16649,69 , 16718,14 , 499,9 , 509,6 , {85,71,88}, 197,3 , 13301,28 , 4,4 , 8,6 , 4599,6 , 1387,6 , 0, 0, 1, 6, 7 }, // Teso/Latin/Uganda + { 206, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29513,48 , 29561,94 , 29655,24 , 29513,48 , 29561,94 , 29655,24 , 16621,28 , 16649,69 , 16718,14 , 16621,28 , 16649,69 , 16718,14 , 499,9 , 509,6 , {75,69,83}, 2,3 , 13329,27 , 4,4 , 8,6 , 4599,6 , 4605,5 , 2, 1, 7, 6, 7 }, // Teso/Latin/Kenya { 207, 7, 67, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 53,19 , 18,7 , 25,12 , 344,48 , 392,118 , 510,24 , 344,48 , 392,118 , 510,24 , 16732,28 , 16760,56 , 16816,14 , 16732,28 , 16760,56 , 16816,14 , 0,2 , 0,2 , {69,82,78}, 8,3 , 0,7 , 4,4 , 4,0 , 0,0 , 43,7 , 2, 1, 1, 6, 7 }, // Saho/Latin/Eritrea - { 208, 7, 132, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 16830,28 , 16858,53 , 16911,14 , 16830,28 , 16858,53 , 16911,14 , 508,6 , 515,6 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4592,11 , 4603,5 , 0, 0, 1, 6, 7 }, // Koyra Chiini/Latin/Mali - { 209, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 26861,87 , 134,24 , 17628,48 , 26861,87 , 134,24 , 14815,28 , 14843,62 , 14905,14 , 14815,28 , 14843,62 , 14905,14 , 437,5 , 446,9 , {84,90,83}, 192,3 , 12978,27 , 0,4 , 4,0 , 4608,6 , 1325,8 , 0, 0, 1, 6, 7 }, // Rwa/Latin/Tanzania - { 210, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29837,48 , 29885,186 , 30071,24 , 29837,48 , 29885,186 , 30071,24 , 16925,28 , 16953,69 , 17022,14 , 16925,28 , 16953,69 , 17022,14 , 514,2 , 521,2 , {75,69,83}, 2,3 , 13379,23 , 0,4 , 4,0 , 4614,6 , 1006,5 , 2, 1, 7, 6, 7 }, // Luo/Latin/Kenya - { 211, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 26335,48 , 26383,152 , 134,24 , 26335,48 , 26383,152 , 134,24 , 14575,28 , 14603,74 , 14677,14 , 14575,28 , 14603,74 , 14677,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 12923,26 , 4,4 , 78,5 , 4620,6 , 1381,6 , 0, 0, 1, 6, 7 }, // Chiga/Latin/Uganda - { 212, 7, 145, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 30095,48 , 30143,86 , 30229,24 , 30095,48 , 30143,86 , 30229,24 , 17036,28 , 17064,48 , 17112,14 , 17036,28 , 17064,48 , 17112,14 , 516,9 , 523,10 , {77,65,68}, 0,0 , 13402,22 , 25,5 , 4,0 , 4626,8 , 4634,6 , 2, 1, 6, 5, 6 }, // Central Morocco Tamazight/Latin/Morocco - { 213, 7, 132, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 17126,28 , 17154,54 , 16911,14 , 17126,28 , 17154,54 , 16911,14 , 508,6 , 515,6 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4640,15 , 4603,5 , 0, 0, 1, 6, 7 }, // Koyraboro Senni/Latin/Mali - { 214, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 30253,84 , 134,24 , 17628,48 , 30253,84 , 134,24 , 17208,28 , 17236,63 , 9599,14 , 17208,28 , 17236,63 , 9599,14 , 525,5 , 533,8 , {84,90,83}, 192,3 , 11152,27 , 0,4 , 4,0 , 4655,9 , 1325,8 , 0, 0, 1, 6, 7 }, // Shambala/Latin/Tanzania - { 215, 13, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 518,6 , 35,18 , 18,7 , 25,12 , 30337,88 , 30337,88 , 30425,31 , 30337,88 , 30337,88 , 30425,31 , 17299,33 , 17332,54 , 17386,19 , 17299,33 , 17332,54 , 17386,19 , 530,3 , 541,6 , {73,78,82}, 122,1 , 13424,10 , 14,5 , 4,0 , 4664,4 , 2276,4 , 2, 1, 7, 7, 7 }, // Bodo/Devanagari/India - { 230, 7, 49, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 30456,49 , 30505,99 , 30604,24 , 30456,49 , 30505,99 , 30604,24 , 17405,28 , 17433,50 , 17483,14 , 17405,28 , 17433,50 , 17483,14 , 533,5 , 547,6 , {67,68,70}, 217,2 , 13434,24 , 0,4 , 4,0 , 4668,8 , 4676,16 , 2, 1, 1, 6, 7 }, // LubaKatanga/Latin/CongoKinshasa - { 237, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 8218, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 30628,48 , 30676,195 , 30871,24 , 30628,48 , 30676,195 , 30871,24 , 17497,28 , 17525,72 , 17597,14 , 17497,28 , 17525,72 , 17597,14 , 538,3 , 553,3 , {88,65,70}, 36,4 , 13458,21 , 0,4 , 4,0 , 4692,5 , 4697,7 , 0, 0, 1, 6, 7 }, // Aghem/Latin/Cameroon - { 238, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 30895,48 , 30943,90 , 31033,24 , 30895,48 , 30943,90 , 31033,24 , 17611,28 , 17639,70 , 17709,14 , 17611,28 , 17639,70 , 17709,14 , 541,10 , 556,9 , {88,65,70}, 36,4 , 13479,22 , 25,5 , 4,0 , 4704,5 , 4709,8 , 0, 0, 1, 6, 7 }, // Basaa/Latin/Cameroon - { 239, 7, 156, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 17126,28 , 17723,53 , 17776,14 , 17126,28 , 17723,53 , 17776,14 , 551,8 , 565,10 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4717,10 , 4727,5 , 0, 0, 1, 6, 7 }, // Zarma/Latin/Niger - { 240, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31057,49 , 31106,99 , 31205,24 , 31057,49 , 31106,99 , 31205,24 , 17790,28 , 17818,45 , 17863,14 , 17790,28 , 17818,45 , 17863,14 , 559,5 , 575,6 , {88,65,70}, 36,4 , 0,7 , 25,5 , 4,0 , 4732,5 , 1615,8 , 0, 0, 1, 6, 7 }, // Duala/Latin/Cameroon - { 241, 7, 187, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31229,36 , 31265,82 , 31347,24 , 31229,36 , 31265,82 , 31347,24 , 17877,28 , 17905,50 , 17955,14 , 17877,28 , 17905,50 , 17955,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 13501,23 , 25,5 , 4,0 , 4737,5 , 4742,7 , 0, 0, 1, 6, 7 }, // JolaFonyi/Latin/Senegal - { 242, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31371,50 , 31421,141 , 31562,24 , 31371,50 , 31421,141 , 31562,24 , 17969,30 , 17999,85 , 18084,14 , 17969,30 , 17999,85 , 18084,14 , 564,7 , 581,9 , {88,65,70}, 36,4 , 13524,23 , 25,5 , 4,0 , 4749,6 , 4755,7 , 0, 0, 1, 6, 7 }, // Ewondo/Latin/Cameroon - { 243, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31586,39 , 31625,191 , 158,27 , 31586,39 , 31625,191 , 158,27 , 18098,29 , 18127,45 , 18172,14 , 18098,29 , 18127,45 , 18172,14 , 571,6 , 590,7 , {88,65,70}, 36,4 , 13547,11 , 25,5 , 4,0 , 4762,5 , 4767,7 , 0, 0, 1, 6, 7 }, // Bafia/Latin/Cameroon - { 244, 7, 146, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 31816,48 , 31864,213 , 32077,24 , 31816,48 , 31864,213 , 32077,24 , 18186,28 , 18214,59 , 18273,14 , 18186,28 , 18214,59 , 18273,14 , 577,8 , 597,10 , {77,90,78}, 269,3 , 0,7 , 14,5 , 4,0 , 4774,5 , 4779,10 , 2, 1, 7, 6, 7 }, // MakhuwaMeetto/Latin/Mozambique - { 245, 7, 37, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 32101,48 , 32149,139 , 32288,24 , 32101,48 , 32149,139 , 32288,24 , 18287,28 , 18315,74 , 18389,14 , 18287,28 , 18315,74 , 18389,14 , 585,5 , 607,5 , {88,65,70}, 36,4 , 13558,17 , 4,4 , 8,6 , 4789,6 , 4795,7 , 0, 0, 1, 6, 7 }, // Mundang/Latin/Cameroon - { 246, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 32312,51 , 32363,143 , 158,27 , 32312,51 , 32363,143 , 158,27 , 18403,30 , 18433,89 , 18522,14 , 18403,30 , 18433,89 , 18522,14 , 590,4 , 612,4 , {88,65,70}, 36,4 , 13575,20 , 25,5 , 4,0 , 4802,6 , 4808,7 , 0, 0, 1, 6, 7 }, // Kwasio/Latin/Cameroon - { 247, 7, 201, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 1476,9 , 99,16 , 18,7 , 560,12 , 32506,54 , 32560,96 , 32656,24 , 32506,54 , 32560,96 , 32656,24 , 18536,38 , 18574,79 , 18653,14 , 18536,38 , 18574,79 , 18653,14 , 594,2 , 616,2 , {83,68,71}, 0,0 , 0,7 , 4,4 , 8,6 , 4815,9 , 4824,5 , 2, 1, 6, 5, 6 }, // Nuer/Latin/Sudan - { 248, 2, 178, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 1485,6 , 1491,30 , 37,5 , 8,10 , 32680,75 , 32755,121 , 32876,24 , 32680,75 , 32755,121 , 32876,24 , 18667,21 , 18688,73 , 18761,14 , 18667,21 , 18688,73 , 18761,14 , 0,2 , 0,2 , {82,85,66}, 275,4 , 0,7 , 14,5 , 4,0 , 4829,9 , 0,0 , 2, 1, 1, 6, 7 }, // Sakha/Cyrillic/Russia - { 249, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 32900,48 , 32948,117 , 158,27 , 32900,48 , 32948,117 , 158,27 , 18775,28 , 18803,60 , 18863,14 , 18775,28 , 18803,60 , 18863,14 , 596,9 , 618,9 , {84,90,83}, 192,3 , 13595,25 , 0,4 , 4,0 , 4838,9 , 4847,9 , 0, 0, 1, 6, 7 }, // Sangu/Latin/Tanzania - { 250, 7, 49, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 33065,48 , 33113,188 , 33301,24 , 33065,48 , 33113,188 , 33301,24 , 18877,28 , 18905,93 , 18998,14 , 18877,28 , 18905,93 , 18998,14 , 605,10 , 627,10 , {67,68,70}, 217,2 , 13620,23 , 4,4 , 4,0 , 4856,18 , 4874,32 , 2, 1, 1, 6, 7 }, // Congo Swahili/Latin/CongoKinshasa - { 251, 7, 156, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 17126,28 , 17154,54 , 16911,14 , 17126,28 , 17154,54 , 16911,14 , 551,8 , 565,10 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4906,13 , 4727,5 , 0, 0, 1, 6, 7 }, // Tasawaq/Latin/Niger - { 252, 35, 121, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 33325,50 , 33325,50 , 158,27 , 33325,50 , 33325,50 , 158,27 , 19012,30 , 19012,30 , 85,14 , 19012,30 , 19012,30 , 85,14 , 0,2 , 0,2 , {76,82,68}, 12,1 , 13643,15 , 4,4 , 8,6 , 4919,2 , 4921,4 , 2, 1, 1, 6, 7 }, // Vai/Vai/Liberia - { 252, 7, 121, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 33375,81 , 33375,81 , 158,27 , 33375,81 , 33375,81 , 158,27 , 19042,48 , 19042,48 , 85,14 , 19042,48 , 19042,48 , 85,14 , 0,2 , 0,2 , {76,82,68}, 12,1 , 13658,20 , 4,4 , 8,6 , 4925,3 , 4928,8 , 2, 1, 1, 6, 7 }, // Vai/Latin/Liberia - { 253, 7, 206, 44, 8217, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 221,9 , 221,9 , 72,10 , 462,18 , 37,5 , 8,10 , 33456,48 , 33504,99 , 33603,24 , 33456,48 , 33504,99 , 33603,24 , 19090,28 , 19118,53 , 19171,14 , 19090,28 , 19118,53 , 19171,14 , 0,2 , 0,2 , {67,72,70}, 0,0 , 0,7 , 14,5 , 4,0 , 4936,6 , 4942,6 , 2, 0, 1, 6, 7 }, // Walser/Latin/Switzerland - { 254, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 33627,51 , 33678,191 , 158,27 , 33627,51 , 33678,191 , 158,27 , 19185,21 , 19206,71 , 19277,14 , 19185,21 , 19206,71 , 19277,14 , 615,8 , 637,8 , {88,65,70}, 36,4 , 0,7 , 25,5 , 30,7 , 4948,6 , 4954,7 , 0, 0, 1, 6, 7 }, // Yangben/Latin/Cameroon - { 256, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 453,7 , 453,7 , 287,6 , 1521,23 , 37,5 , 8,10 , 33869,48 , 33917,85 , 34002,24 , 34026,48 , 34074,117 , 34002,24 , 19291,28 , 19319,54 , 3272,14 , 19291,28 , 19319,54 , 3272,14 , 0,2 , 0,2 , {69,85,82}, 131,1 , 2449,20 , 25,5 , 4,0 , 4961,9 , 2048,6 , 2, 1, 1, 6, 7 }, // Asturian/Latin/Spain - { 257, 7, 37, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 629,11 , 629,11 , 640,16 , 656,9 , 72,10 , 269,18 , 37,5 , 8,10 , 34191,174 , 34191,174 , 158,27 , 34191,174 , 34191,174 , 158,27 , 19373,60 , 19373,60 , 19433,25 , 19373,60 , 19373,60 , 19433,25 , 623,8 , 645,13 , {88,65,70}, 36,4 , 13678,12 , 14,5 , 4,0 , 4970,5 , 4975,7 , 0, 0, 1, 6, 7 }, // Ngomba/Latin/Cameroon - { 258, 7, 37, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 1544,10 , 82,17 , 37,5 , 8,10 , 34365,102 , 34365,102 , 158,27 , 34365,102 , 34365,102 , 158,27 , 19458,54 , 19458,54 , 19512,21 , 19458,54 , 19458,54 , 19512,21 , 0,2 , 0,2 , {88,65,70}, 36,4 , 13690,16 , 14,5 , 4,0 , 4982,4 , 4986,7 , 0, 0, 1, 6, 7 }, // Kako/Latin/Cameroon - { 259, 7, 37, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 269,18 , 37,5 , 8,10 , 34467,137 , 34604,142 , 34746,36 , 34467,137 , 34604,142 , 34746,36 , 19533,49 , 19533,49 , 19582,21 , 19533,49 , 19533,49 , 19582,21 , 0,2 , 0,2 , {88,65,70}, 36,4 , 13706,12 , 14,5 , 4,0 , 4993,5 , 4998,7 , 0, 0, 1, 6, 7 }, // Meta/Latin/Cameroon - { 260, 7, 37, 44, 46, 44, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1554,32 , 37,5 , 8,10 , 34782,164 , 34782,164 , 158,27 , 34782,164 , 34782,164 , 158,27 , 19603,111 , 19603,111 , 85,14 , 19603,111 , 19603,111 , 85,14 , 631,9 , 658,8 , {88,65,70}, 36,4 , 13718,16 , 14,5 , 4,0 , 5005,16 , 5021,7 , 0, 0, 1, 6, 7 }, // Ngiemboon/Latin/Cameroon + { 208, 7, 132, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 16830,28 , 16858,53 , 16911,14 , 16830,28 , 16858,53 , 16911,14 , 508,6 , 515,6 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4610,11 , 4621,5 , 0, 0, 1, 6, 7 }, // Koyra Chiini/Latin/Mali + { 209, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 26861,87 , 134,24 , 17628,48 , 26861,87 , 134,24 , 14815,28 , 14843,62 , 14905,14 , 14815,28 , 14843,62 , 14905,14 , 437,5 , 446,9 , {84,90,83}, 192,3 , 12978,27 , 0,4 , 4,0 , 4626,6 , 1331,8 , 0, 0, 1, 6, 7 }, // Rwa/Latin/Tanzania + { 210, 7, 111, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 29837,48 , 29885,186 , 30071,24 , 29837,48 , 29885,186 , 30071,24 , 16925,28 , 16953,69 , 17022,14 , 16925,28 , 16953,69 , 17022,14 , 514,2 , 521,2 , {75,69,83}, 2,3 , 13379,23 , 0,4 , 4,0 , 4632,6 , 1012,5 , 2, 1, 7, 6, 7 }, // Luo/Latin/Kenya + { 211, 7, 221, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 26335,48 , 26383,152 , 134,24 , 26335,48 , 26383,152 , 134,24 , 14575,28 , 14603,74 , 14677,14 , 14575,28 , 14603,74 , 14677,14 , 0,2 , 0,2 , {85,71,88}, 197,3 , 12923,26 , 4,4 , 78,5 , 4638,6 , 1387,6 , 0, 0, 1, 6, 7 }, // Chiga/Latin/Uganda + { 212, 7, 145, 44, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 30095,48 , 30143,86 , 30229,24 , 30095,48 , 30143,86 , 30229,24 , 17036,28 , 17064,48 , 17112,14 , 17036,28 , 17064,48 , 17112,14 , 516,9 , 523,10 , {77,65,68}, 0,0 , 13402,22 , 25,5 , 4,0 , 4644,8 , 4652,6 , 2, 1, 6, 5, 6 }, // Central Morocco Tamazight/Latin/Morocco + { 213, 7, 132, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 17126,28 , 17154,54 , 16911,14 , 17126,28 , 17154,54 , 16911,14 , 508,6 , 515,6 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4658,15 , 4621,5 , 0, 0, 1, 6, 7 }, // Koyraboro Senni/Latin/Mali + { 214, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 17628,48 , 30253,84 , 134,24 , 17628,48 , 30253,84 , 134,24 , 17208,28 , 17236,63 , 9599,14 , 17208,28 , 17236,63 , 9599,14 , 525,5 , 533,8 , {84,90,83}, 192,3 , 11152,27 , 0,4 , 4,0 , 4673,9 , 1331,8 , 0, 0, 1, 6, 7 }, // Shambala/Latin/Tanzania + { 215, 13, 100, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 518,6 , 35,18 , 18,7 , 25,12 , 30337,88 , 30337,88 , 30425,31 , 30337,88 , 30337,88 , 30425,31 , 17299,33 , 17332,54 , 17386,19 , 17299,33 , 17332,54 , 17386,19 , 530,3 , 541,6 , {73,78,82}, 123,1 , 13424,10 , 14,5 , 4,0 , 4682,4 , 2282,4 , 2, 1, 7, 7, 7 }, // Bodo/Devanagari/India + { 230, 7, 49, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 30456,49 , 30505,99 , 30604,24 , 30456,49 , 30505,99 , 30604,24 , 17405,28 , 17433,50 , 17483,14 , 17405,28 , 17433,50 , 17483,14 , 533,5 , 547,6 , {67,68,70}, 217,2 , 13434,24 , 0,4 , 4,0 , 4686,8 , 4694,16 , 2, 1, 1, 6, 7 }, // LubaKatanga/Latin/CongoKinshasa + { 237, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 8218, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 30628,48 , 30676,195 , 30871,24 , 30628,48 , 30676,195 , 30871,24 , 17497,28 , 17525,72 , 17597,14 , 17497,28 , 17525,72 , 17597,14 , 538,3 , 553,3 , {88,65,70}, 37,4 , 13458,21 , 0,4 , 4,0 , 4710,5 , 4715,7 , 0, 0, 1, 6, 7 }, // Aghem/Latin/Cameroon + { 238, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8222, 8220, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 30895,48 , 30943,90 , 31033,24 , 30895,48 , 30943,90 , 31033,24 , 17611,28 , 17639,70 , 17709,14 , 17611,28 , 17639,70 , 17709,14 , 541,10 , 556,9 , {88,65,70}, 37,4 , 13479,22 , 25,5 , 4,0 , 4722,5 , 4727,8 , 0, 0, 1, 6, 7 }, // Basaa/Latin/Cameroon + { 239, 7, 156, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 17126,28 , 17723,53 , 17776,14 , 17126,28 , 17723,53 , 17776,14 , 551,8 , 565,10 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4735,10 , 4745,5 , 0, 0, 1, 6, 7 }, // Zarma/Latin/Niger + { 240, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31057,49 , 31106,99 , 31205,24 , 31057,49 , 31106,99 , 31205,24 , 17790,28 , 17818,45 , 17863,14 , 17790,28 , 17818,45 , 17863,14 , 559,5 , 575,6 , {88,65,70}, 37,4 , 0,7 , 25,5 , 4,0 , 4750,5 , 1621,8 , 0, 0, 1, 6, 7 }, // Duala/Latin/Cameroon + { 241, 7, 187, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31229,36 , 31265,82 , 31347,24 , 31229,36 , 31265,82 , 31347,24 , 17877,28 , 17905,50 , 17955,14 , 17877,28 , 17905,50 , 17955,14 , 0,2 , 0,2 , {88,79,70}, 209,3 , 13501,23 , 25,5 , 4,0 , 4755,5 , 4760,7 , 0, 0, 1, 6, 7 }, // JolaFonyi/Latin/Senegal + { 242, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31371,50 , 31421,141 , 31562,24 , 31371,50 , 31421,141 , 31562,24 , 17969,30 , 17999,85 , 18084,14 , 17969,30 , 17999,85 , 18084,14 , 564,7 , 581,9 , {88,65,70}, 37,4 , 13524,23 , 25,5 , 4,0 , 4767,6 , 4773,7 , 0, 0, 1, 6, 7 }, // Ewondo/Latin/Cameroon + { 243, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 31586,39 , 31625,191 , 158,27 , 31586,39 , 31625,191 , 158,27 , 18098,29 , 18127,45 , 18172,14 , 18098,29 , 18127,45 , 18172,14 , 571,6 , 590,7 , {88,65,70}, 37,4 , 13547,11 , 25,5 , 4,0 , 4780,5 , 4785,7 , 0, 0, 1, 6, 7 }, // Bafia/Latin/Cameroon + { 244, 7, 146, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 31816,48 , 31864,213 , 32077,24 , 31816,48 , 31864,213 , 32077,24 , 18186,28 , 18214,59 , 18273,14 , 18186,28 , 18214,59 , 18273,14 , 577,8 , 597,10 , {77,90,78}, 269,3 , 0,7 , 14,5 , 4,0 , 4792,5 , 4797,10 , 2, 1, 7, 6, 7 }, // MakhuwaMeetto/Latin/Mozambique + { 245, 7, 37, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 32101,48 , 32149,139 , 32288,24 , 32101,48 , 32149,139 , 32288,24 , 18287,28 , 18315,74 , 18389,14 , 18287,28 , 18315,74 , 18389,14 , 585,5 , 607,5 , {88,65,70}, 37,4 , 13558,17 , 4,4 , 8,6 , 4807,6 , 4813,7 , 0, 0, 1, 6, 7 }, // Mundang/Latin/Cameroon + { 246, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8221, 171, 187, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 32312,51 , 32363,143 , 158,27 , 32312,51 , 32363,143 , 158,27 , 18403,30 , 18433,89 , 18522,14 , 18403,30 , 18433,89 , 18522,14 , 590,4 , 612,4 , {88,65,70}, 37,4 , 13575,20 , 25,5 , 4,0 , 4820,6 , 4826,7 , 0, 0, 1, 6, 7 }, // Kwasio/Latin/Cameroon + { 247, 7, 201, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 1476,9 , 99,16 , 18,7 , 560,12 , 32506,54 , 32560,96 , 32656,24 , 32506,54 , 32560,96 , 32656,24 , 18536,38 , 18574,79 , 18653,14 , 18536,38 , 18574,79 , 18653,14 , 594,2 , 616,2 , {83,68,71}, 0,0 , 0,7 , 4,4 , 8,6 , 4833,9 , 4842,5 , 2, 1, 6, 5, 6 }, // Nuer/Latin/Sudan + { 248, 2, 178, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 1485,6 , 1491,30 , 37,5 , 8,10 , 32680,75 , 32755,121 , 32876,24 , 32680,75 , 32755,121 , 32876,24 , 18667,21 , 18688,73 , 18761,14 , 18667,21 , 18688,73 , 18761,14 , 0,2 , 0,2 , {82,85,66}, 275,4 , 0,7 , 14,5 , 4,0 , 4847,9 , 0,0 , 2, 1, 1, 6, 7 }, // Sakha/Cyrillic/Russia + { 249, 7, 210, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 32900,48 , 32948,117 , 158,27 , 32900,48 , 32948,117 , 158,27 , 18775,28 , 18803,60 , 18863,14 , 18775,28 , 18803,60 , 18863,14 , 596,9 , 618,9 , {84,90,83}, 192,3 , 13595,25 , 0,4 , 4,0 , 4856,9 , 4865,9 , 0, 0, 1, 6, 7 }, // Sangu/Latin/Tanzania + { 250, 7, 49, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 33065,48 , 33113,188 , 33301,24 , 33065,48 , 33113,188 , 33301,24 , 18877,28 , 18905,93 , 18998,14 , 18877,28 , 18905,93 , 18998,14 , 605,10 , 627,10 , {67,68,70}, 217,2 , 13620,23 , 4,4 , 4,0 , 4874,18 , 4892,32 , 2, 1, 1, 6, 7 }, // Congo Swahili/Latin/CongoKinshasa + { 251, 7, 156, 46, 160, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 29679,46 , 29725,88 , 29813,24 , 29679,46 , 29725,88 , 29813,24 , 17126,28 , 17154,54 , 16911,14 , 17126,28 , 17154,54 , 16911,14 , 551,8 , 565,10 , {88,79,70}, 209,3 , 13356,23 , 0,4 , 4,0 , 4924,13 , 4745,5 , 0, 0, 1, 6, 7 }, // Tasawaq/Latin/Niger + { 252, 35, 121, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 33325,50 , 33325,50 , 158,27 , 33325,50 , 33325,50 , 158,27 , 19012,30 , 19012,30 , 85,14 , 19012,30 , 19012,30 , 85,14 , 0,2 , 0,2 , {76,82,68}, 12,1 , 13643,15 , 4,4 , 8,6 , 4937,2 , 4939,4 , 2, 1, 1, 6, 7 }, // Vai/Vai/Liberia + { 252, 7, 121, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 141,10 , 10,17 , 18,7 , 25,12 , 33375,81 , 33375,81 , 158,27 , 33375,81 , 33375,81 , 158,27 , 19042,48 , 19042,48 , 85,14 , 19042,48 , 19042,48 , 85,14 , 0,2 , 0,2 , {76,82,68}, 12,1 , 13658,20 , 4,4 , 8,6 , 4943,3 , 4946,8 , 2, 1, 1, 6, 7 }, // Vai/Latin/Liberia + { 253, 7, 206, 44, 8217, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 221,9 , 221,9 , 72,10 , 462,18 , 37,5 , 8,10 , 33456,48 , 33504,99 , 33603,24 , 33456,48 , 33504,99 , 33603,24 , 19090,28 , 19118,53 , 19171,14 , 19090,28 , 19118,53 , 19171,14 , 0,2 , 0,2 , {67,72,70}, 0,0 , 0,7 , 14,5 , 4,0 , 4954,6 , 4960,6 , 2, 0, 1, 6, 7 }, // Walser/Latin/Switzerland + { 254, 7, 37, 44, 160, 59, 37, 48, 45, 43, 101, 171, 187, 171, 187, 0,6 , 0,6 , 0,6 , 0,6 , 364,8 , 99,16 , 37,5 , 8,10 , 33627,51 , 33678,191 , 158,27 , 33627,51 , 33678,191 , 158,27 , 19185,21 , 19206,71 , 19277,14 , 19185,21 , 19206,71 , 19277,14 , 615,8 , 637,8 , {88,65,70}, 37,4 , 0,7 , 25,5 , 30,7 , 4966,6 , 4972,7 , 0, 0, 1, 6, 7 }, // Yangben/Latin/Cameroon + { 256, 7, 197, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 453,7 , 453,7 , 287,6 , 1521,23 , 37,5 , 8,10 , 33869,48 , 33917,85 , 34002,24 , 34026,48 , 34074,117 , 34002,24 , 19291,28 , 19319,54 , 3272,14 , 19291,28 , 19319,54 , 3272,14 , 0,2 , 0,2 , {69,85,82}, 19,1 , 2460,20 , 25,5 , 4,0 , 4979,9 , 2054,6 , 2, 1, 1, 6, 7 }, // Asturian/Latin/Spain + { 257, 7, 37, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 629,11 , 629,11 , 640,16 , 656,9 , 72,10 , 269,18 , 37,5 , 8,10 , 34191,174 , 34191,174 , 158,27 , 34191,174 , 34191,174 , 158,27 , 19373,60 , 19373,60 , 19433,25 , 19373,60 , 19373,60 , 19433,25 , 623,8 , 645,13 , {88,65,70}, 37,4 , 13678,12 , 14,5 , 4,0 , 4988,5 , 4993,7 , 0, 0, 1, 6, 7 }, // Ngomba/Latin/Cameroon + { 258, 7, 37, 44, 46, 59, 37, 48, 45, 43, 101, 171, 187, 8249, 8250, 0,6 , 0,6 , 0,6 , 0,6 , 1544,10 , 82,17 , 37,5 , 8,10 , 34365,102 , 34365,102 , 158,27 , 34365,102 , 34365,102 , 158,27 , 19458,54 , 19458,54 , 19512,21 , 19458,54 , 19458,54 , 19512,21 , 0,2 , 0,2 , {88,65,70}, 37,4 , 13690,16 , 14,5 , 4,0 , 5000,4 , 5004,7 , 0, 0, 1, 6, 7 }, // Kako/Latin/Cameroon + { 259, 7, 37, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 72,10 , 269,18 , 37,5 , 8,10 , 34467,137 , 34604,142 , 34746,36 , 34467,137 , 34604,142 , 34746,36 , 19533,49 , 19533,49 , 19582,21 , 19533,49 , 19533,49 , 19582,21 , 0,2 , 0,2 , {88,65,70}, 37,4 , 13706,12 , 14,5 , 4,0 , 5011,5 , 5016,7 , 0, 0, 1, 6, 7 }, // Meta/Latin/Cameroon + { 260, 7, 37, 44, 46, 44, 37, 48, 45, 43, 101, 171, 187, 8220, 8221, 0,6 , 0,6 , 0,6 , 0,6 , 27,8 , 1554,32 , 37,5 , 8,10 , 34782,164 , 34782,164 , 158,27 , 34782,164 , 34782,164 , 158,27 , 19603,111 , 19603,111 , 85,14 , 19603,111 , 19603,111 , 85,14 , 631,9 , 658,8 , {88,65,70}, 37,4 , 13718,16 , 14,5 , 4,0 , 5023,16 , 5039,7 , 0, 0, 1, 6, 7 }, // Ngiemboon/Latin/Cameroon { 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 0s }; @@ -2448,19 +2451,19 @@ static const ushort months_data[] = { 0x440, 0x443, 0x430, 0x440, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x431, 0x430, 0x440, 0x3b, 0x43d, 0x43e, 0x432, 0x435, 0x43c, 0x431, 0x430, -0x440, 0x3b, 0x434, 0x435, 0x446, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x3b, 0x444, 0x435, -0x431, 0x440, 0x443, 0x430, 0x440, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c, 0x430, 0x458, -0x3b, 0x458, 0x443, 0x43d, 0x438, 0x3b, 0x458, 0x443, 0x43b, 0x438, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, -0x43f, 0x442, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x431, 0x430, 0x440, 0x3b, 0x43d, 0x43e, 0x432, 0x435, -0x43c, 0x431, 0x430, 0x440, 0x3b, 0x434, 0x435, 0x446, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, -0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, -0x6c, 0x3b, 0x61, 0x76, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, -0x63, 0x3b, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, -0x74, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, -0x61, 0x76, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x6f, 0x6b, 0x74, -0x6f, 0x62, 0x61, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, -0x61, 0x72, 0x3b, 0x6a, 0x3b, 0x66, 0x3b, 0x6d, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x6a, 0x3b, 0x6a, 0x3b, 0x61, 0x3b, 0x73, -0x3b, 0x6f, 0x3b, 0x6e, 0x3b, 0x64, 0x3b, 0x42f, 0x43d, 0x432, 0x430, 0x440, 0x44c, 0x3b, 0x424, 0x435, 0x432, 0x440, 0x430, 0x43b, +0x440, 0x3b, 0x434, 0x435, 0x446, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, +0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, +0x76, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x3b, 0x6a, +0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, +0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67, +0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61, +0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, +0x6a, 0x3b, 0x66, 0x3b, 0x6d, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x6a, 0x3b, 0x6a, 0x3b, 0x61, 0x3b, 0x73, 0x3b, 0x6f, 0x3b, +0x6e, 0x3b, 0x64, 0x3b, 0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x3b, 0x444, 0x435, 0x431, 0x440, 0x443, 0x430, 0x440, 0x3b, 0x43c, +0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x438, 0x3b, 0x458, +0x443, 0x43b, 0x438, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x435, 0x43c, 0x431, 0x430, 0x440, +0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x431, 0x430, 0x440, 0x3b, 0x43d, 0x43e, 0x432, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x434, 0x435, +0x446, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x42f, 0x43d, 0x432, 0x430, 0x440, 0x44c, 0x3b, 0x424, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x44a, 0x438, 0x3b, 0x410, 0x43f, 0x440, 0x435, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418, 0x44e, 0x43d, 0x44c, 0x3b, 0x418, 0x44e, 0x43b, 0x44c, 0x3b, 0x410, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x421, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41d, 0x43e, 0x44f, 0x431, 0x440, 0x44c, @@ -3841,15 +3844,15 @@ static const ushort days_data[] = { 0x3b, 0x43f, 0x435, 0x442, 0x3b, 0x441, 0x443, 0x431, 0x3b, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440, 0x430, 0x43a, 0x3b, 0x441, 0x440, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, 0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x430, 0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, -0x3b, 0x43d, 0x3b, 0x43f, 0x3b, 0x443, 0x3b, 0x441, 0x3b, 0x447, 0x3b, 0x43f, 0x3b, 0x441, 0x3b, 0x43d, 0x435, 0x434, 0x3b, 0x43f, -0x43e, 0x43d, 0x3b, 0x443, 0x442, 0x43e, 0x3b, 0x441, 0x440, 0x438, 0x3b, 0x447, 0x435, 0x442, 0x3b, 0x43f, 0x435, 0x442, 0x3b, 0x441, -0x443, 0x431, 0x3b, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x43a, 0x3b, -0x443, 0x442, 0x43e, 0x440, 0x430, 0x43a, 0x3b, 0x441, 0x440, 0x438, 0x458, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, -0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x430, 0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x3b, 0x6e, 0x65, 0x64, -0x3b, 0x70, 0x6f, 0x6e, 0x3b, 0x75, 0x74, 0x6f, 0x3b, 0x73, 0x72, 0x65, 0x3b, 0x10d, 0x65, 0x74, 0x3b, 0x70, 0x65, 0x74, -0x3b, 0x73, 0x75, 0x62, 0x3b, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x65, 0x64, 0x65, 0x6c, -0x6a, 0x61, 0x6b, 0x3b, 0x75, 0x74, 0x6f, 0x72, 0x61, 0x6b, 0x3b, 0x73, 0x72, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x65, 0x74, -0x76, 0x72, 0x74, 0x61, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61, 0x6b, 0x3b, 0x73, 0x75, 0x62, 0x6f, 0x74, 0x61, 0x3b, 0x425, +0x3b, 0x43d, 0x3b, 0x43f, 0x3b, 0x443, 0x3b, 0x441, 0x3b, 0x447, 0x3b, 0x43f, 0x3b, 0x441, 0x3b, 0x6e, 0x65, 0x64, 0x3b, 0x70, +0x6f, 0x6e, 0x3b, 0x75, 0x74, 0x6f, 0x3b, 0x73, 0x72, 0x65, 0x3b, 0x10d, 0x65, 0x74, 0x3b, 0x70, 0x65, 0x74, 0x3b, 0x73, +0x75, 0x62, 0x3b, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, +0x6b, 0x3b, 0x75, 0x74, 0x6f, 0x72, 0x61, 0x6b, 0x3b, 0x73, 0x72, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x65, 0x74, 0x76, 0x72, +0x74, 0x61, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61, 0x6b, 0x3b, 0x73, 0x75, 0x62, 0x6f, 0x74, 0x61, 0x3b, 0x43d, 0x435, 0x434, +0x3b, 0x43f, 0x43e, 0x43d, 0x3b, 0x443, 0x442, 0x43e, 0x3b, 0x441, 0x440, 0x438, 0x3b, 0x447, 0x435, 0x442, 0x3b, 0x43f, 0x435, 0x442, +0x3b, 0x441, 0x443, 0x431, 0x3b, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, +0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440, 0x430, 0x43a, 0x3b, 0x441, 0x440, 0x438, 0x458, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, +0x432, 0x440, 0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x430, 0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x3b, 0x425, 0x446, 0x431, 0x3b, 0x41a, 0x440, 0x441, 0x3b, 0x414, 0x446, 0x433, 0x3b, 0x4d4, 0x440, 0x442, 0x3b, 0x426, 0x43f, 0x440, 0x3b, 0x41c, 0x440, 0x431, 0x3b, 0x421, 0x431, 0x442, 0x3b, 0x425, 0x443, 0x44b, 0x446, 0x430, 0x443, 0x431, 0x43e, 0x43d, 0x3b, 0x41a, 0x44a, 0x443, 0x44b, 0x440, 0x438, 0x441, 0x4d5, 0x440, 0x3b, 0x414, 0x44b, 0x446, 0x446, 0x4d5, 0x433, 0x3b, 0x4d4, 0x440, 0x442, 0x44b, 0x446, 0x446, @@ -4490,13 +4493,13 @@ static const ushort pm_data[] = { }; static const ushort currency_symbol_data[] = { -0x42, 0x72, 0x4b, 0x73, 0x68, 0x46, 0x64, 0x6a, 0x4e, 0x66, 0x6b, 0x52, 0x24, 0x4c, 0x65, 0x6b, 0x64, 0x65, 0x6e, 0x1265, -0x122d, 0x62c, 0x2e, 0x645, 0x2e, 0x200f, 0x62f, 0x2e, 0x62c, 0x2e, 0x200f, 0x62f, 0x2e, 0x628, 0x2e, 0x200f, 0x46, 0x43, 0x46, 0x41, -0x641, 0x2e, 0x62c, 0x2e, 0x642, 0x2e, 0x200f, 0x62f, 0x2e, 0x639, 0x2e, 0x200f, 0x20aa, 0x62f, 0x2e, 0x623, 0x2e, 0x200f, 0x62f, 0x2e, -0x643, 0x2e, 0x200f, 0x644, 0x2e, 0x644, 0x2e, 0x200f, 0x62f, 0x2e, 0x644, 0x2e, 0x200f, 0x623, 0x2e, 0x645, 0x2e, 0x200f, 0x62f, 0x2e, -0x645, 0x2e, 0x200f, 0x631, 0x2e, 0x639, 0x2e, 0x200f, 0x631, 0x2e, 0x642, 0x2e, 0x200f, 0x631, 0x2e, 0x633, 0x2e, 0x200f, 0x53, 0x644, -0x2e, 0x633, 0x2e, 0x200f, 0x62f, 0x2e, 0x62a, 0x2e, 0x200f, 0x62f, 0x2e, 0x625, 0x2e, 0x200f, 0x631, 0x2e, 0x64a, 0x2e, 0x200f, 0x564, -0x580, 0x2e, 0x20b9, 0x6d, 0x61, 0x6e, 0x2e, 0x43c, 0x430, 0x43d, 0x2e, 0x20ac, 0x9f3, 0x4e, 0x75, 0x2e, 0x43b, 0x432, 0x2e, 0x4b, +0x42, 0x72, 0x4b, 0x73, 0x68, 0x46, 0x64, 0x6a, 0x4e, 0x66, 0x6b, 0x52, 0x24, 0x4c, 0x65, 0x6b, 0x64, 0x65, 0x6e, 0x20ac, +0x1265, 0x122d, 0x62c, 0x2e, 0x645, 0x2e, 0x200f, 0x62f, 0x2e, 0x62c, 0x2e, 0x200f, 0x62f, 0x2e, 0x628, 0x2e, 0x200f, 0x46, 0x43, 0x46, +0x41, 0x641, 0x2e, 0x62c, 0x2e, 0x642, 0x2e, 0x200f, 0x62f, 0x2e, 0x639, 0x2e, 0x200f, 0x20aa, 0x62f, 0x2e, 0x623, 0x2e, 0x200f, 0x62f, +0x2e, 0x643, 0x2e, 0x200f, 0x644, 0x2e, 0x644, 0x2e, 0x200f, 0x62f, 0x2e, 0x644, 0x2e, 0x200f, 0x623, 0x2e, 0x645, 0x2e, 0x200f, 0x62f, +0x2e, 0x645, 0x2e, 0x200f, 0x631, 0x2e, 0x639, 0x2e, 0x200f, 0x631, 0x2e, 0x642, 0x2e, 0x200f, 0x631, 0x2e, 0x633, 0x2e, 0x200f, 0x53, +0x644, 0x2e, 0x633, 0x2e, 0x200f, 0x62f, 0x2e, 0x62a, 0x2e, 0x200f, 0x62f, 0x2e, 0x625, 0x2e, 0x200f, 0x631, 0x2e, 0x64a, 0x2e, 0x200f, +0x564, 0x580, 0x2e, 0x20b9, 0x6d, 0x61, 0x6e, 0x2e, 0x43c, 0x430, 0x43d, 0x2e, 0x9f3, 0x4e, 0x75, 0x2e, 0x43b, 0x432, 0x2e, 0x4b, 0x440, 0x2e, 0x17db, 0xffe5, 0x4d, 0x4f, 0x50, 0x24, 0x4e, 0x54, 0x24, 0x6b, 0x6e, 0x4b, 0x4d, 0x4b, 0x10d, 0x6b, 0x72, 0x41, 0x66, 0x6c, 0x2e, 0x4e, 0x41, 0x66, 0x2e, 0x45, 0x43, 0x24, 0x50, 0xa3, 0x44, 0x47, 0x48, 0x20b5, 0x41, 0x72, 0x4d, 0x4b, 0x52, 0x73, 0x20a6, 0x20b1, 0x57, 0x53, 0x24, 0x53, 0x52, 0x4c, 0x65, 0x45, 0x54, 0x53, 0x68, 0x54, 0x24, 0x55, 0x53, 0x68, @@ -4504,7 +4507,7 @@ static const ushort currency_symbol_data[] = { 0x43, 0x46, 0x50, 0x46, 0x47, 0x47, 0x55, 0x4d, 0x52, 0x46, 0x43, 0x48, 0x46, 0x4c, 0x53, 0x44, 0x54, 0x46, 0x74, 0x52, 0x70, 0x20b8, 0x441, 0x43e, 0x43c, 0x20a9, 0x20ad, 0x4c, 0x73, 0x4b, 0x7a, 0x4c, 0x74, 0x434, 0x435, 0x43d, 0x52, 0x4d, 0x20ae, 0x928, 0x947, 0x930, 0x942, 0x60b, 0xfdfc, 0x7a, 0x142, 0x52, 0x24, 0x4d, 0x54, 0x6e, 0x44, 0x62, 0x631, 0x440, 0x443, 0x431, 0x2e, 0x20b4, -0x434, 0x438, 0x43d, 0x2e, 0x41a, 0x41c, 0x64, 0x69, 0x6e, 0x2e, 0xdbb, 0xdd4, 0x2e, 0x42, 0x73, 0x20a1, 0x51, 0x4c, 0x43, 0x24, +0x434, 0x438, 0x43d, 0x2e, 0x64, 0x69, 0x6e, 0x2e, 0x41a, 0x41c, 0xdbb, 0xdd4, 0x2e, 0x42, 0x73, 0x20a1, 0x51, 0x4c, 0x43, 0x24, 0x42, 0x2f, 0x2e, 0x20b2, 0x53, 0x2f, 0x2e, 0x42, 0x73, 0x2e, 0x52, 0x73, 0x2e, 0xe3f, 0xa5, 0x20ba, 0x441, 0x45e, 0x43c, 0x73, 0x6f, 0x2bb, 0x6d, 0x20ab }; @@ -4514,360 +4517,360 @@ static const ushort currency_display_name_data[] = { 0x72, 0x72, 0x69, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x75, 0x69, 0x64, 0x2d, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x72, 0x61, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x65, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, -0x3b, 0x12e8, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x20, 0x1265, 0x122d, 0x3b, 0x3b, 0x12e8, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x20, 0x1265, -0x122d, 0x3b, 0x3b, 0x3b, 0x3b, 0x12e8, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x20, 0x1265, 0x122d, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, -0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, -0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, -0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, -0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, -0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, -0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, -0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, -0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, -0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, -0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, -0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, -0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, -0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, -0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, -0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, -0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, -0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, -0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, -0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, -0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, -0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, -0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, -0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, -0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, -0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, -0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, -0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, -0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, -0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, -0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, -0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, -0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, -0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, -0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, -0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, -0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, -0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, -0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, -0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, -0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, -0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, -0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, -0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, -0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, -0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, -0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, -0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, -0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, -0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, -0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, -0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, -0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, -0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, -0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, -0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, +0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12e8, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x20, 0x1265, +0x122d, 0x3b, 0x3b, 0x12e8, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x20, 0x1265, 0x122d, 0x3b, 0x3b, 0x3b, 0x3b, 0x12e8, 0x12a2, 0x1275, 0x12ee, +0x1335, 0x12eb, 0x20, 0x1265, 0x122d, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, +0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, +0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, +0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, +0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, +0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, +0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, +0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, +0x62c, 0x632, 0x627, 0x626, 0x631, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, +0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, +0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, +0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, +0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x3b, 0x641, 0x631, +0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, +0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, +0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, +0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, +0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, +0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, +0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, +0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, +0x643, 0x20, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631, +0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, +0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, +0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, +0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x641, +0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, +0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, +0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, +0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, +0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x3b, 0x646, 0x627, 0x643, 0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, +0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, +0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, +0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, +0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, +0x639, 0x631, 0x627, 0x642, 0x64a, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, +0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, +0x62f, 0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, +0x64a, 0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, +0x62f, 0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, +0x3b, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, +0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x3b, 0x62f, +0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, +0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, +0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, +0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, +0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, +0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, +0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, +0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, +0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, +0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, +0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, +0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62c, +0x646, 0x64a, 0x629, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, -0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x623, 0x648, 0x642, -0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, -0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, -0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, -0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, -0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, -0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, +0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, +0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, +0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, +0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, +0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, +0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, +0x646, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, -0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, +0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, -0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, -0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, -0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, -0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, -0x648, 0x62f, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, +0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, +0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, +0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, +0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, 0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642, +0x637, 0x631, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x631, -0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, +0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, -0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, -0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, -0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, -0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, -0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, -0x629, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, +0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x3b, 0x62c, 0x646, +0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, +0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, +0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, +0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x3b, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, +0x64a, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x644, 0x64a, 0x631, -0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, +0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a, 0x629, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, -0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, -0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, -0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, -0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, -0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, -0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, -0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, -0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, -0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x540, 0x561, 0x575, 0x56f, 0x561, 0x56f, 0x561, 0x576, 0x20, 0x564, 0x580, 0x561, 0x574, 0x3b, -0x3b, 0x540, 0x561, 0x575, 0x56f, 0x561, 0x56f, 0x561, 0x576, 0x20, 0x564, 0x580, 0x561, 0x574, 0x3b, 0x3b, 0x3b, 0x3b, 0x540, 0x561, -0x575, 0x56f, 0x561, 0x56f, 0x561, 0x576, 0x20, 0x564, 0x580, 0x561, 0x574, 0x3b, 0x41, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, -0x61, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x74, 0x131, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x41, 0x7a, 0x259, 0x72, 0x62, -0x61, 0x79, 0x63, 0x61, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x74, 0x131, 0x3b, 0x43c, 0x430, 0x43d, 0x430, 0x442, 0x3b, 0x3b, -0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x9ac, 0x9be, 0x982, -0x9b2, 0x9be, 0x9a6, 0x9c7, 0x9b6, 0x9c0, 0x20, 0x99f, 0x9be, 0x995, 0x9be, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x9ad, 0x9be, -0x9b0, 0x9a4, 0x9c0, 0x9af, 0x9bc, 0x20, 0x9b0, 0x9c1, 0x9aa, 0x9bf, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xf51, 0xf44, 0xf74, -0xf63, 0xf0b, 0xf40, 0xfb2, 0xf58, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, -0x3b, 0x3b, 0x3b, 0x411, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x20, 0x43b, 0x435, 0x432, 0x3b, 0x3b, 0x431, 0x44a, -0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x20, 0x43b, 0x435, 0x432, 0x3b, 0x3b, 0x3b, 0x3b, 0x431, 0x44a, 0x43b, 0x433, 0x430, -0x440, 0x441, 0x43a, 0x438, 0x20, 0x43b, 0x435, 0x432, 0x430, 0x3b, 0x1019, 0x103c, 0x1014, 0x103a, 0x1019, 0x102c, 0x20, 0x1000, 0x103b, 0x1015, -0x103a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x431, 0x435, 0x43b, 0x430, 0x440, 0x443, 0x441, 0x43a, 0x456, 0x20, 0x440, 0x443, -0x431, 0x435, 0x43b, 0x44c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x179a, 0x17c0, 0x179b, 0x20, 0x1780, 0x1798, 0x17d2, 0x1796, 0x17bb, -0x1787, 0x17b6, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, -0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x73, 0x3b, 0x4eba, 0x6c11, 0x5e01, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x6e2f, -0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x6fb3, 0x95e8, 0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x65b0, 0x52a0, -0x5761, 0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x6fb3, 0x9580, 0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x65b0, -0x81fa, 0x5e63, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x61, 0x20, 0x6b, 0x75, -0x6e, 0x61, 0x3b, 0x3b, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x61, 0x20, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x3b, 0x68, -0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x65, 0x20, 0x6b, 0x75, 0x6e, 0x65, 0x3b, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, -0x69, 0x68, 0x20, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x69, 0x68, 0x20, 0x6b, 0x75, -0x6e, 0x61, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x72, -0x6b, 0x61, 0x3b, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61, -0x72, 0x6b, 0x61, 0x3b, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x65, 0x20, 0x6d, -0x61, 0x72, 0x6b, 0x65, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x69, 0x68, 0x20, -0x6d, 0x61, 0x72, 0x61, 0x6b, 0x61, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x69, -0x68, 0x20, 0x6d, 0x61, 0x72, 0x61, 0x6b, 0x61, 0x3b, 0x10d, 0x65, 0x73, 0x6b, 0xe1, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x6e, -0x61, 0x3b, 0x3b, 0x10d, 0x65, 0x73, 0x6b, 0xe1, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x6e, 0x61, 0x3b, 0x3b, 0x10d, 0x65, 0x73, -0x6b, 0xe9, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x6e, 0x79, 0x3b, 0x3b, 0x10d, 0x65, 0x73, 0x6b, 0xfd, 0x63, 0x68, 0x20, 0x6b, -0x6f, 0x72, 0x75, 0x6e, 0x3b, 0x44, 0x61, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65, 0x3b, 0x3b, 0x44, 0x61, -0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x44, 0x61, 0x6e, 0x73, 0x6b, 0x65, 0x20, -0x6b, 0x72, 0x6f, 0x6e, 0x65, 0x72, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, -0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x41, 0x72, 0x75, 0x62, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x72, -0x69, 0x6e, 0x3b, 0x3b, 0x41, 0x72, 0x75, 0x62, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x72, 0x69, 0x6e, -0x3b, 0x3b, 0x3b, 0x3b, 0x41, 0x72, 0x75, 0x62, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x72, 0x69, 0x6e, -0x3b, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x2d, 0x41, 0x6e, 0x74, 0x69, 0x6c, 0x6c, 0x69, 0x61, -0x61, 0x6e, 0x73, 0x65, 0x20, 0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x3b, 0x3b, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, -0x6e, 0x64, 0x73, 0x2d, 0x41, 0x6e, 0x74, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x67, 0x75, 0x6c, -0x64, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x2d, 0x41, 0x6e, -0x74, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x3b, 0x53, 0x75, -0x72, 0x69, 0x6e, 0x61, 0x61, 0x6d, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, -0x3b, 0x3b, 0x55, 0x53, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x55, 0x53, 0x20, 0x64, 0x6f, 0x6c, 0x6c, -0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x55, 0x53, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x45, 0x61, 0x73, -0x74, 0x20, 0x43, 0x61, 0x72, 0x69, 0x62, 0x62, 0x65, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, -0x45, 0x61, 0x73, 0x74, 0x20, 0x43, 0x61, 0x72, 0x69, 0x62, 0x62, 0x65, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, -0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x61, 0x73, 0x74, 0x20, 0x43, 0x61, 0x72, 0x69, 0x62, 0x62, 0x65, 0x61, 0x6e, 0x20, -0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x44, -0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, -0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x64, -0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, -0x61, 0x72, 0x3b, 0x3b, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, -0x3b, 0x3b, 0x3b, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, -0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x42, 0x61, -0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x61, -0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x65, 0x6c, 0x69, -0x7a, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x6f, -0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, -0x72, 0x73, 0x3b, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, -0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, -0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x6f, 0x74, 0x73, -0x77, 0x61, 0x6e, 0x61, 0x6e, 0x20, 0x50, 0x75, 0x6c, 0x61, 0x3b, 0x3b, 0x42, 0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, -0x6e, 0x20, 0x70, 0x75, 0x6c, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x6e, 0x20, -0x70, 0x75, 0x6c, 0x61, 0x73, 0x3b, 0x43, 0x46, 0x41, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x42, 0x45, 0x41, 0x43, -0x3b, 0x3b, 0x43, 0x46, 0x41, 0x20, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x42, 0x45, 0x41, 0x43, 0x3b, 0x3b, 0x3b, 0x3b, -0x43, 0x46, 0x41, 0x20, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x42, 0x45, 0x41, 0x43, 0x3b, 0x43, 0x61, 0x6e, 0x61, -0x64, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61, -0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61, 0x6e, -0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, -0x6e, 0x64, 0x73, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49, -0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x43, 0x61, 0x79, -0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, -0x46, 0x69, 0x6a, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x46, 0x69, 0x6a, 0x69, 0x61, -0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x46, 0x69, 0x6a, 0x69, 0x61, 0x6e, 0x20, 0x64, -0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, -0x3b, 0x3b, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, -0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x3b, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, -0x6e, 0x20, 0x44, 0x61, 0x6c, 0x61, 0x73, 0x69, 0x3b, 0x3b, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x61, -0x6c, 0x61, 0x73, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x61, 0x6c, 0x61, -0x73, 0x69, 0x73, 0x3b, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x69, 0x61, 0x6e, 0x20, 0x43, 0x65, 0x64, 0x69, 0x3b, 0x3b, 0x47, -0x68, 0x61, 0x6e, 0x61, 0x69, 0x61, 0x6e, 0x20, 0x63, 0x65, 0x64, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x47, 0x68, 0x61, 0x6e, -0x61, 0x69, 0x61, 0x6e, 0x20, 0x63, 0x65, 0x64, 0x69, 0x73, 0x3b, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, -0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x20, 0x70, 0x6f, -0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x20, 0x70, 0x6f, 0x75, -0x6e, 0x64, 0x73, 0x3b, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x65, 0x73, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, -0x3b, 0x3b, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x65, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, -0x3b, 0x3b, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x65, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, -0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x48, 0x6f, -0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x48, 0x6f, -0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x49, 0x6e, 0x64, 0x69, -0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, -0x65, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x73, 0x3b, -0x4a, 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x4a, 0x61, 0x6d, -0x61, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x4a, 0x61, 0x6d, 0x61, -0x69, 0x63, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x20, -0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, -0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x3b, 0x3b, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, -0x6c, 0x69, 0x6e, 0x67, 0x73, 0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, -0x52, 0x61, 0x6e, 0x64, 0x3b, 0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, -0x72, 0x61, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, -0x6e, 0x20, 0x72, 0x61, 0x6e, 0x64, 0x3b, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, -0x61, 0x72, 0x3b, 0x3b, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, -0x3b, 0x3b, 0x3b, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, -0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x20, 0x41, 0x72, 0x69, 0x61, 0x72, 0x79, 0x3b, 0x3b, 0x4d, 0x61, 0x6c, -0x61, 0x67, 0x61, 0x73, 0x79, 0x20, 0x41, 0x72, 0x69, 0x61, 0x72, 0x79, 0x3b, 0x3b, 0x3b, 0x3b, 0x4d, 0x61, 0x6c, 0x61, -0x67, 0x61, 0x73, 0x79, 0x20, 0x41, 0x72, 0x69, 0x61, 0x72, 0x69, 0x65, 0x73, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, -0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x3b, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x61, 0x6e, 0x20, -0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x61, 0x6e, 0x20, 0x4b, -0x77, 0x61, 0x63, 0x68, 0x61, 0x73, 0x3b, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, -0x65, 0x65, 0x3b, 0x3b, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x3b, -0x3b, 0x3b, 0x3b, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x73, 0x3b, -0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x4e, 0x61, 0x6d, -0x69, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x61, 0x6d, 0x69, -0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, -0x6c, 0x61, 0x6e, 0x64, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, -0x6c, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x65, 0x77, 0x20, 0x5a, -0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x4e, 0x69, 0x67, 0x65, 0x72, -0x69, 0x61, 0x6e, 0x20, 0x4e, 0x61, 0x69, 0x72, 0x61, 0x3b, 0x3b, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, -0x6e, 0x61, 0x69, 0x72, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x6e, 0x61, -0x69, 0x72, 0x61, 0x73, 0x3b, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x69, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, -0x3b, 0x3b, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x69, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x3b, -0x3b, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x69, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x73, 0x3b, 0x50, 0x61, -0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x4b, 0x69, 0x6e, 0x61, -0x3b, 0x3b, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x6e, 0x20, -0x6b, 0x69, 0x6e, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, -0x69, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x6b, 0x69, 0x6e, 0x61, 0x3b, 0x50, 0x65, 0x73, 0x6f, 0x3b, 0x3b, 0x50, 0x68, 0x69, -0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x20, 0x70, 0x65, 0x73, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x50, 0x68, 0x69, 0x6c, -0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x20, 0x70, 0x65, 0x73, 0x6f, 0x73, 0x3b, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x6e, 0x20, -0x54, 0x61, 0x6c, 0x61, 0x3b, 0x3b, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x6e, 0x20, 0x74, 0x61, 0x6c, 0x61, 0x3b, 0x3b, 0x3b, -0x3b, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x6e, 0x20, 0x74, 0x61, 0x6c, 0x61, 0x3b, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, -0x6c, 0x6f, 0x69, 0x73, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, -0x6f, 0x69, 0x73, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, -0x6c, 0x6f, 0x69, 0x73, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x73, 0x3b, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, -0x65, 0x6f, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x3b, 0x3b, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, -0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x6c, 0x65, 0x6f, 0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x69, -0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x6c, 0x65, 0x6f, 0x6e, 0x65, 0x73, 0x3b, -0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x53, 0x69, -0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x69, -0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x53, 0x6f, 0x6c, 0x6f, -0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, -0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x6f, 0x6c, 0x6c, -0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, -0x73, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x53, 0x77, 0x61, 0x7a, 0x69, 0x20, 0x4c, 0x69, 0x6c, 0x61, -0x6e, 0x67, 0x65, 0x6e, 0x69, 0x3b, 0x3b, 0x53, 0x77, 0x61, 0x7a, 0x69, 0x20, 0x6c, 0x69, 0x6c, 0x61, 0x6e, 0x67, 0x65, -0x6e, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x77, 0x61, 0x7a, 0x69, 0x20, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x6e, 0x67, 0x65, -0x6e, 0x69, 0x3b, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, -0x67, 0x3b, 0x3b, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, -0x67, 0x3b, 0x3b, 0x3b, 0x3b, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, -0x69, 0x6e, 0x67, 0x73, 0x3b, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x6e, 0x20, 0x50, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x3b, -0x3b, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x6e, 0x20, 0x70, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x54, -0x6f, 0x6e, 0x67, 0x61, 0x6e, 0x20, 0x70, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x3b, 0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, -0x61, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67, 0x6f, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, -0x3b, 0x3b, 0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, 0x61, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67, -0x6f, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, 0x61, 0x64, -0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67, 0x6f, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, -0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x55, 0x67, -0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x3b, 0x3b, 0x55, 0x67, -0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x3b, 0x56, 0x61, 0x6e, 0x75, -0x61, 0x74, 0x75, 0x20, 0x56, 0x61, 0x74, 0x75, 0x3b, 0x3b, 0x56, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, -0x74, 0x75, 0x3b, 0x3b, 0x3b, 0x3b, 0x56, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x74, 0x75, 0x73, 0x3b, -0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x3b, 0x3b, 0x5a, 0x61, 0x6d, 0x62, -0x69, 0x61, 0x6e, 0x20, 0x6b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, -0x6e, 0x20, 0x6b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x73, 0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, -0x6e, 0x65, 0x73, 0x65, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, -0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x6f, 0x75, 0x74, -0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x3b, 0x65, 0x75, -0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x74, 0x3b, 0x64, 0x6f, -0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x3b, 0x3b, 0x64, 0x6f, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, -0x6e, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x6f, 0x6e, 0x73, 0x6b, 0x61, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x75, 0x72, 0x3b, -0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x61, 0x3b, -0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x61, 0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, -0x72, 0x20, 0x61, 0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x73, -0x20, 0x61, 0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, -0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, -0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x43, 0x46, -0x41, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x62, 0x75, 0x72, 0x75, -0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x61, -0x69, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x61, -0x69, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x3b, -0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x3b, 0x3b, 0x3b, -0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x3b, 0x64, -0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x64, 0x6f, 0x6c, 0x6c, -0x61, 0x72, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x6f, 0x6c, 0x6c, 0x61, -0x72, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, -0x6f, 0x6d, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, 0x6d, 0x6f, 0x72, -0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6f, 0x72, 0x69, -0x65, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x3b, -0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, -0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x3b, 0x66, 0x72, 0x61, -0x6e, 0x63, 0x20, 0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, -0x20, 0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, -0x73, 0x20, 0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x65, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, -0x43, 0x46, 0x50, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x50, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, -0x61, 0x6e, 0x63, 0x73, 0x20, 0x43, 0x46, 0x50, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x67, 0x75, 0x69, 0x6e, 0xe9, -0x65, 0x6e, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x67, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, -0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x67, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x6e, 0x73, 0x3b, 0x67, 0x6f, 0x75, -0x72, 0x64, 0x65, 0x20, 0x68, 0x61, 0xef, 0x74, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x67, 0x6f, 0x75, 0x72, 0x64, -0x65, 0x20, 0x68, 0x61, 0xef, 0x74, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x67, 0x6f, 0x75, 0x72, 0x64, -0x65, 0x73, 0x20, 0x68, 0x61, 0xef, 0x74, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x3b, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, -0x20, 0x6d, 0x61, 0x6c, 0x67, 0x61, 0x63, 0x68, 0x65, 0x3b, 0x3b, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, 0x20, 0x6d, 0x61, -0x6c, 0x67, 0x61, 0x63, 0x68, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, 0x73, 0x20, 0x6d, 0x61, -0x6c, 0x67, 0x61, 0x63, 0x68, 0x65, 0x73, 0x3b, 0x6f, 0x75, 0x67, 0x75, 0x69, 0x79, 0x61, 0x20, 0x6d, 0x61, 0x75, 0x72, -0x69, 0x74, 0x61, 0x6e, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x6f, 0x75, 0x67, 0x75, 0x69, 0x79, 0x61, 0x20, 0x6d, 0x61, 0x75, -0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x6f, 0x75, 0x67, 0x75, 0x69, 0x79, 0x61, 0x73, -0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x65, 0x6e, 0x73, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, -0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, -0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x72, 0x6f, 0x75, 0x70, -0x69, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x72, -0x68, 0x61, 0x6d, 0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, 0x61, 0x69, 0x6e, 0x3b, 0x3b, 0x64, 0x69, 0x72, 0x68, 0x61, 0x6d, -0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, 0x61, 0x69, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x69, 0x72, 0x68, 0x61, 0x6d, 0x73, -0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, 0x61, 0x69, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x72, 0x77, 0x61, -0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x69, -0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x69, 0x73, -0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x64, 0x65, 0x73, 0x20, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, -0x65, 0x73, 0x3b, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x64, 0x65, 0x73, 0x20, 0x53, 0x65, 0x79, 0x63, 0x68, -0x65, 0x6c, 0x6c, 0x65, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x73, 0x20, 0x64, 0x65, 0x73, -0x20, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x73, 0x75, -0x69, 0x73, 0x73, 0x65, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x3b, 0x3b, -0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x73, 0x3b, 0x6c, 0x69, 0x76, -0x72, 0x65, 0x20, 0x73, 0x79, 0x72, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x6c, 0x69, 0x76, 0x72, 0x65, 0x20, 0x73, -0x79, 0x72, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x6c, 0x69, 0x76, 0x72, 0x65, 0x73, 0x20, 0x73, 0x79, -0x72, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x74, 0x75, 0x6e, 0x69, 0x73, 0x69, -0x65, 0x6e, 0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x74, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x3b, 0x3b, -0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x73, 0x20, 0x74, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x73, 0x3b, 0x76, -0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x61, 0x6e, 0x3b, 0x3b, 0x76, 0x61, 0x74, 0x75, 0x20, -0x76, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x61, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x76, 0x61, 0x74, 0x75, 0x73, 0x20, 0x76, -0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x61, 0x6e, 0x73, 0x3b, 0x50, 0x75, 0x6e, 0x6e, 0x64, 0x20, 0x53, 0x61, 0x73, 0x61, -0x6e, 0x6e, 0x61, 0x63, 0x68, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, -0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x73, 0x3b, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10e3, 0x10da, 0x10d8, 0x20, -0x10da, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x45, 0x75, 0x72, -0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, -0x46, 0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x3b, 0x3b, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x46, -0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, -0x46, 0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x3b, 0x395, 0x3c5, 0x3c1, 0x3ce, 0x3b, 0x3b, 0x3b5, 0x3c5, 0x3c1, 0x3ce, 0x3b, 0x3b, -0x3b, 0x3b, 0x3b5, 0x3c5, 0x3c1, 0x3ce, 0x3b, 0x64, 0x61, 0x6e, 0x6e, 0x73, 0x6b, 0x69, 0x6e, 0x75, 0x74, 0x20, 0x6b, 0x6f, -0x72, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x3b, 0x64, 0x61, 0x6e, 0x73, 0x6b, 0x69, 0x6e, 0x75, 0x74, 0x20, 0x6b, 0x6f, 0x72, -0x75, 0x75, 0x6e, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x61, 0x6e, 0x73, 0x6b, 0x69, 0x6e, 0x75, 0x74, 0x20, 0x6b, 0x6f, -0x72, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0xaad, 0xabe, 0xab0, 0xaa4, 0xac0, 0xaaf, 0x20, 0xab0, 0xac2, 0xaaa, 0xac0, 0xaaf, 0xabe, 0x3b, -0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x61, 0x69, 0x72, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x4b, 0x75, -0x257, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x66, 0x61, 0x20, 0x6e, 0x61, 0x20, 0x41, 0x66, 0x69, 0x72, 0x6b, 0x61, 0x20, 0x54, -0x61, 0x20, 0x59, 0x61, 0x6d, 0x6d, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x5e9, 0x5f4, 0x5d7, 0x3b, 0x3b, 0x5e9, -0x5e7, 0x5dc, 0x5d9, 0x5dd, 0x20, 0x5d7, 0x5d3, 0x5e9, 0x5d9, 0x5dd, 0x3b, 0x5e9, 0x5e7, 0x5dc, 0x5d9, 0x5dd, 0x20, 0x5d7, 0x5d3, 0x5e9, -0x5d9, 0x5dd, 0x3b, 0x3b, 0x5e9, 0x5e7, 0x5dc, 0x5d9, 0x5dd, 0x20, 0x5d7, 0x5d3, 0x5e9, 0x5d9, 0x5dd, 0x3b, 0x5e9, 0x5e7, 0x5dc, 0x5d9, -0x5dd, 0x20, 0x5d7, 0x5d3, 0x5e9, 0x5d9, 0x5dd, 0x3b, 0x92d, 0x93e, 0x930, 0x924, 0x940, 0x92f, 0x20, 0x930, 0x942, 0x92a, 0x92f, 0x93e, -0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x4d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x69, 0x6e, 0x74, -0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xcd, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, -0x3b, 0x3b, 0xed, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0xed, -0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0x72, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x75, 0x72, 0x3b, 0x52, 0x75, 0x70, 0x69, -0x61, 0x68, 0x20, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, -0x75, 0x72, 0x6f, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, +0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, +0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, +0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, +0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, +0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, +0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, +0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, +0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, +0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x3b, 0x540, 0x561, 0x575, +0x56f, 0x561, 0x56f, 0x561, 0x576, 0x20, 0x564, 0x580, 0x561, 0x574, 0x3b, 0x3b, 0x540, 0x561, 0x575, 0x56f, 0x561, 0x56f, 0x561, 0x576, +0x20, 0x564, 0x580, 0x561, 0x574, 0x3b, 0x3b, 0x3b, 0x3b, 0x540, 0x561, 0x575, 0x56f, 0x561, 0x56f, 0x561, 0x576, 0x20, 0x564, 0x580, +0x561, 0x574, 0x3b, 0x41, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x74, 0x131, +0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x41, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x20, 0x6d, 0x61, 0x6e, +0x61, 0x74, 0x131, 0x3b, 0x43c, 0x430, 0x43d, 0x430, 0x442, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, +0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x9ac, 0x9be, 0x982, 0x9b2, 0x9be, 0x9a6, 0x9c7, 0x9b6, 0x9c0, 0x20, 0x99f, 0x9be, +0x995, 0x9be, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x9ad, 0x9be, 0x9b0, 0x9a4, 0x9c0, 0x9af, 0x9bc, 0x20, 0x9b0, 0x9c1, 0x9aa, +0x9bf, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xf51, 0xf44, 0xf74, 0xf63, 0xf0b, 0xf40, 0xfb2, 0xf58, 0x3b, 0x3b, 0x3b, 0x3b, +0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x411, 0x44a, 0x43b, 0x433, 0x430, 0x440, +0x441, 0x43a, 0x438, 0x20, 0x43b, 0x435, 0x432, 0x3b, 0x3b, 0x431, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x20, 0x43b, +0x435, 0x432, 0x3b, 0x3b, 0x3b, 0x3b, 0x431, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x20, 0x43b, 0x435, 0x432, 0x430, +0x3b, 0x1019, 0x103c, 0x1014, 0x103a, 0x1019, 0x102c, 0x20, 0x1000, 0x103b, 0x1015, 0x103a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x431, +0x435, 0x43b, 0x430, 0x440, 0x443, 0x441, 0x43a, 0x456, 0x20, 0x440, 0x443, 0x431, 0x435, 0x43b, 0x44c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, +0x3b, 0x3b, 0x179a, 0x17c0, 0x179b, 0x20, 0x1780, 0x1798, 0x17d2, 0x1796, 0x17bb, 0x1787, 0x17b6, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, +0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x73, 0x3b, +0x4eba, 0x6c11, 0x5e01, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x6e2f, 0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x6fb3, +0x95e8, 0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x65b0, 0x52a0, 0x5761, 0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, +0x6fb3, 0x9580, 0x5143, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x65b0, 0x81fa, 0x5e63, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, +0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x61, 0x20, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x3b, 0x68, 0x72, 0x76, 0x61, 0x74, +0x73, 0x6b, 0x61, 0x20, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x3b, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x65, 0x20, 0x6b, +0x75, 0x6e, 0x65, 0x3b, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x69, 0x68, 0x20, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x68, +0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x69, 0x68, 0x20, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, +0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x3b, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, 0x65, +0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x3b, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, +0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x3b, 0x6b, 0x6f, 0x6e, 0x76, +0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x69, 0x68, 0x20, 0x6d, 0x61, 0x72, 0x61, 0x6b, 0x61, 0x3b, 0x6b, 0x6f, +0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x69, 0x68, 0x20, 0x6d, 0x61, 0x72, 0x61, 0x6b, 0x61, 0x3b, +0x10d, 0x65, 0x73, 0x6b, 0xe1, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x6e, 0x61, 0x3b, 0x3b, 0x10d, 0x65, 0x73, 0x6b, 0xe1, 0x20, +0x6b, 0x6f, 0x72, 0x75, 0x6e, 0x61, 0x3b, 0x3b, 0x10d, 0x65, 0x73, 0x6b, 0xe9, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x6e, 0x79, +0x3b, 0x3b, 0x10d, 0x65, 0x73, 0x6b, 0xfd, 0x63, 0x68, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x6e, 0x3b, 0x44, 0x61, 0x6e, 0x73, +0x6b, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65, 0x3b, 0x3b, 0x44, 0x61, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65, +0x3b, 0x3b, 0x3b, 0x3b, 0x44, 0x61, 0x6e, 0x73, 0x6b, 0x65, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65, 0x72, 0x3b, 0x45, 0x75, +0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x41, 0x72, 0x75, +0x62, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x72, 0x69, 0x6e, 0x3b, 0x3b, 0x41, 0x72, 0x75, 0x62, 0x61, +0x61, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x72, 0x69, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x41, 0x72, 0x75, 0x62, 0x61, +0x61, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x72, 0x69, 0x6e, 0x3b, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, +0x64, 0x73, 0x2d, 0x41, 0x6e, 0x74, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x67, 0x75, 0x6c, 0x64, +0x65, 0x6e, 0x3b, 0x3b, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x2d, 0x41, 0x6e, 0x74, 0x69, 0x6c, +0x6c, 0x69, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x65, +0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x2d, 0x41, 0x6e, 0x74, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x61, 0x6e, 0x73, +0x65, 0x20, 0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x3b, 0x53, 0x75, 0x72, 0x69, 0x6e, 0x61, 0x61, 0x6d, 0x73, 0x65, 0x20, +0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x55, 0x53, 0x20, 0x44, 0x6f, 0x6c, 0x6c, +0x61, 0x72, 0x3b, 0x3b, 0x55, 0x53, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x55, 0x53, 0x20, +0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x45, 0x61, 0x73, 0x74, 0x20, 0x43, 0x61, 0x72, 0x69, 0x62, 0x62, 0x65, +0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x45, 0x61, 0x73, 0x74, 0x20, 0x43, 0x61, 0x72, 0x69, +0x62, 0x62, 0x65, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x61, 0x73, 0x74, +0x20, 0x43, 0x61, 0x72, 0x69, 0x62, 0x62, 0x65, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x41, +0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x41, 0x75, +0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x41, +0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x61, +0x68, 0x61, 0x6d, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x42, 0x61, 0x68, 0x61, 0x6d, +0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x69, +0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, +0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x64, +0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x64, +0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, +0x3b, 0x3b, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, +0x65, 0x6c, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, +0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x6e, 0x20, +0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x6e, 0x20, 0x64, +0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x6e, 0x20, 0x50, 0x75, 0x6c, +0x61, 0x3b, 0x3b, 0x42, 0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x6e, 0x20, 0x70, 0x75, 0x6c, 0x61, 0x3b, 0x3b, 0x3b, +0x3b, 0x42, 0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x6e, 0x20, 0x70, 0x75, 0x6c, 0x61, 0x73, 0x3b, 0x43, 0x46, 0x41, +0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x42, 0x45, 0x41, 0x43, 0x3b, 0x3b, 0x43, 0x46, 0x41, 0x20, 0x66, 0x72, 0x61, +0x6e, 0x63, 0x20, 0x42, 0x45, 0x41, 0x43, 0x3b, 0x3b, 0x3b, 0x3b, 0x43, 0x46, 0x41, 0x20, 0x66, 0x72, 0x61, 0x6e, 0x63, +0x73, 0x20, 0x42, 0x45, 0x41, 0x43, 0x3b, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, +0x61, 0x72, 0x3b, 0x3b, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, +0x3b, 0x3b, 0x3b, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, +0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, +0x72, 0x3b, 0x3b, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x6f, +0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, +0x64, 0x73, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x46, 0x69, 0x6a, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, +0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x46, 0x69, 0x6a, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, +0x3b, 0x3b, 0x3b, 0x46, 0x69, 0x6a, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x42, 0x72, +0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, +0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x70, 0x6f, +0x75, 0x6e, 0x64, 0x73, 0x3b, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x61, 0x6c, 0x61, 0x73, 0x69, 0x3b, +0x3b, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x61, 0x6c, 0x61, 0x73, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x47, +0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x61, 0x6c, 0x61, 0x73, 0x69, 0x73, 0x3b, 0x47, 0x68, 0x61, 0x6e, 0x61, +0x69, 0x61, 0x6e, 0x20, 0x43, 0x65, 0x64, 0x69, 0x3b, 0x3b, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x69, 0x61, 0x6e, 0x20, 0x63, +0x65, 0x64, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x69, 0x61, 0x6e, 0x20, 0x63, 0x65, 0x64, 0x69, +0x73, 0x3b, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x47, +0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x47, 0x69, +0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x3b, 0x47, 0x75, 0x79, 0x61, 0x6e, +0x61, 0x65, 0x73, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x65, +0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x65, +0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, +0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x20, 0x64, +0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x20, 0x64, +0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x3b, +0x3b, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x49, 0x6e, 0x64, +0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x73, 0x3b, 0x4a, 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x6e, 0x20, +0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x4a, 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, +0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x4a, 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, +0x61, 0x72, 0x73, 0x3b, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, +0x3b, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x3b, 0x3b, +0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x3b, 0x53, 0x6f, 0x75, +0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x52, 0x61, 0x6e, 0x64, 0x3b, 0x3b, 0x53, 0x6f, 0x75, +0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x72, 0x61, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, +0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x72, 0x61, 0x6e, 0x64, 0x3b, 0x4c, 0x69, +0x62, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x4c, 0x69, 0x62, 0x65, 0x72, +0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, +0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x20, +0x41, 0x72, 0x69, 0x61, 0x72, 0x79, 0x3b, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x20, 0x41, 0x72, 0x69, +0x61, 0x72, 0x79, 0x3b, 0x3b, 0x3b, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x20, 0x41, 0x72, 0x69, 0x61, +0x72, 0x69, 0x65, 0x73, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, +0x3b, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x3b, 0x3b, 0x3b, +0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x73, 0x3b, 0x4d, 0x61, +0x75, 0x72, 0x69, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x4d, 0x61, 0x75, 0x72, 0x69, +0x74, 0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, +0x69, 0x61, 0x6e, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x73, 0x3b, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x6e, 0x20, +0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, +0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x64, 0x6f, 0x6c, 0x6c, +0x61, 0x72, 0x73, 0x3b, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x44, 0x6f, 0x6c, 0x6c, +0x61, 0x72, 0x3b, 0x3b, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x6f, 0x6c, 0x6c, +0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x6f, +0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x4e, 0x61, 0x69, 0x72, 0x61, +0x3b, 0x3b, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x6e, 0x61, 0x69, 0x72, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, +0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x6e, 0x61, 0x69, 0x72, 0x61, 0x73, 0x3b, 0x50, 0x61, 0x6b, 0x69, +0x73, 0x74, 0x61, 0x6e, 0x69, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, +0x6e, 0x69, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, +0x69, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, 0x73, 0x3b, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, +0x75, 0x69, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x4b, 0x69, 0x6e, 0x61, 0x3b, 0x3b, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, +0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x6b, 0x69, 0x6e, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x50, +0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x6b, 0x69, 0x6e, +0x61, 0x3b, 0x50, 0x65, 0x73, 0x6f, 0x3b, 0x3b, 0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x20, 0x70, +0x65, 0x73, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x20, 0x70, 0x65, +0x73, 0x6f, 0x73, 0x3b, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x6e, 0x20, 0x54, 0x61, 0x6c, 0x61, 0x3b, 0x3b, 0x53, 0x61, 0x6d, +0x6f, 0x61, 0x6e, 0x20, 0x74, 0x61, 0x6c, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x6e, 0x20, 0x74, +0x61, 0x6c, 0x61, 0x3b, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x69, 0x73, 0x20, 0x52, 0x75, 0x70, 0x65, +0x65, 0x3b, 0x3b, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x69, 0x73, 0x20, 0x72, 0x75, 0x70, 0x65, 0x65, +0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x69, 0x73, 0x20, 0x72, 0x75, 0x70, 0x65, +0x65, 0x73, 0x3b, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x4c, 0x65, +0x6f, 0x6e, 0x65, 0x3b, 0x3b, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x61, 0x6e, 0x20, +0x6c, 0x65, 0x6f, 0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, 0x65, 0x6f, 0x6e, +0x65, 0x61, 0x6e, 0x20, 0x6c, 0x65, 0x6f, 0x6e, 0x65, 0x73, 0x3b, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, +0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x64, +0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x64, +0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, +0x64, 0x73, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, +0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x6f, 0x6c, +0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, +0x3b, 0x53, 0x77, 0x61, 0x7a, 0x69, 0x20, 0x4c, 0x69, 0x6c, 0x61, 0x6e, 0x67, 0x65, 0x6e, 0x69, 0x3b, 0x3b, 0x53, 0x77, +0x61, 0x7a, 0x69, 0x20, 0x6c, 0x69, 0x6c, 0x61, 0x6e, 0x67, 0x65, 0x6e, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x77, 0x61, +0x7a, 0x69, 0x20, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x6e, 0x67, 0x65, 0x6e, 0x69, 0x3b, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, +0x69, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, +0x69, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x3b, 0x3b, 0x54, 0x61, 0x6e, 0x7a, +0x61, 0x6e, 0x69, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x3b, 0x54, 0x6f, 0x6e, 0x67, +0x61, 0x6e, 0x20, 0x50, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x3b, 0x3b, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x6e, 0x20, 0x70, +0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x6e, 0x20, 0x70, 0x61, 0x2bb, +0x61, 0x6e, 0x67, 0x61, 0x3b, 0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, 0x61, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, +0x62, 0x61, 0x67, 0x6f, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, 0x3b, 0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, 0x61, +0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67, 0x6f, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x3b, +0x3b, 0x3b, 0x3b, 0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, 0x61, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, 0x62, 0x61, +0x67, 0x6f, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x3b, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x53, +0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, +0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x3b, 0x3b, 0x3b, 0x3b, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x69, +0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x3b, 0x56, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x20, 0x56, 0x61, 0x74, 0x75, 0x3b, +0x3b, 0x56, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x74, 0x75, 0x3b, 0x3b, 0x3b, 0x3b, 0x56, 0x61, 0x6e, +0x75, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x74, 0x75, 0x73, 0x3b, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x4b, +0x77, 0x61, 0x63, 0x68, 0x61, 0x3b, 0x3b, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x6b, 0x77, 0x61, 0x63, 0x68, +0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x6b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x73, +0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x50, 0x6f, 0x75, 0x6e, +0x64, 0x3b, 0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x70, 0x6f, +0x75, 0x6e, 0x64, 0x3b, 0x3b, 0x3b, 0x3b, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, +0x65, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, +0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x74, 0x3b, 0x64, 0x6f, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, +0x3b, 0x3b, 0x64, 0x6f, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x6f, 0x6e, +0x73, 0x6b, 0x61, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x75, 0x72, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, +0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x61, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x61, 0x6c, 0x67, +0xe9, 0x72, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x61, 0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, +0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x73, 0x20, 0x61, 0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, 0x6e, +0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x3b, +0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x3b, 0x3b, +0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, +0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x66, 0x72, +0x61, 0x6e, 0x63, 0x20, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, +0x6e, 0x63, 0x73, 0x20, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, +0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, +0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x43, +0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x3b, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x20, 0x63, 0x61, 0x6e, +0x61, 0x64, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, +0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, +0x65, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, 0x6d, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x3b, 0x3b, +0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, 0x6d, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, +0x61, 0x6e, 0x63, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, +0x20, 0x63, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, +0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x63, 0x6f, +0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, +0x74, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, +0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, +0x69, 0x65, 0x6e, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x50, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, +0x63, 0x20, 0x43, 0x46, 0x50, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x43, 0x46, 0x50, 0x3b, +0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x67, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x6e, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, +0x20, 0x67, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, 0x67, +0x75, 0x69, 0x6e, 0xe9, 0x65, 0x6e, 0x73, 0x3b, 0x67, 0x6f, 0x75, 0x72, 0x64, 0x65, 0x20, 0x68, 0x61, 0xef, 0x74, 0x69, +0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x67, 0x6f, 0x75, 0x72, 0x64, 0x65, 0x20, 0x68, 0x61, 0xef, 0x74, 0x69, 0x65, 0x6e, +0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x67, 0x6f, 0x75, 0x72, 0x64, 0x65, 0x73, 0x20, 0x68, 0x61, 0xef, 0x74, 0x69, 0x65, +0x6e, 0x6e, 0x65, 0x73, 0x3b, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, 0x20, 0x6d, 0x61, 0x6c, 0x67, 0x61, 0x63, 0x68, 0x65, +0x3b, 0x3b, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, 0x20, 0x6d, 0x61, 0x6c, 0x67, 0x61, 0x63, 0x68, 0x65, 0x3b, 0x3b, 0x3b, +0x3b, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, 0x73, 0x20, 0x6d, 0x61, 0x6c, 0x67, 0x61, 0x63, 0x68, 0x65, 0x73, 0x3b, 0x6f, +0x75, 0x67, 0x75, 0x69, 0x79, 0x61, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x65, 0x6e, 0x3b, 0x3b, +0x6f, 0x75, 0x67, 0x75, 0x69, 0x79, 0x61, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x65, 0x6e, 0x3b, +0x3b, 0x3b, 0x3b, 0x6f, 0x75, 0x67, 0x75, 0x69, 0x79, 0x61, 0x73, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, +0x69, 0x65, 0x6e, 0x73, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x69, 0x65, +0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x69, 0x65, +0x6e, 0x6e, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, +0x63, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x72, 0x68, 0x61, 0x6d, 0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, +0x61, 0x69, 0x6e, 0x3b, 0x3b, 0x64, 0x69, 0x72, 0x68, 0x61, 0x6d, 0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, 0x61, 0x69, 0x6e, +0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x69, 0x72, 0x68, 0x61, 0x6d, 0x73, 0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, 0x61, 0x69, 0x6e, +0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x66, 0x72, +0x61, 0x6e, 0x63, 0x20, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, +0x63, 0x73, 0x20, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x64, +0x65, 0x73, 0x20, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x3b, 0x3b, 0x72, 0x6f, 0x75, 0x70, 0x69, +0x65, 0x20, 0x64, 0x65, 0x73, 0x20, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, +0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x73, 0x20, 0x64, 0x65, 0x73, 0x20, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, +0x65, 0x73, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x3b, 0x3b, 0x66, 0x72, 0x61, +0x6e, 0x63, 0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x73, 0x20, +0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x73, 0x3b, 0x6c, 0x69, 0x76, 0x72, 0x65, 0x20, 0x73, 0x79, 0x72, 0x69, 0x65, 0x6e, +0x6e, 0x65, 0x3b, 0x3b, 0x6c, 0x69, 0x76, 0x72, 0x65, 0x20, 0x73, 0x79, 0x72, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x3b, 0x3b, +0x3b, 0x3b, 0x6c, 0x69, 0x76, 0x72, 0x65, 0x73, 0x20, 0x73, 0x79, 0x72, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x3b, 0x64, +0x69, 0x6e, 0x61, 0x72, 0x20, 0x74, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, +0x20, 0x74, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x73, 0x20, +0x74, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x73, 0x3b, 0x76, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x6e, 0x75, 0x61, +0x74, 0x75, 0x61, 0x6e, 0x3b, 0x3b, 0x76, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x61, 0x6e, +0x3b, 0x3b, 0x3b, 0x3b, 0x76, 0x61, 0x74, 0x75, 0x73, 0x20, 0x76, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x61, 0x6e, 0x73, +0x3b, 0x50, 0x75, 0x6e, 0x6e, 0x64, 0x20, 0x53, 0x61, 0x73, 0x61, 0x6e, 0x6e, 0x61, 0x63, 0x68, 0x3b, 0x3b, 0x3b, 0x3b, +0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x65, 0x75, 0x72, +0x6f, 0x73, 0x3b, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10e3, 0x10da, 0x10d8, 0x20, 0x10da, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, +0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, +0x3b, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x3b, 0x3b, +0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x3b, 0x3b, 0x3b, +0x3b, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x3b, 0x395, +0x3c5, 0x3c1, 0x3ce, 0x3b, 0x3b, 0x3b5, 0x3c5, 0x3c1, 0x3ce, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b5, 0x3c5, 0x3c1, 0x3ce, 0x3b, 0x64, 0x61, +0x6e, 0x6e, 0x73, 0x6b, 0x69, 0x6e, 0x75, 0x74, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x3b, 0x64, 0x61, +0x6e, 0x73, 0x6b, 0x69, 0x6e, 0x75, 0x74, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x3b, 0x3b, 0x3b, 0x64, +0x61, 0x6e, 0x73, 0x6b, 0x69, 0x6e, 0x75, 0x74, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0xaad, 0xabe, 0xab0, +0xaa4, 0xac0, 0xaaf, 0x20, 0xab0, 0xac2, 0xaaa, 0xac0, 0xaaf, 0xabe, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x4e, 0x61, 0x69, +0x72, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x4b, 0x75, 0x257, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x66, 0x61, 0x20, +0x6e, 0x61, 0x20, 0x41, 0x66, 0x69, 0x72, 0x6b, 0x61, 0x20, 0x54, 0x61, 0x20, 0x59, 0x61, 0x6d, 0x6d, 0x61, 0x3b, 0x3b, +0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x5e9, 0x5f4, 0x5d7, 0x3b, 0x3b, 0x5e9, 0x5e7, 0x5dc, 0x5d9, 0x5dd, 0x20, 0x5d7, 0x5d3, 0x5e9, 0x5d9, +0x5dd, 0x3b, 0x5e9, 0x5e7, 0x5dc, 0x5d9, 0x5dd, 0x20, 0x5d7, 0x5d3, 0x5e9, 0x5d9, 0x5dd, 0x3b, 0x3b, 0x5e9, 0x5e7, 0x5dc, 0x5d9, 0x5dd, +0x20, 0x5d7, 0x5d3, 0x5e9, 0x5d9, 0x5dd, 0x3b, 0x5e9, 0x5e7, 0x5dc, 0x5d9, 0x5dd, 0x20, 0x5d7, 0x5d3, 0x5e9, 0x5d9, 0x5dd, 0x3b, 0x92d, +0x93e, 0x930, 0x924, 0x940, 0x92f, 0x20, 0x930, 0x942, 0x92a, 0x92f, 0x93e, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x4d, 0x61, +0x67, 0x79, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x69, 0x6e, 0x74, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xcd, 0x73, +0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x3b, 0x3b, 0xed, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, +0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0xed, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0x72, 0x20, +0x6b, 0x72, 0xf3, 0x6e, 0x75, 0x72, 0x3b, 0x52, 0x75, 0x70, 0x69, 0x61, 0x68, 0x20, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, +0x73, 0x69, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x75, 0x72, 0x6f, 0x73, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x53, 0x76, 0x69, 0x7a, 0x7a, 0x65, 0x72, 0x6f, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x73, 0x76, 0x69, 0x7a, 0x7a, 0x65, 0x72, 0x6f, 0x3b, 0x3b, 0x3b, 0x3b, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x69, 0x20, 0x73, 0x76, 0x69, 0x7a, 0x7a, 0x65, 0x72, 0x69, 0x3b, 0x65e5, 0x672c, 0x5186, 0x3b, 0x3b, @@ -4979,32 +4982,32 @@ static const ushort currency_display_name_data[] = { 0x43d, 0x430, 0x440, 0x3b, 0x3b, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x20, 0x434, 0x438, 0x43d, 0x430, 0x440, 0x3b, 0x3b, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x430, 0x20, 0x434, 0x438, 0x43d, 0x430, 0x440, 0x430, 0x3b, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x445, 0x20, 0x434, 0x438, 0x43d, 0x430, 0x440, 0x430, 0x3b, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x445, 0x20, 0x434, 0x438, 0x43d, 0x430, -0x440, 0x430, 0x3b, 0x41a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d, 0x430, 0x20, 0x41c, 0x430, 0x440, -0x43a, 0x430, 0x3b, 0x3b, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x2d, 0x445, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, -0x432, 0x430, 0x447, 0x43a, 0x430, 0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d, 0x430, 0x20, -0x43c, 0x430, 0x440, 0x43a, 0x430, 0x3b, 0x3b, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x2d, 0x445, 0x435, 0x440, 0x446, -0x435, 0x433, 0x43e, 0x432, 0x430, 0x447, 0x43a, 0x435, 0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, -0x43d, 0x435, 0x20, 0x43c, 0x430, 0x440, 0x43a, 0x65, 0x3b, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x2d, 0x445, 0x435, -0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x430, 0x447, 0x43a, 0x438, 0x445, 0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x430, -0x431, 0x438, 0x43b, 0x43d, 0x438, 0x445, 0x20, 0x43c, 0x430, 0x440, 0x430, 0x43a, 0x430, 0x3b, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, -0x43a, 0x43e, 0x2d, 0x445, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x430, 0x447, 0x43a, 0x438, 0x445, 0x20, 0x43a, 0x43e, 0x43d, -0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d, 0x438, 0x445, 0x20, 0x43c, 0x430, 0x440, 0x430, 0x43a, 0x430, 0x3b, 0x415, -0x432, 0x440, 0x43e, 0x3b, 0x3b, 0x435, 0x432, 0x440, 0x43e, 0x3b, 0x3b, 0x435, 0x432, 0x440, 0x430, 0x3b, 0x435, 0x432, 0x440, 0x430, -0x3b, 0x435, 0x432, 0x440, 0x430, 0x3b, 0x4b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, +0x440, 0x430, 0x3b, 0x4b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x72, +0x6b, 0x61, 0x3b, 0x3b, 0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x6f, 0x2d, 0x68, 0x65, 0x72, 0x63, 0x65, 0x67, 0x6f, +0x76, 0x61, 0x10d, 0x6b, 0x61, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x3b, 0x3b, 0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x6f, 0x2d, 0x68, 0x65, 0x72, 0x63, -0x65, 0x67, 0x6f, 0x76, 0x61, 0x10d, 0x6b, 0x61, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, -0x6e, 0x61, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x3b, 0x3b, 0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x6f, 0x2d, 0x68, -0x65, 0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x61, 0x10d, 0x6b, 0x65, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, -0x62, 0x69, 0x6c, 0x6e, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x3b, 0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x6f, -0x2d, 0x68, 0x65, 0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x61, 0x10d, 0x6b, 0x69, 0x68, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, -0x72, 0x74, 0x61, 0x62, 0x69, 0x6c, 0x6e, 0x69, 0x68, 0x20, 0x6d, 0x61, 0x72, 0x61, 0x6b, 0x61, 0x3b, 0x62, 0x6f, 0x73, -0x61, 0x6e, 0x73, 0x6b, 0x6f, 0x2d, 0x68, 0x65, 0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x61, 0x10d, 0x6b, 0x69, 0x68, 0x20, -0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x69, 0x68, 0x20, 0x6d, 0x61, 0x72, 0x61, 0x6b, -0x61, 0x3b, 0x45, 0x76, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x76, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x76, 0x72, 0x61, 0x3b, 0x65, -0x76, 0x72, 0x61, 0x3b, 0x65, 0x76, 0x72, 0x61, 0x3b, 0x53, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x20, 0x64, 0x69, 0x6e, 0x61, -0x72, 0x3b, 0x3b, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x3b, 0x3b, 0x73, 0x72, 0x70, -0x73, 0x6b, 0x61, 0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x61, 0x3b, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x68, 0x20, 0x64, -0x69, 0x6e, 0x61, 0x72, 0x61, 0x3b, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x68, 0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x61, +0x65, 0x67, 0x6f, 0x76, 0x61, 0x10d, 0x6b, 0x65, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, +0x6e, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x3b, 0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x6f, 0x2d, 0x68, 0x65, +0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x61, 0x10d, 0x6b, 0x69, 0x68, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x61, +0x62, 0x69, 0x6c, 0x6e, 0x69, 0x68, 0x20, 0x6d, 0x61, 0x72, 0x61, 0x6b, 0x61, 0x3b, 0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73, +0x6b, 0x6f, 0x2d, 0x68, 0x65, 0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x61, 0x10d, 0x6b, 0x69, 0x68, 0x20, 0x6b, 0x6f, 0x6e, +0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x69, 0x68, 0x20, 0x6d, 0x61, 0x72, 0x61, 0x6b, 0x61, 0x3b, 0x45, +0x76, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x76, 0x72, 0x6f, 0x3b, 0x3b, 0x65, 0x76, 0x72, 0x61, 0x3b, 0x65, 0x76, 0x72, 0x61, +0x3b, 0x65, 0x76, 0x72, 0x61, 0x3b, 0x53, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x3b, 0x3b, +0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x3b, 0x3b, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x61, +0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x61, 0x3b, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x68, 0x20, 0x64, 0x69, 0x6e, 0x61, +0x72, 0x61, 0x3b, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x68, 0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x61, 0x3b, 0x41a, 0x43e, +0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d, 0x430, 0x20, 0x41c, 0x430, 0x440, 0x43a, 0x430, 0x3b, 0x3b, 0x431, +0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x2d, 0x445, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x430, 0x447, 0x43a, 0x430, +0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d, 0x430, 0x20, 0x43c, 0x430, 0x440, 0x43a, 0x430, +0x3b, 0x3b, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x2d, 0x445, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x430, +0x447, 0x43a, 0x435, 0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d, 0x435, 0x20, 0x43c, 0x430, +0x440, 0x43a, 0x65, 0x3b, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x2d, 0x445, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, +0x432, 0x430, 0x447, 0x43a, 0x438, 0x445, 0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x430, 0x431, 0x438, 0x43b, 0x43d, 0x438, +0x445, 0x20, 0x43c, 0x430, 0x440, 0x430, 0x43a, 0x430, 0x3b, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x2d, 0x445, 0x435, +0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x430, 0x447, 0x43a, 0x438, 0x445, 0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, +0x431, 0x438, 0x43b, 0x43d, 0x438, 0x445, 0x20, 0x43c, 0x430, 0x440, 0x430, 0x43a, 0x430, 0x3b, 0x415, 0x432, 0x440, 0x43e, 0x3b, 0x3b, +0x435, 0x432, 0x440, 0x43e, 0x3b, 0x3b, 0x435, 0x432, 0x440, 0x430, 0x3b, 0x435, 0x432, 0x440, 0x430, 0x3b, 0x435, 0x432, 0x440, 0x430, 0x3b, 0x41b, 0x430, 0x440, 0x3b, 0x3b, 0x43b, 0x430, 0x440, 0x3b, 0x3b, 0x3b, 0x3b, 0x43b, 0x430, 0x440, 0x44b, 0x3b, 0x421, 0x43e, 0x43c, 0x3b, 0x3b, 0x441, 0x43e, 0x43c, 0x3b, 0x3b, 0x3b, 0x3b, 0x441, 0x43e, 0x43c, 0x44b, 0x3b, 0x44, 0x6f, 0x72, 0x61, 0x20, 0x72, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x6b, 0x61, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xdbd, 0xd82, 0xd9a, @@ -5211,254 +5214,255 @@ static const ushort endonyms_data[] = { 0x69, 0x79, 0x61, 0x61, 0x51, 0x61, 0x66, 0x61, 0x72, 0x4f, 0x74, 0x6f, 0x62, 0x62, 0x69, 0x61, 0x59, 0x61, 0x62, 0x75, 0x75, 0x74, 0x69, 0x45, 0x72, 0x65, 0x74, 0x72, 0x69, 0x61, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x61, 0x6e, 0x73, 0x53, 0x75, 0x69, 0x64, 0x2d, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0xeb, 0x73, 0x68, 0x71, -0x69, 0x70, 0x53, 0x68, 0x71, 0x69, 0x70, 0xeb, 0x72, 0x69, 0x61, 0x4d, 0x61, 0x71, 0x65, 0x64, 0x6f, 0x6e, 0x69, 0x12a0, -0x121b, 0x122d, 0x129b, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, 0x629, 0x645, 0x635, 0x631, 0x627, 0x644, -0x62c, 0x632, 0x627, 0x626, 0x631, 0x627, 0x644, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x62a, 0x634, 0x627, 0x62f, 0x62c, 0x632, 0x631, 0x20, -0x627, 0x644, 0x642, 0x645, 0x631, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x627, 0x627, 0x644, -0x639, 0x631, 0x627, 0x642, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x627, 0x644, 0x623, 0x631, 0x62f, 0x646, 0x627, 0x644, 0x643, -0x648, 0x64a, 0x62a, 0x644, 0x628, 0x646, 0x627, 0x646, 0x644, 0x64a, 0x628, 0x64a, 0x627, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, -0x64a, 0x627, 0x627, 0x644, 0x645, 0x63a, 0x631, 0x628, 0x639, 0x64f, 0x645, 0x627, 0x646, 0x641, 0x644, 0x633, 0x637, 0x64a, 0x646, 0x642, -0x637, 0x631, 0x627, 0x644, 0x645, 0x645, 0x644, 0x643, 0x629, 0x20, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, -0x633, 0x639, 0x648, 0x62f, 0x64a, 0x629, 0x627, 0x644, 0x635, 0x648, 0x645, 0x627, 0x644, 0x627, 0x644, 0x633, 0x648, 0x62f, 0x627, 0x646, -0x633, 0x648, 0x631, 0x64a, 0x627, 0x62a, 0x648, 0x646, 0x633, 0x627, 0x644, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x20, 0x627, 0x644, -0x639, 0x631, 0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, 0x645, 0x62a, 0x62d, 0x62f, 0x629, 0x627, 0x644, 0x635, 0x62d, 0x631, 0x627, 0x621, -0x20, 0x627, 0x644, 0x63a, 0x631, 0x628, 0x64a, 0x629, 0x627, 0x644, 0x64a, 0x645, 0x646, 0x570, 0x561, 0x575, 0x565, 0x580, 0x565, 0x576, -0x540, 0x561, 0x575, 0x561, 0x57d, 0x57f, 0x561, 0x576, 0x985, 0x9b8, 0x9ae, 0x9c0, 0x9af, 0x9bc, 0x9be, 0x9ad, 0x9be, 0x9f0, 0x9a4, 0x61, -0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x63, 0x61, 0x41, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, -0x6e, 0x410, 0x437, 0x4d9, 0x440, 0x431, 0x430, 0x458, 0x4b9, 0x430, 0x43d, 0x65, 0x75, 0x73, 0x6b, 0x61, 0x72, 0x61, 0x45, 0x73, -0x70, 0x61, 0x69, 0x6e, 0x69, 0x61, 0x9ac, 0x9be, 0x982, 0x9b2, 0x9be, 0x9ac, 0x9be, 0x982, 0x9b2, 0x9be, 0x9a6, 0x9c7, 0x9b6, 0x9ad, -0x9be, 0x9b0, 0x9a4, 0xf62, 0xfab, 0xf7c, 0xf44, 0xf0b, 0xf41, 0xf60, 0xf56, 0xfb2, 0xf74, 0xf42, 0x62, 0x72, 0x65, 0x7a, 0x68, 0x6f, -0x6e, 0x65, 0x67, 0x46, 0x72, 0x61, 0xf1, 0x73, 0x431, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x411, 0x44a, 0x43b, -0x433, 0x430, 0x440, 0x438, 0x44f, 0x1017, 0x1019, 0x102c, 0x1019, 0x103c, 0x1014, 0x103a, 0x1019, 0x102c, 0x431, 0x435, 0x43b, 0x430, 0x440, 0x443, -0x441, 0x43a, 0x430, 0x44f, 0x411, 0x435, 0x43b, 0x430, 0x440, 0x443, 0x441, 0x44c, 0x1781, 0x17d2, 0x1798, 0x17c2, 0x179a, 0x1780, 0x1798, 0x17d2, -0x1796, 0x17bb, 0x1787, 0x17b6, 0x63, 0x61, 0x74, 0x61, 0x6c, 0xe0, 0x45, 0x73, 0x70, 0x61, 0x6e, 0x79, 0x61, 0x41, 0x6e, 0x64, -0x6f, 0x72, 0x72, 0x61, 0x7b80, 0x4f53, 0x4e2d, 0x6587, 0x4e2d, 0x56fd, 0x4e2d, 0x56fd, 0x9999, 0x6e2f, 0x7279, 0x522b, 0x884c, 0x653f, 0x533a, 0x4e2d, -0x56fd, 0x6fb3, 0x95e8, 0x7279, 0x522b, 0x884c, 0x653f, 0x533a, 0x65b0, 0x52a0, 0x5761, 0x7e41, 0x9ad4, 0x4e2d, 0x6587, 0x4e2d, 0x83ef, 0x4eba, 0x6c11, 0x5171, -0x548c, 0x570b, 0x9999, 0x6e2f, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x4e2d, 0x83ef, 0x4eba, 0x6c11, 0x5171, 0x548c, 0x570b, 0x6fb3, 0x9580, 0x7279, 0x5225, -0x884c, 0x653f, 0x5340, 0x53f0, 0x7063, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x69, 0x48, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, -0x61, 0x42, 0x6f, 0x73, 0x6e, 0x61, 0x20, 0x69, 0x20, 0x48, 0x65, 0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x69, 0x6e, 0x61, -0x10d, 0x65, 0x161, 0x74, 0x69, 0x6e, 0x61, 0x10c, 0x65, 0x73, 0x6b, 0xe1, 0x20, 0x72, 0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, -0x6b, 0x61, 0x64, 0x61, 0x6e, 0x73, 0x6b, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, -0x61, 0x6e, 0x64, 0x73, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x41, 0x72, 0x75, 0x62, 0x61, 0x56, 0x6c, -0x61, 0x61, 0x6d, 0x73, 0x42, 0x65, 0x6c, 0x67, 0x69, 0xeb, 0x43, 0x75, 0x72, 0x61, 0xe7, 0x61, 0x6f, 0x53, 0x75, 0x72, -0x69, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x69, 0x6e, 0x74, 0x2d, 0x4d, 0x61, 0x61, 0x72, 0x74, 0x65, 0x6e, 0x55, 0x2e, 0x53, -0x2e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, -0x65, 0x73, 0xd801, 0xdc00, 0xd801, 0xdc4d, 0xd801, 0xdc4a, 0xd801, 0xdc2e, 0xd801, 0xdc47, 0xd801, 0xdc0f, 0xd801, 0xdc2d, 0xd801, 0xdc4c, 0xd801, 0xdc34, -0xd801, 0xdc3b, 0xd801, 0xdc32, 0xd801, 0xdc3c, 0x20, 0xd801, 0xdc1d, 0xd801, 0xdc3b, 0xd801, 0xdc29, 0xd801, 0xdc3b, 0xd801, 0xdc45, 0x45, 0x6e, 0x67, -0x6c, 0x69, 0x73, 0x68, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x41, 0x6e, -0x74, 0x69, 0x67, 0x75, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x42, 0x61, 0x72, 0x62, 0x75, 0x64, 0x61, 0x41, 0x75, 0x73, -0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x41, 0x75, 0x73, 0x74, 0x72, -0x61, 0x6c, 0x69, 0x61, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x61, 0x73, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x6f, 0x73, 0x42, -0x65, 0x6c, 0x67, 0x69, 0x75, 0x6d, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x42, -0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x6f, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x61, 0x64, -0x69, 0x61, 0x6e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x43, 0x61, 0x79, -0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x46, -0x69, 0x6a, 0x69, 0x47, 0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x47, 0x68, 0x61, -0x6e, 0x61, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x47, 0x75, -0x61, 0x6d, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x20, 0x53, 0x41, -0x52, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x49, 0x72, 0x65, 0x6c, 0x61, 0x6e, 0x64, 0x4a, -0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x4b, 0x69, 0x72, 0x69, 0x62, 0x61, 0x74, 0x69, 0x4c, -0x65, 0x73, 0x6f, 0x74, 0x68, 0x6f, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x4d, 0x61, 0x64, 0x61, 0x67, 0x61, 0x73, -0x63, 0x61, 0x72, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x4d, 0x61, 0x6c, 0x74, 0x61, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, -0x6c, 0x6c, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x4d, -0x69, 0x63, 0x72, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x4e, 0x65, 0x77, 0x20, -0x5a, 0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x65, -0x72, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x61, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x50, 0x61, -0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, -0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x73, 0x50, 0x75, -0x65, 0x72, 0x74, 0x6f, 0x20, 0x52, 0x69, 0x63, 0x6f, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x20, 0x4b, 0x69, 0x74, 0x74, 0x73, -0x20, 0x61, 0x6e, 0x64, 0x20, 0x4e, 0x65, 0x76, 0x69, 0x73, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x20, 0x4c, 0x75, 0x63, 0x69, -0x61, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x20, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, -0x68, 0x65, 0x20, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x53, 0x65, -0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, -0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, -0x61, 0x6e, 0x64, 0x73, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x53, 0x77, 0x61, 0x7a, -0x69, 0x6c, 0x61, 0x6e, 0x64, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0x72, -0x69, 0x6e, 0x69, 0x64, 0x61, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67, 0x6f, 0x54, 0x75, 0x72, -0x6b, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x43, 0x61, 0x69, 0x63, 0x6f, 0x73, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, -0x73, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, -0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x4b, 0x69, 0x6e, 0x67, 0x64, 0x6f, 0x6d, 0x55, 0x2e, 0x53, 0x2e, -0x20, 0x4f, 0x75, 0x74, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x56, 0x61, 0x6e, -0x75, 0x61, 0x74, 0x75, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x56, 0x69, 0x72, 0x67, 0x69, 0x6e, 0x20, 0x49, -0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x56, 0x69, 0x72, 0x67, 0x69, 0x6e, 0x20, 0x49, 0x73, -0x6c, 0x61, 0x6e, 0x64, 0x73, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x5a, 0x69, 0x6d, 0x62, 0x61, 0x62, 0x77, 0x65, 0x49, -0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x61, 0x6e, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x53, 0x6f, 0x75, 0x74, -0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x65, 0x73, 0x74, 0x69, 0x45, 0x65, 0x73, 0x74, 0x69, 0x66, 0xf8, 0x72, -0x6f, 0x79, 0x73, 0x6b, 0x74, 0x46, 0xf8, 0x72, 0x6f, 0x79, 0x61, 0x72, 0x73, 0x75, 0x6f, 0x6d, 0x69, 0x53, 0x75, 0x6f, -0x6d, 0x69, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x6c, 0x67, 0xe9, -0x72, 0x69, 0x65, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x71, 0x75, 0x65, 0x42, 0xe9, 0x6e, 0x69, 0x6e, 0x42, 0x75, 0x72, 0x6b, -0x69, 0x6e, 0x61, 0x20, 0x46, 0x61, 0x73, 0x6f, 0x42, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x69, 0x43, 0x61, 0x6d, 0x65, 0x72, -0x6f, 0x75, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e, -0x52, 0xe9, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x71, 0x75, 0x65, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x66, 0x72, 0x69, -0x63, 0x61, 0x69, 0x6e, 0x65, 0x54, 0x63, 0x68, 0x61, 0x64, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x65, 0x73, 0x52, 0xe9, 0x70, -0x75, 0x62, 0x6c, 0x69, 0x71, 0x75, 0x65, 0x20, 0x64, 0xe9, 0x6d, 0x6f, 0x63, 0x72, 0x61, 0x74, 0x69, 0x71, 0x75, 0x65, -0x20, 0x64, 0x75, 0x20, 0x43, 0x6f, 0x6e, 0x67, 0x6f, 0x43, 0x6f, 0x6e, 0x67, 0x6f, 0x2d, 0x42, 0x72, 0x61, 0x7a, 0x7a, -0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x43, 0xf4, 0x74, 0x65, 0x20, 0x64, 0x2019, 0x49, 0x76, 0x6f, 0x69, 0x72, 0x65, 0x44, -0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x20, 0xe9, 0x71, 0x75, 0x61, 0x74, 0x6f, -0x72, 0x69, 0x61, 0x6c, 0x65, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, -0x65, 0x50, 0x6f, 0x6c, 0x79, 0x6e, 0xe9, 0x73, 0x69, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x65, -0x47, 0x61, 0x62, 0x6f, 0x6e, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f, 0x75, 0x70, 0x65, 0x47, 0x75, 0x69, 0x6e, 0xe9, -0x65, 0x48, 0x61, 0xef, 0x74, 0x69, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f, 0x75, 0x72, 0x67, 0x4d, 0x61, 0x6c, 0x69, -0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x65, -0x4d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, -0x4d, 0x61, 0x72, 0x6f, 0x63, 0x4e, 0x6f, 0x75, 0x76, 0x65, 0x6c, 0x6c, 0x65, 0x2d, 0x43, 0x61, 0x6c, 0xe9, 0x64, 0x6f, -0x6e, 0x69, 0x65, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x52, 0xe9, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x52, 0x77, 0x61, 0x6e, 0x64, -0x61, 0x53, 0xe9, 0x6e, 0xe9, 0x67, 0x61, 0x6c, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x20, 0x73, 0x75, 0x69, -0x73, 0x73, 0x65, 0x53, 0x75, 0x69, 0x73, 0x73, 0x65, 0x53, 0x79, 0x72, 0x69, 0x65, 0x54, 0x6f, 0x67, 0x6f, 0x54, 0x75, -0x6e, 0x69, 0x73, 0x69, 0x65, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x2d, 0x42, 0x61, 0x72, 0x74, 0x68, 0xe9, 0x6c, 0xe9, 0x6d, -0x79, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x2d, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x20, 0x5b, 0x70, 0x61, 0x72, 0x74, 0x69, -0x65, 0x20, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x65, 0x5d, 0x47, 0xe0, 0x69, 0x64, 0x68, 0x6c, 0x69, 0x67, -0x41, 0x6e, 0x20, 0x52, 0xec, 0x6f, 0x67, 0x68, 0x61, 0x63, 0x68, 0x64, 0x20, 0x41, 0x6f, 0x6e, 0x61, 0x69, 0x63, 0x68, -0x74, 0x65, 0x67, 0x61, 0x6c, 0x65, 0x67, 0x6f, 0x45, 0x73, 0x70, 0x61, 0xf1, 0x61, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10e3, 0x10da, -0x10d8, 0x10e1, 0x10d0, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10d5, 0x10d4, 0x10da, 0x10dd, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x44, 0x65, -0x75, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61, 0x6e, 0x64, 0xd6, 0x73, 0x74, 0x65, 0x72, 0x72, 0x65, 0x69, 0x63, 0x68, 0x69, -0x73, 0x63, 0x68, 0x65, 0x73, 0x20, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0xd6, 0x73, 0x74, 0x65, 0x72, 0x72, 0x65, -0x69, 0x63, 0x68, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x65, 0x6e, 0x4c, 0x69, 0x65, 0x63, 0x68, 0x74, 0x65, 0x6e, 0x73, 0x74, -0x65, 0x69, 0x6e, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x75, 0x72, 0x67, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, -0x72, 0x20, 0x48, 0x6f, 0x63, 0x68, 0x64, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, -0x395, 0x3bb, 0x3bb, 0x3b7, 0x3bd, 0x3b9, 0x3ba, 0x3ac, 0x395, 0x3bb, 0x3bb, 0x3ac, 0x3b4, 0x3b1, 0x39a, 0x3cd, 0x3c0, 0x3c1, 0x3bf, 0x3c2, -0x6b, 0x61, 0x6c, 0x61, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x75, 0x74, 0x4b, 0x61, 0x6c, 0x61, 0x61, 0x6c, 0x6c, 0x69, 0x74, -0x20, 0x4e, 0x75, 0x6e, 0x61, 0x61, 0x74, 0xa97, 0xac1, 0xa9c, 0xab0, 0xabe, 0xaa4, 0xac0, 0xaad, 0xabe, 0xab0, 0xaa4, 0x48, 0x61, -0x75, 0x73, 0x61, 0x4e, 0x61, 0x6a, 0x65, 0x72, 0x69, 0x79, 0x61, 0x47, 0x61, 0x6e, 0x61, 0x4e, 0x69, 0x6a, 0x61, 0x72, -0x5e2, 0x5d1, 0x5e8, 0x5d9, 0x5ea, 0x5d9, 0x5e9, 0x5e8, 0x5d0, 0x5dc, 0x939, 0x93f, 0x928, 0x94d, 0x926, 0x940, 0x92d, 0x93e, 0x930, 0x924, -0x6d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x4d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x6f, 0x72, 0x73, 0x7a, 0xe1, 0x67, 0xed, 0x73, -0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0xcd, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x42, 0x61, 0x68, 0x61, 0x73, 0x61, 0x20, 0x49, -0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x69, 0x6e, 0x74, -0x65, 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x75, 0x61, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x61, 0x47, 0x61, 0x65, 0x69, 0x6c, -0x67, 0x65, 0xc9, 0x69, 0x72, 0x65, 0x69, 0x74, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x6f, 0x49, 0x74, 0x61, 0x6c, 0x69, 0x61, -0x53, 0x61, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x6e, 0x6f, 0x53, 0x76, 0x69, 0x7a, 0x7a, 0x65, 0x72, 0x61, 0x65e5, 0x672c, -0x8a9e, 0x65e5, 0x672c, 0xc95, 0xca8, 0xccd, 0xca8, 0xca1, 0xcad, 0xcbe, 0xcb0, 0xca4, 0x6a9, 0x672, 0x634, 0x64f, 0x631, 0x6c1, 0x650, 0x646, -0x65b, 0x62f, 0x648, 0x633, 0x62a, 0x627, 0x646, 0x49b, 0x430, 0x437, 0x430, 0x49b, 0x20, 0x442, 0x456, 0x43b, 0x456, 0x49a, 0x430, 0x437, -0x430, 0x49b, 0x441, 0x442, 0x430, 0x43d, 0x4b, 0x69, 0x6e, 0x79, 0x61, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x41a, 0x44b, 0x440, -0x433, 0x44b, 0x437, 0x41a, 0x44b, 0x440, 0x433, 0x44b, 0x437, 0x441, 0x442, 0x430, 0x43d, 0xd55c, 0xad6d, 0xc5b4, 0xb300, 0xd55c, 0xbbfc, 0xad6d, -0xc870, 0xc120, 0x20, 0xbbfc, 0xc8fc, 0xc8fc, 0xc758, 0x20, 0xc778, 0xbbfc, 0x20, 0xacf5, 0xd654, 0xad6d, 0x49, 0x6b, 0x69, 0x72, 0x75, 0x6e, -0x64, 0x69, 0x55, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x69, 0xea5, 0xeb2, 0xea7, 0xeaa, 0x2e, 0xe9b, 0x2e, 0xe9b, 0x20, 0xea5, -0xeb2, 0xea7, 0x6c, 0x61, 0x74, 0x76, 0x69, 0x65, 0x161, 0x75, 0x4c, 0x61, 0x74, 0x76, 0x69, 0x6a, 0x61, 0x6c, 0x69, 0x6e, -0x67, 0xe1, 0x6c, 0x61, 0x52, 0x65, 0x70, 0x69, 0x62, 0x69, 0x6b, 0x69, 0x20, 0x64, 0x65, 0x6d, 0x6f, 0x6b, 0x72, 0x61, -0x74, 0x69, 0x6b, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0xf3, 0x41, 0x6e, 0x67, 0xf3, 0x6c, 0x61, 0x52, -0x65, 0x70, 0x69, 0x62, 0x69, 0x6b, 0x69, 0x20, 0x79, 0x61, 0x20, 0x41, 0x66, 0x72, 0xed, 0x6b, 0x61, 0x20, 0x79, 0x61, -0x20, 0x4b, 0xe1, 0x74, 0x69, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x69, 0x65, 0x74, 0x75, 0x76, 0x69, 0x173, 0x4c, 0x69, -0x65, 0x74, 0x75, 0x76, 0x61, 0x43c, 0x430, 0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x441, 0x43a, 0x438, 0x41c, 0x430, 0x43a, 0x435, 0x434, -0x43e, 0x43d, 0x438, 0x458, 0x430, 0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x4d, 0x61, 0x64, 0x61, 0x67, 0x61, 0x73, -0x69, 0x6b, 0x61, 0x72, 0x61, 0x42, 0x61, 0x68, 0x61, 0x73, 0x61, 0x20, 0x4d, 0x65, 0x6c, 0x61, 0x79, 0x75, 0x4d, 0x61, -0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x75, 0x72, -0x61, 0xd2e, 0xd32, 0xd2f, 0xd3e, 0xd33, 0xd02, 0xd07, 0xd28, 0xd4d, 0xd24, 0xd4d, 0xd2f, 0x4d, 0x61, 0x6c, 0x74, 0x69, 0x92e, 0x930, -0x93e, 0x920, 0x940, 0x43c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x41c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x928, 0x947, 0x92a, 0x93e, 0x932, -0x940, 0x928, 0x947, 0x92a, 0x93e, 0x932, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x20, 0x62, 0x6f, 0x6b, 0x6d, 0xe5, 0x6c, 0x4e, 0x6f, -0x72, 0x67, 0x65, 0xb13, 0xb21, 0xb3c, 0xb3f, 0xb06, 0xb2d, 0xb3e, 0xb30, 0xb24, 0x67e, 0x69a, 0x62a, 0x648, 0x627, 0x641, 0x63a, 0x627, -0x646, 0x633, 0x62a, 0x627, 0x646, 0x641, 0x627, 0x631, 0x633, 0x6cc, 0x627, 0x6cc, 0x631, 0x627, 0x646, 0x62f, 0x631, 0x6cc, 0x70, 0x6f, -0x6c, 0x73, 0x6b, 0x69, 0x50, 0x6f, 0x6c, 0x73, 0x6b, 0x61, 0x70, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x75, 0xea, 0x73, 0x20, -0x64, 0x6f, 0x20, 0x42, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x42, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x70, 0x6f, 0x72, 0x74, 0x75, -0x67, 0x75, 0xea, 0x73, 0x41, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x43, 0x61, 0x62, 0x6f, 0x20, 0x56, 0x65, 0x72, 0x64, 0x65, -0x54, 0x69, 0x6d, 0x6f, 0x72, 0x2d, 0x4c, 0x65, 0x73, 0x74, 0x65, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x2d, 0x42, 0x69, 0x73, -0x73, 0x61, 0x75, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x2c, 0x20, 0x52, 0x41, 0x45, 0x20, 0x64, 0x61, 0x20, 0x43, 0x68, 0x69, -0x6e, 0x61, 0x4d, 0x6f, 0xe7, 0x61, 0x6d, 0x62, 0x69, 0x71, 0x75, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x75, 0xea, -0x73, 0x20, 0x65, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x75, 0x50, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x61, 0x6c, 0x53, 0xe3, 0x6f, -0x20, 0x54, 0x6f, 0x6d, 0xe9, 0x20, 0x65, 0x20, 0x50, 0x72, 0xed, 0x6e, 0x63, 0x69, 0x70, 0x65, 0xa2a, 0xa70, 0xa1c, 0xa3e, -0xa2c, 0xa40, 0xa2d, 0xa3e, 0xa30, 0xa24, 0x67e, 0x646, 0x62c, 0x627, 0x628, 0x67e, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x72, 0x75, 0x6d, -0x61, 0x6e, 0x74, 0x73, 0x63, 0x68, 0x53, 0x76, 0x69, 0x7a, 0x72, 0x61, 0x72, 0x6f, 0x6d, 0xe2, 0x6e, 0x103, 0x52, 0x6f, -0x6d, 0xe2, 0x6e, 0x69, 0x61, 0x52, 0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x20, 0x4d, 0x6f, 0x6c, 0x64, 0x6f, -0x76, 0x61, 0x440, 0x443, 0x441, 0x441, 0x43a, 0x438, 0x439, 0x420, 0x43e, 0x441, 0x441, 0x438, 0x44f, 0x41a, 0x430, 0x437, 0x430, 0x445, -0x441, 0x442, 0x430, 0x43d, 0x41a, 0x438, 0x440, 0x433, 0x438, 0x437, 0x438, 0x44f, 0x41c, 0x43e, 0x43b, 0x434, 0x43e, 0x432, 0x430, 0x423, -0x43a, 0x440, 0x430, 0x438, 0x43d, 0x430, 0x53, 0xe4, 0x6e, 0x67, 0xf6, 0x4b, 0xf6, 0x64, 0xf6, 0x72, 0xf6, 0x73, 0xea, 0x73, -0x65, 0x20, 0x74, 0xee, 0x20, 0x42, 0xea, 0x61, 0x66, 0x72, 0xee, 0x6b, 0x61, 0x421, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x421, -0x440, 0x431, 0x438, 0x458, 0x430, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x411, 0x43e, 0x441, 0x43d, 0x430, 0x20, 0x438, 0x20, 0x425, -0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x438, 0x43d, 0x430, 0x426, 0x440, 0x43d, 0x430, 0x20, 0x413, 0x43e, 0x440, 0x430, 0x53, -0x72, 0x70, 0x73, 0x6b, 0x69, 0x43, 0x72, 0x6e, 0x61, 0x20, 0x47, 0x6f, 0x72, 0x61, 0x53, 0x72, 0x62, 0x69, 0x6a, 0x61, -0x438, 0x440, 0x43e, 0x43d, 0x413, 0x443, 0x44b, 0x440, 0x434, 0x437, 0x44b, 0x441, 0x442, 0x43e, 0x43d, 0x423, 0x4d5, 0x440, 0x4d5, 0x441, -0x435, 0x53, 0x65, 0x73, 0x6f, 0x74, 0x68, 0x6f, 0x53, 0x65, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x63, 0x68, 0x69, 0x53, -0x68, 0x6f, 0x6e, 0x61, 0xdc3, 0xdd2, 0xd82, 0xdc4, 0xdbd, 0xdc1, 0xdca, 0x200d, 0xdbb, 0xdd3, 0x20, 0xdbd, 0xd82, 0xd9a, 0xdcf, 0xdc0, -0x53, 0x69, 0x73, 0x77, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x10d, 0x69, 0x6e, 0x61, 0x53, 0x6c, 0x6f, -0x76, 0x65, 0x6e, 0x73, 0x6b, 0x6f, 0x73, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x161, 0x10d, 0x69, 0x6e, 0x61, 0x53, 0x6c, 0x6f, -0x76, 0x65, 0x6e, 0x69, 0x6a, 0x61, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, -0x6c, 0x69, 0x79, 0x61, 0x4a, 0x61, 0x62, 0x75, 0x75, 0x74, 0x69, 0x49, 0x74, 0x6f, 0x6f, 0x62, 0x69, 0x79, 0x61, 0x4b, -0x69, 0x69, 0x6e, 0x69, 0x79, 0x61, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x64, 0x65, 0x20, 0x45, 0x73, 0x70, -0x61, 0xf1, 0x61, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x42, -0x6f, 0x6c, 0x69, 0x76, 0x69, 0x61, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x69, 0x61, 0x43, -0x6f, 0x73, 0x74, 0x61, 0x20, 0x52, 0x69, 0x63, 0x61, 0x43, 0x75, 0x62, 0x61, 0x52, 0x65, 0x70, 0xfa, 0x62, 0x6c, 0x69, -0x63, 0x61, 0x20, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x6e, 0x61, 0x45, 0x63, 0x75, 0x61, 0x64, 0x6f, 0x72, -0x45, 0x6c, 0x20, 0x53, 0x61, 0x6c, 0x76, 0x61, 0x64, 0x6f, 0x72, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x45, 0x63, -0x75, 0x61, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x47, 0x75, 0x61, 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x48, 0x6f, 0x6e, -0x64, 0x75, 0x72, 0x61, 0x73, 0x4d, 0xe9, 0x78, 0x69, 0x63, 0x6f, 0x4e, 0x69, 0x63, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, -0x50, 0x61, 0x6e, 0x61, 0x6d, 0xe1, 0x50, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x79, 0x50, 0x65, 0x72, 0xfa, 0x46, 0x69, -0x6c, 0x69, 0x70, 0x69, 0x6e, 0x61, 0x73, 0x45, 0x73, 0x74, 0x61, 0x64, 0x6f, 0x73, 0x20, 0x55, 0x6e, 0x69, 0x64, 0x6f, -0x73, 0x55, 0x72, 0x75, 0x67, 0x75, 0x61, 0x79, 0x56, 0x65, 0x6e, 0x65, 0x7a, 0x75, 0x65, 0x6c, 0x61, 0x49, 0x73, 0x6c, -0x61, 0x73, 0x20, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x61, 0x73, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x6c, -0x61, 0x74, 0x69, 0x6e, 0x6f, 0x61, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x4c, 0x61, 0x74, 0x69, 0x6e, 0x6f, -0x61, 0x6d, 0xe9, 0x72, 0x69, 0x63, 0x61, 0x43, 0x65, 0x75, 0x74, 0x61, 0x20, 0x79, 0x20, 0x4d, 0x65, 0x6c, 0x69, 0x6c, -0x6c, 0x61, 0x4b, 0x69, 0x73, 0x77, 0x61, 0x68, 0x69, 0x6c, 0x69, 0x73, 0x76, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0x53, 0x76, -0x65, 0x72, 0x69, 0x67, 0x65, 0x46, 0x69, 0x6e, 0x6c, 0x61, 0x6e, 0x64, 0xc5, 0x6c, 0x61, 0x6e, 0x64, 0x422, 0x43e, 0x4b7, -0x438, 0x43a, 0x4e3, 0x422, 0x43e, 0x4b7, 0x438, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d, 0xba4, 0xbae, 0xbbf, 0xbb4, 0xbcd, 0xb87, 0xba8, -0xbcd, 0xba4, 0xbbf, 0xbaf, 0xbbe, 0xbae, 0xbb2, 0xbc7, 0xbb7, 0xbbf, 0xbaf, 0xbbe, 0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd, 0xbaa, -0xbc2, 0xbb0, 0xbcd, 0xb87, 0xbb2, 0xb99, 0xbcd, 0xb95, 0xbc8, 0xc24, 0xc46, 0xc32, 0xc41, 0xc17, 0xc41, 0xc2d, 0xc3e, 0xc30, 0xc24, 0x20, -0xc26, 0xc47, 0xc36, 0xc02, 0xe44, 0xe17, 0xe22, 0xf54, 0xf7c, 0xf51, 0xf0b, 0xf66, 0xf90, 0xf51, 0xf0b, 0xf62, 0xf92, 0xfb1, 0xf0b, 0xf53, -0xf42, 0xf62, 0xf92, 0xfb1, 0xf0b, 0xf42, 0xf62, 0xf0b, 0x1275, 0x130d, 0x122d, 0x129b, 0x12a4, 0x122d, 0x1275, 0x122b, 0x6c, 0x65, 0x61, 0x20, -0x66, 0x61, 0x6b, 0x61, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x58, 0x69, 0x74, 0x73, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0xfc, 0x72, -0x6b, 0xe7, 0x65, 0x54, 0xfc, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x47, 0xfc, 0x6e, 0x65, 0x79, 0x20, 0x4b, 0x131, 0x62, 0x72, -0x131, 0x73, 0x20, 0x52, 0x75, 0x6d, 0x20, 0x4b, 0x65, 0x73, 0x69, 0x6d, 0x69, 0x443, 0x43a, 0x440, 0x430, 0x457, 0x43d, 0x441, -0x44c, 0x43a, 0x430, 0x423, 0x43a, 0x440, 0x430, 0x457, 0x43d, 0x430, 0x627, 0x631, 0x62f, 0x648, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, -0x646, 0x628, 0x6be, 0x627, 0x631, 0x62a, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x438, 0x441, 0x442, 0x43e, -0x43d, 0x627, 0x648, 0x632, 0x628, 0x6cc, 0x6a9, 0x6f, 0x2bb, 0x7a, 0x62, 0x65, 0x6b, 0x63, 0x68, 0x61, 0x4f, 0x2bb, 0x7a, 0x62, -0x65, 0x6b, 0x69, 0x73, 0x74, 0x6f, 0x6e, 0x54, 0x69, 0x1ebf, 0x6e, 0x67, 0x20, 0x56, 0x69, 0x1ec7, 0x74, 0x56, 0x69, 0x1ec7, -0x74, 0x20, 0x4e, 0x61, 0x6d, 0x43, 0x79, 0x6d, 0x72, 0x61, 0x65, 0x67, 0x79, 0x20, 0x44, 0x65, 0x79, 0x72, 0x6e, 0x61, -0x73, 0x20, 0x55, 0x6e, 0x65, 0x64, 0x69, 0x67, 0x69, 0x73, 0x69, 0x58, 0x68, 0x6f, 0x73, 0x61, 0xc8, 0x64, 0xe8, 0x20, -0x59, 0x6f, 0x72, 0xf9, 0x62, 0xe1, 0x4f, 0x72, 0xed, 0x6c, 0x1eb9, 0x301, 0xe8, 0x64, 0x65, 0x20, 0x4e, 0xe0, 0xec, 0x6a, -0xed, 0x72, 0xed, 0xe0, 0x69, 0x73, 0x69, 0x5a, 0x75, 0x6c, 0x75, 0x69, 0x4e, 0x69, 0x6e, 0x67, 0x69, 0x7a, 0x69, 0x6d, -0x75, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x6e, 0x79, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x4e, 0x6f, 0x72, 0x65, 0x67, -0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x69, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x438, 0x47, 0x61, 0x65, 0x6c, -0x67, 0x52, 0x79, 0x77, 0x76, 0x61, 0x6e, 0x65, 0x74, 0x68, 0x20, 0x55, 0x6e, 0x79, 0x73, 0x6b, 0x65, 0x72, 0x6e, 0x65, -0x77, 0x65, 0x6b, 0x41, 0x6b, 0x61, 0x6e, 0x47, 0x61, 0x61, 0x6e, 0x61, 0x915, 0x94b, 0x902, 0x915, 0x923, 0x940, 0x49, 0x67, -0x62, 0x6f, 0x4b, 0x69, 0x6b, 0x61, 0x6d, 0x62, 0x61, 0x1265, 0x120a, 0x1295, 0x1275, 0x130d, 0x1228, 0x66, 0x75, 0x72, 0x6c, 0x61, -0x6e, 0x49, 0x74, 0x61, 0x6c, 0x69, 0x65, 0x54, 0x73, 0x68, 0x69, 0x76, 0x65, 0x6e, 0x1e13, 0x61, 0x65, 0x28b, 0x65, 0x67, -0x62, 0x65, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x20, 0x6e, 0x75, 0x74, 0x6f, 0x6d, 0x65, 0x54, 0x6f, 0x67, 0x6f, 0x20, 0x6e, -0x75, 0x74, 0x6f, 0x6d, 0x65, 0x12c8, 0x120b, 0x12ed, 0x1273, 0x1271, 0x2bb, 0x14c, 0x6c, 0x65, 0x6c, 0x6f, 0x20, 0x48, 0x61, 0x77, -0x61, 0x69, 0x2bb, 0x69, 0x2bb, 0x41, 0x6d, 0x65, 0x6c, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x75, 0x69, 0x20, 0x50, 0x16b, 0x20, -0x2bb, 0x49, 0x61, 0x46, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x6f, 0x50, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x61, 0x73, -0x53, 0x63, 0x68, 0x77, 0x69, 0x69, 0x7a, 0x65, 0x72, 0x74, 0xfc, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x53, 0x63, 0x68, 0x77, -0x69, 0x69, 0x7a, 0xa188, 0xa320, 0xa259, 0xa34f, 0xa1e9, 0x69, 0x73, 0x69, 0x4e, 0x64, 0x65, 0x62, 0x65, 0x6c, 0x65, 0x53, 0x65, -0x73, 0x6f, 0x74, 0x68, 0x6f, 0x20, 0x73, 0x61, 0x20, 0x4c, 0x65, 0x62, 0x6f, 0x61, 0x64, 0x61, 0x76, 0x76, 0x69, 0x73, -0xe1, 0x6d, 0x65, 0x67, 0x69, 0x65, 0x6c, 0x6c, 0x61, 0x4e, 0x6f, 0x72, 0x67, 0x61, 0x53, 0x75, 0x6f, 0x70, 0x6d, 0x61, -0x45, 0x6b, 0x65, 0x67, 0x75, 0x73, 0x69, 0x69, 0x4b, 0x69, 0x74, 0x61, 0x69, 0x74, 0x61, 0x50, 0x75, 0x6c, 0x61, 0x61, -0x72, 0x53, 0x65, 0x6e, 0x65, 0x67, 0x61, 0x61, 0x6c, 0x47, 0x69, 0x6b, 0x75, 0x79, 0x75, 0x4b, 0x69, 0x73, 0x61, 0x6d, -0x70, 0x75, 0x72, 0x73, 0x65, 0x6e, 0x61, 0x4b, 0x69, 0x68, 0x6f, 0x72, 0x6f, 0x6d, 0x62, 0x6f, 0x2d5c, 0x2d30, 0x2d4e, 0x2d30, -0x2d63, 0x2d49, 0x2d56, 0x2d5c, 0x2d4d, 0x2d4e, 0x2d56, 0x2d54, 0x2d49, 0x2d31, 0x74, 0x61, 0x6d, 0x61, 0x7a, 0x69, 0x67, 0x68, 0x74, 0x6c, -0x6d, 0x263, 0x72, 0x69, 0x62, 0x54, 0x61, 0x71, 0x62, 0x61, 0x79, 0x6c, 0x69, 0x74, 0x4c, 0x65, 0x7a, 0x7a, 0x61, 0x79, -0x65, 0x72, 0x52, 0x75, 0x6e, 0x79, 0x61, 0x6e, 0x6b, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x62, 0x65, 0x6e, 0x61, 0x48, 0x75, -0x74, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x4b, 0x79, 0x69, 0x76, 0x75, 0x6e, 0x6a, 0x6f, 0x62, 0x61, 0x6d, 0x61, -0x6e, 0x61, 0x6b, 0x61, 0x6e, 0x4b, 0x129, 0x65, 0x6d, 0x62, 0x75, 0x13e3, 0x13b3, 0x13a9, 0x13a0, 0x13b9, 0x13f0, 0x13df, 0x6b, 0x72, -0x65, 0x6f, 0x6c, 0x20, 0x6d, 0x6f, 0x72, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x4d, 0x6f, 0x72, 0x69, 0x73, 0x43, 0x68, 0x69, -0x6d, 0x61, 0x6b, 0x6f, 0x6e, 0x64, 0x65, 0x4b, 0x268, 0x6c, 0x61, 0x61, 0x6e, 0x67, 0x69, 0x54, 0x61, 0x61, 0x6e, 0x73, -0x61, 0x6e, 0xed, 0x61, 0x4c, 0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x59, 0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x49, 0x63, -0x68, 0x69, 0x62, 0x65, 0x6d, 0x62, 0x61, 0x6b, 0x61, 0x62, 0x75, 0x76, 0x65, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x75, 0x4b, -0x61, 0x62, 0x75, 0x20, 0x56, 0x65, 0x72, 0x64, 0x69, 0x4b, 0x129, 0x6d, 0x129, 0x72, 0x169, 0x4b, 0x61, 0x6c, 0x65, 0x6e, -0x6a, 0x69, 0x6e, 0x45, 0x6d, 0x65, 0x74, 0x61, 0x62, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x4b, 0x68, 0x6f, 0x65, 0x6b, -0x68, 0x6f, 0x65, 0x67, 0x6f, 0x77, 0x61, 0x62, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x62, 0x4b, 0x69, 0x6d, 0x61, -0x63, 0x68, 0x61, 0x6d, 0x65, 0x4b, 0xf6, 0x6c, 0x73, 0x63, 0x68, 0x44, 0x6f, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61, -0x6e, 0x64, 0x4d, 0x61, 0x61, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69, 0x61, 0x4f, 0x6c, 0x75, 0x73, 0x6f, 0x67, 0x61, -0x4c, 0x75, 0x6c, 0x75, 0x68, 0x69, 0x61, 0x4b, 0x69, 0x70, 0x61, 0x72, 0x65, 0x54, 0x61, 0x64, 0x68, 0x61, 0x6e, 0x69, -0x61, 0x4b, 0x69, 0x74, 0x65, 0x73, 0x6f, 0x4b, 0x65, 0x6e, 0x69, 0x61, 0x4b, 0x6f, 0x79, 0x72, 0x61, 0x20, 0x63, 0x69, -0x69, 0x6e, 0x69, 0x4d, 0x61, 0x61, 0x6c, 0x69, 0x4b, 0x69, 0x72, 0x75, 0x77, 0x61, 0x44, 0x68, 0x6f, 0x6c, 0x75, 0x6f, -0x52, 0x75, 0x6b, 0x69, 0x67, 0x61, 0x54, 0x61, 0x6d, 0x61, 0x7a, 0x69, 0x263, 0x74, 0x4d, 0x65, 0x1e5b, 0x1e5b, 0x75, 0x6b, -0x4b, 0x6f, 0x79, 0x72, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69, 0x4b, 0x69, 0x73, 0x68, 0x61, -0x6d, 0x62, 0x61, 0x61, 0x92c, 0x921, 0x93c, 0x94b, 0x54, 0x73, 0x68, 0x69, 0x6c, 0x75, 0x62, 0x61, 0x44, 0x69, 0x74, 0x75, -0x6e, 0x67, 0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x75, 0x41, 0x67, 0x68, 0x65, 0x6d, 0x4b, 0xe0, 0x6d, -0xe0, 0x6c, 0xfb, 0x14b, 0x181, 0xe0, 0x73, 0xe0, 0x61, 0x4b, 0xe0, 0x6d, 0x25b, 0x300, 0x72, 0xfb, 0x6e, 0x5a, 0x61, 0x72, -0x6d, 0x61, 0x63, 0x69, 0x69, 0x6e, 0x65, 0x4e, 0x69, 0x17e, 0x65, 0x72, 0x64, 0x75, 0xe1, 0x6c, 0xe1, 0x6a, 0x6f, 0x6f, -0x6c, 0x61, 0x53, 0x65, 0x6e, 0x65, 0x67, 0x61, 0x6c, 0x65, 0x77, 0x6f, 0x6e, 0x64, 0x6f, 0x4b, 0x61, 0x6d, 0x259, 0x72, -0xfa, 0x6e, 0x72, 0x69, 0x6b, 0x70, 0x61, 0x6b, 0x61, 0x6d, 0x25b, 0x72, 0xfa, 0x6e, 0x4d, 0x61, 0x6b, 0x75, 0x61, 0x55, -0x6d, 0x6f, 0x7a, 0x61, 0x6d, 0x62, 0x69, 0x6b, 0x69, 0x4d, 0x55, 0x4e, 0x44, 0x41, 0x14a, 0x6b, 0x61, 0x6d, 0x65, 0x72, -0x75, 0x14b, 0x4b, 0x77, 0x61, 0x73, 0x69, 0x6f, 0x4b, 0x61, 0x6d, 0x65, 0x72, 0x75, 0x6e, 0x54, 0x68, 0x6f, 0x6b, 0x20, -0x4e, 0x61, 0x74, 0x68, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x441, 0x430, 0x445, 0x430, 0x20, 0x442, 0x44b, 0x43b, 0x430, 0x49, 0x73, -0x68, 0x69, 0x73, 0x61, 0x6e, 0x67, 0x75, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69, 0x79, 0x61, 0x4b, 0x69, 0x73, 0x77, -0x61, 0x68, 0x69, 0x6c, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x4a, 0x61, 0x6d, 0x68, 0x75, 0x72, -0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x69, 0x64, 0x65, 0x6d, 0x6f, 0x6b, 0x72, 0x61, 0x73, 0x69, 0x61, 0x20, 0x79, 0x61, -0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x54, 0x61, 0x73, 0x61, 0x77, 0x61, 0x71, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69, 0xa559, -0xa524, 0xa55e, 0xa524, 0xa52b, 0xa569, 0x56, 0x61, 0x69, 0x4c, 0x61, 0x69, 0x62, 0x68, 0x69, 0x79, 0x61, 0x57, 0x61, 0x6c, 0x73, -0x65, 0x72, 0x53, 0x63, 0x68, 0x77, 0x69, 0x7a, 0x6e, 0x75, 0x61, 0x73, 0x75, 0x65, 0x4b, 0x65, 0x6d, 0x65, 0x6c, 0xfa, -0x6e, 0x61, 0x73, 0x74, 0x75, 0x72, 0x69, 0x61, 0x6e, 0x75, 0x4e, 0x64, 0x61, 0xa78c, 0x61, 0x4b, 0x61, 0x6d, 0x25b, 0x6c, -0xfb, 0x6e, 0x6b, 0x61, 0x6b, 0x254, 0x4b, 0x61, 0x6d, 0x25b, 0x72, 0x75, 0x6e, 0x6d, 0x65, 0x74, 0x61, 0x2bc, 0x4b, 0x61, -0x6d, 0x61, 0x6c, 0x75, 0x6e, 0x53, 0x68, 0x77, 0xf3, 0x14b, 0xf2, 0x20, 0x6e, 0x67, 0x69, 0x65, 0x6d, 0x62, 0x254, 0x254, -0x6e, 0x4b, 0xe0, 0x6d, 0x61, 0x6c, 0xfb, 0x6d +0x69, 0x70, 0x53, 0x68, 0x71, 0x69, 0x70, 0xeb, 0x72, 0x69, 0x61, 0x4d, 0x61, 0x71, 0x65, 0x64, 0x6f, 0x6e, 0x69, 0x4b, +0x6f, 0x73, 0x6f, 0x76, 0xeb, 0x12a0, 0x121b, 0x122d, 0x129b, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, +0x629, 0x645, 0x635, 0x631, 0x627, 0x644, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x627, 0x644, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x62a, 0x634, +0x627, 0x62f, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x623, 0x631, 0x64a, +0x62a, 0x631, 0x64a, 0x627, 0x627, 0x644, 0x639, 0x631, 0x627, 0x642, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x627, 0x644, 0x623, +0x631, 0x62f, 0x646, 0x627, 0x644, 0x643, 0x648, 0x64a, 0x62a, 0x644, 0x628, 0x646, 0x627, 0x646, 0x644, 0x64a, 0x628, 0x64a, 0x627, 0x645, +0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x627, 0x627, 0x644, 0x645, 0x63a, 0x631, 0x628, 0x639, 0x64f, 0x645, 0x627, 0x646, 0x641, +0x644, 0x633, 0x637, 0x64a, 0x646, 0x642, 0x637, 0x631, 0x627, 0x644, 0x645, 0x645, 0x644, 0x643, 0x629, 0x20, 0x627, 0x644, 0x639, 0x631, +0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x629, 0x627, 0x644, 0x635, 0x648, 0x645, 0x627, 0x644, 0x627, +0x644, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x633, 0x648, 0x631, 0x64a, 0x627, 0x62a, 0x648, 0x646, 0x633, 0x627, 0x644, 0x625, 0x645, 0x627, +0x631, 0x627, 0x62a, 0x20, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, 0x645, 0x62a, 0x62d, 0x62f, 0x629, 0x627, +0x644, 0x635, 0x62d, 0x631, 0x627, 0x621, 0x20, 0x627, 0x644, 0x63a, 0x631, 0x628, 0x64a, 0x629, 0x627, 0x644, 0x64a, 0x645, 0x646, 0x570, +0x561, 0x575, 0x565, 0x580, 0x565, 0x576, 0x540, 0x561, 0x575, 0x561, 0x57d, 0x57f, 0x561, 0x576, 0x985, 0x9b8, 0x9ae, 0x9c0, 0x9af, 0x9bc, +0x9be, 0x9ad, 0x9be, 0x9f0, 0x9a4, 0x61, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x63, 0x61, 0x41, 0x7a, 0x259, +0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x410, 0x437, 0x4d9, 0x440, 0x431, 0x430, 0x458, 0x4b9, 0x430, 0x43d, 0x65, 0x75, 0x73, +0x6b, 0x61, 0x72, 0x61, 0x45, 0x73, 0x70, 0x61, 0x69, 0x6e, 0x69, 0x61, 0x9ac, 0x9be, 0x982, 0x9b2, 0x9be, 0x9ac, 0x9be, 0x982, +0x9b2, 0x9be, 0x9a6, 0x9c7, 0x9b6, 0x9ad, 0x9be, 0x9b0, 0x9a4, 0xf62, 0xfab, 0xf7c, 0xf44, 0xf0b, 0xf41, 0xf60, 0xf56, 0xfb2, 0xf74, 0xf42, +0x62, 0x72, 0x65, 0x7a, 0x68, 0x6f, 0x6e, 0x65, 0x67, 0x46, 0x72, 0x61, 0xf1, 0x73, 0x431, 0x44a, 0x43b, 0x433, 0x430, 0x440, +0x441, 0x43a, 0x438, 0x411, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x438, 0x44f, 0x1017, 0x1019, 0x102c, 0x1019, 0x103c, 0x1014, 0x103a, 0x1019, 0x102c, +0x431, 0x435, 0x43b, 0x430, 0x440, 0x443, 0x441, 0x43a, 0x430, 0x44f, 0x411, 0x435, 0x43b, 0x430, 0x440, 0x443, 0x441, 0x44c, 0x1781, 0x17d2, +0x1798, 0x17c2, 0x179a, 0x1780, 0x1798, 0x17d2, 0x1796, 0x17bb, 0x1787, 0x17b6, 0x63, 0x61, 0x74, 0x61, 0x6c, 0xe0, 0x45, 0x73, 0x70, 0x61, +0x6e, 0x79, 0x61, 0x41, 0x6e, 0x64, 0x6f, 0x72, 0x72, 0x61, 0x7b80, 0x4f53, 0x4e2d, 0x6587, 0x4e2d, 0x56fd, 0x4e2d, 0x56fd, 0x9999, 0x6e2f, +0x7279, 0x522b, 0x884c, 0x653f, 0x533a, 0x4e2d, 0x56fd, 0x6fb3, 0x95e8, 0x7279, 0x522b, 0x884c, 0x653f, 0x533a, 0x65b0, 0x52a0, 0x5761, 0x7e41, 0x9ad4, 0x4e2d, +0x6587, 0x4e2d, 0x83ef, 0x4eba, 0x6c11, 0x5171, 0x548c, 0x570b, 0x9999, 0x6e2f, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x4e2d, 0x83ef, 0x4eba, 0x6c11, 0x5171, +0x548c, 0x570b, 0x6fb3, 0x9580, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x53f0, 0x7063, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x69, 0x48, +0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x61, 0x42, 0x6f, 0x73, 0x6e, 0x61, 0x20, 0x69, 0x20, 0x48, 0x65, 0x72, 0x63, 0x65, +0x67, 0x6f, 0x76, 0x69, 0x6e, 0x61, 0x10d, 0x65, 0x161, 0x74, 0x69, 0x6e, 0x61, 0x10c, 0x65, 0x73, 0x6b, 0xe1, 0x20, 0x72, +0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x6b, 0x61, 0x64, 0x61, 0x6e, 0x73, 0x6b, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, +0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x41, +0x72, 0x75, 0x62, 0x61, 0x56, 0x6c, 0x61, 0x61, 0x6d, 0x73, 0x42, 0x65, 0x6c, 0x67, 0x69, 0xeb, 0x43, 0x75, 0x72, 0x61, +0xe7, 0x61, 0x6f, 0x53, 0x75, 0x72, 0x69, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x69, 0x6e, 0x74, 0x2d, 0x4d, 0x61, 0x61, 0x72, +0x74, 0x65, 0x6e, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x65, +0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0xd801, 0xdc00, 0xd801, 0xdc4d, 0xd801, 0xdc4a, 0xd801, 0xdc2e, 0xd801, 0xdc47, 0xd801, 0xdc0f, +0xd801, 0xdc2d, 0xd801, 0xdc4c, 0xd801, 0xdc34, 0xd801, 0xdc3b, 0xd801, 0xdc32, 0xd801, 0xdc3c, 0x20, 0xd801, 0xdc1d, 0xd801, 0xdc3b, 0xd801, 0xdc29, 0xd801, +0xdc3b, 0xd801, 0xdc45, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x53, +0x61, 0x6d, 0x6f, 0x61, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x42, 0x61, 0x72, 0x62, +0x75, 0x64, 0x61, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, +0x68, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x61, 0x73, 0x42, 0x61, 0x72, +0x62, 0x61, 0x64, 0x6f, 0x73, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x75, 0x6d, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x42, 0x65, +0x72, 0x6d, 0x75, 0x64, 0x61, 0x42, 0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x6f, 0x6f, +0x6e, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x43, 0x61, 0x6e, +0x61, 0x64, 0x61, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x44, 0x6f, 0x6d, +0x69, 0x6e, 0x69, 0x63, 0x61, 0x46, 0x69, 0x6a, 0x69, 0x47, 0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x47, 0x61, 0x6d, +0x62, 0x69, 0x61, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x47, 0x72, 0x65, +0x6e, 0x61, 0x64, 0x61, 0x47, 0x75, 0x61, 0x6d, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, +0x6f, 0x6e, 0x67, 0x20, 0x53, 0x41, 0x52, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x49, 0x72, +0x65, 0x6c, 0x61, 0x6e, 0x64, 0x4a, 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x4b, 0x69, 0x72, +0x69, 0x62, 0x61, 0x74, 0x69, 0x4c, 0x65, 0x73, 0x6f, 0x74, 0x68, 0x6f, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x4d, +0x61, 0x64, 0x61, 0x67, 0x61, 0x73, 0x63, 0x61, 0x72, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x4d, 0x61, 0x6c, 0x74, 0x61, +0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x4d, 0x61, 0x75, 0x72, +0x69, 0x74, 0x69, 0x75, 0x73, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x4e, 0x61, 0x6d, 0x69, 0x62, +0x69, 0x61, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, +0x4e, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x61, 0x20, 0x49, 0x73, 0x6c, +0x61, 0x6e, 0x64, 0x73, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x50, 0x61, 0x70, +0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, +0x69, 0x6e, 0x65, 0x73, 0x50, 0x75, 0x65, 0x72, 0x74, 0x6f, 0x20, 0x52, 0x69, 0x63, 0x6f, 0x53, 0x61, 0x69, 0x6e, 0x74, +0x20, 0x4b, 0x69, 0x74, 0x74, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4e, 0x65, 0x76, 0x69, 0x73, 0x53, 0x61, 0x69, 0x6e, +0x74, 0x20, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x20, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x74, +0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x53, +0x61, 0x6d, 0x6f, 0x61, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, +0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, +0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, +0x63, 0x61, 0x53, 0x77, 0x61, 0x7a, 0x69, 0x6c, 0x61, 0x6e, 0x64, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x54, +0x6f, 0x6e, 0x67, 0x61, 0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, 0x61, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x6f, 0x62, +0x61, 0x67, 0x6f, 0x54, 0x75, 0x72, 0x6b, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x43, 0x61, 0x69, 0x63, 0x6f, 0x73, 0x20, +0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, +0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x4b, 0x69, 0x6e, 0x67, 0x64, +0x6f, 0x6d, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x4f, 0x75, 0x74, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x49, 0x73, 0x6c, 0x61, +0x6e, 0x64, 0x73, 0x56, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x56, 0x69, +0x72, 0x67, 0x69, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x56, 0x69, 0x72, +0x67, 0x69, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x5a, 0x69, 0x6d, +0x62, 0x61, 0x62, 0x77, 0x65, 0x49, 0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x61, 0x6e, 0x4a, 0x65, 0x72, 0x73, +0x65, 0x79, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x65, 0x73, 0x74, 0x69, 0x45, 0x65, +0x73, 0x74, 0x69, 0x66, 0xf8, 0x72, 0x6f, 0x79, 0x73, 0x6b, 0x74, 0x46, 0xf8, 0x72, 0x6f, 0x79, 0x61, 0x72, 0x73, 0x75, +0x6f, 0x6d, 0x69, 0x53, 0x75, 0x6f, 0x6d, 0x69, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x46, 0x72, 0x61, 0x6e, +0x63, 0x65, 0x41, 0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x71, 0x75, 0x65, 0x42, 0xe9, 0x6e, +0x69, 0x6e, 0x42, 0x75, 0x72, 0x6b, 0x69, 0x6e, 0x61, 0x20, 0x46, 0x61, 0x73, 0x6f, 0x42, 0x75, 0x72, 0x75, 0x6e, 0x64, +0x69, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x6f, 0x75, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x20, 0x63, 0x61, +0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x52, 0xe9, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x71, 0x75, 0x65, 0x20, 0x63, 0x65, 0x6e, +0x74, 0x72, 0x61, 0x66, 0x72, 0x69, 0x63, 0x61, 0x69, 0x6e, 0x65, 0x54, 0x63, 0x68, 0x61, 0x64, 0x43, 0x6f, 0x6d, 0x6f, +0x72, 0x65, 0x73, 0x52, 0xe9, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x71, 0x75, 0x65, 0x20, 0x64, 0xe9, 0x6d, 0x6f, 0x63, 0x72, +0x61, 0x74, 0x69, 0x71, 0x75, 0x65, 0x20, 0x64, 0x75, 0x20, 0x43, 0x6f, 0x6e, 0x67, 0x6f, 0x43, 0x6f, 0x6e, 0x67, 0x6f, +0x2d, 0x42, 0x72, 0x61, 0x7a, 0x7a, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x43, 0xf4, 0x74, 0x65, 0x20, 0x64, 0x2019, 0x49, +0x76, 0x6f, 0x69, 0x72, 0x65, 0x44, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x20, +0xe9, 0x71, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x65, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x65, 0x20, 0x66, 0x72, +0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x79, 0x6e, 0xe9, 0x73, 0x69, 0x65, 0x20, 0x66, 0x72, 0x61, +0x6e, 0xe7, 0x61, 0x69, 0x73, 0x65, 0x47, 0x61, 0x62, 0x6f, 0x6e, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f, 0x75, 0x70, +0x65, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x48, 0x61, 0xef, 0x74, 0x69, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f, 0x75, +0x72, 0x67, 0x4d, 0x61, 0x6c, 0x69, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x4d, 0x61, 0x75, 0x72, +0x69, 0x74, 0x61, 0x6e, 0x69, 0x65, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, +0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x4d, 0x61, 0x72, 0x6f, 0x63, 0x4e, 0x6f, 0x75, 0x76, 0x65, 0x6c, 0x6c, 0x65, 0x2d, +0x43, 0x61, 0x6c, 0xe9, 0x64, 0x6f, 0x6e, 0x69, 0x65, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x52, 0xe9, 0x75, 0x6e, 0x69, 0x6f, +0x6e, 0x52, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x53, 0xe9, 0x6e, 0xe9, 0x67, 0x61, 0x6c, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, +0x69, 0x73, 0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x53, 0x75, 0x69, 0x73, 0x73, 0x65, 0x53, 0x79, 0x72, 0x69, 0x65, +0x54, 0x6f, 0x67, 0x6f, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x2d, 0x42, 0x61, 0x72, +0x74, 0x68, 0xe9, 0x6c, 0xe9, 0x6d, 0x79, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x2d, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x20, +0x5b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x65, 0x5d, 0x47, 0xe0, +0x69, 0x64, 0x68, 0x6c, 0x69, 0x67, 0x41, 0x6e, 0x20, 0x52, 0xec, 0x6f, 0x67, 0x68, 0x61, 0x63, 0x68, 0x64, 0x20, 0x41, +0x6f, 0x6e, 0x61, 0x69, 0x63, 0x68, 0x74, 0x65, 0x67, 0x61, 0x6c, 0x65, 0x67, 0x6f, 0x45, 0x73, 0x70, 0x61, 0xf1, 0x61, +0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10e3, 0x10da, 0x10d8, 0x10e1, 0x10d0, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10d5, 0x10d4, 0x10da, 0x10dd, 0x44, 0x65, 0x75, +0x74, 0x73, 0x63, 0x68, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61, 0x6e, 0x64, 0xd6, 0x73, 0x74, 0x65, 0x72, +0x72, 0x65, 0x69, 0x63, 0x68, 0x69, 0x73, 0x63, 0x68, 0x65, 0x73, 0x20, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0xd6, +0x73, 0x74, 0x65, 0x72, 0x72, 0x65, 0x69, 0x63, 0x68, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x65, 0x6e, 0x4c, 0x69, 0x65, 0x63, +0x68, 0x74, 0x65, 0x6e, 0x73, 0x74, 0x65, 0x69, 0x6e, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x75, 0x72, 0x67, 0x53, 0x63, +0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x48, 0x6f, 0x63, 0x68, 0x64, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x53, +0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x395, 0x3bb, 0x3bb, 0x3b7, 0x3bd, 0x3b9, 0x3ba, 0x3ac, 0x395, 0x3bb, 0x3bb, 0x3ac, 0x3b4, 0x3b1, +0x39a, 0x3cd, 0x3c0, 0x3c1, 0x3bf, 0x3c2, 0x6b, 0x61, 0x6c, 0x61, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x75, 0x74, 0x4b, 0x61, 0x6c, +0x61, 0x61, 0x6c, 0x6c, 0x69, 0x74, 0x20, 0x4e, 0x75, 0x6e, 0x61, 0x61, 0x74, 0xa97, 0xac1, 0xa9c, 0xab0, 0xabe, 0xaa4, 0xac0, +0xaad, 0xabe, 0xab0, 0xaa4, 0x48, 0x61, 0x75, 0x73, 0x61, 0x4e, 0x61, 0x6a, 0x65, 0x72, 0x69, 0x79, 0x61, 0x47, 0x61, 0x6e, +0x61, 0x4e, 0x69, 0x6a, 0x61, 0x72, 0x5e2, 0x5d1, 0x5e8, 0x5d9, 0x5ea, 0x5d9, 0x5e9, 0x5e8, 0x5d0, 0x5dc, 0x939, 0x93f, 0x928, 0x94d, +0x926, 0x940, 0x92d, 0x93e, 0x930, 0x924, 0x6d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x4d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x6f, 0x72, +0x73, 0x7a, 0xe1, 0x67, 0xed, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0xcd, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x42, 0x61, +0x68, 0x61, 0x73, 0x61, 0x20, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, +0x73, 0x69, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x75, 0x61, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, +0x61, 0x47, 0x61, 0x65, 0x69, 0x6c, 0x67, 0x65, 0xc9, 0x69, 0x72, 0x65, 0x69, 0x74, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x6f, +0x49, 0x74, 0x61, 0x6c, 0x69, 0x61, 0x53, 0x61, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x6e, 0x6f, 0x53, 0x76, 0x69, 0x7a, +0x7a, 0x65, 0x72, 0x61, 0x65e5, 0x672c, 0x8a9e, 0x65e5, 0x672c, 0xc95, 0xca8, 0xccd, 0xca8, 0xca1, 0xcad, 0xcbe, 0xcb0, 0xca4, 0x6a9, 0x672, +0x634, 0x64f, 0x631, 0x6c1, 0x650, 0x646, 0x65b, 0x62f, 0x648, 0x633, 0x62a, 0x627, 0x646, 0x49b, 0x430, 0x437, 0x430, 0x49b, 0x20, 0x442, +0x456, 0x43b, 0x456, 0x49a, 0x430, 0x437, 0x430, 0x49b, 0x441, 0x442, 0x430, 0x43d, 0x4b, 0x69, 0x6e, 0x79, 0x61, 0x72, 0x77, 0x61, +0x6e, 0x64, 0x61, 0x41a, 0x44b, 0x440, 0x433, 0x44b, 0x437, 0x41a, 0x44b, 0x440, 0x433, 0x44b, 0x437, 0x441, 0x442, 0x430, 0x43d, 0xd55c, +0xad6d, 0xc5b4, 0xb300, 0xd55c, 0xbbfc, 0xad6d, 0xc870, 0xc120, 0x20, 0xbbfc, 0xc8fc, 0xc8fc, 0xc758, 0x20, 0xc778, 0xbbfc, 0x20, 0xacf5, 0xd654, 0xad6d, +0x49, 0x6b, 0x69, 0x72, 0x75, 0x6e, 0x64, 0x69, 0x55, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x69, 0xea5, 0xeb2, 0xea7, 0xeaa, +0x2e, 0xe9b, 0x2e, 0xe9b, 0x20, 0xea5, 0xeb2, 0xea7, 0x6c, 0x61, 0x74, 0x76, 0x69, 0x65, 0x161, 0x75, 0x4c, 0x61, 0x74, 0x76, +0x69, 0x6a, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0xe1, 0x6c, 0x61, 0x52, 0x65, 0x70, 0x69, 0x62, 0x69, 0x6b, 0x69, 0x20, 0x64, +0x65, 0x6d, 0x6f, 0x6b, 0x72, 0x61, 0x74, 0x69, 0x6b, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0xf3, 0x41, +0x6e, 0x67, 0xf3, 0x6c, 0x61, 0x52, 0x65, 0x70, 0x69, 0x62, 0x69, 0x6b, 0x69, 0x20, 0x79, 0x61, 0x20, 0x41, 0x66, 0x72, +0xed, 0x6b, 0x61, 0x20, 0x79, 0x61, 0x20, 0x4b, 0xe1, 0x74, 0x69, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x69, 0x65, 0x74, +0x75, 0x76, 0x69, 0x173, 0x4c, 0x69, 0x65, 0x74, 0x75, 0x76, 0x61, 0x43c, 0x430, 0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x441, 0x43a, +0x438, 0x41c, 0x430, 0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x438, 0x458, 0x430, 0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x4d, +0x61, 0x64, 0x61, 0x67, 0x61, 0x73, 0x69, 0x6b, 0x61, 0x72, 0x61, 0x42, 0x61, 0x68, 0x61, 0x73, 0x61, 0x20, 0x4d, 0x65, +0x6c, 0x61, 0x79, 0x75, 0x4d, 0x61, 0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x53, 0x69, +0x6e, 0x67, 0x61, 0x70, 0x75, 0x72, 0x61, 0xd2e, 0xd32, 0xd2f, 0xd3e, 0xd33, 0xd02, 0xd07, 0xd28, 0xd4d, 0xd24, 0xd4d, 0xd2f, 0x4d, +0x61, 0x6c, 0x74, 0x69, 0x92e, 0x930, 0x93e, 0x920, 0x940, 0x43c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x41c, 0x43e, 0x43d, 0x433, 0x43e, +0x43b, 0x928, 0x947, 0x92a, 0x93e, 0x932, 0x940, 0x928, 0x947, 0x92a, 0x93e, 0x932, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x20, 0x62, 0x6f, +0x6b, 0x6d, 0xe5, 0x6c, 0x4e, 0x6f, 0x72, 0x67, 0x65, 0xb13, 0xb21, 0xb3c, 0xb3f, 0xb06, 0xb2d, 0xb3e, 0xb30, 0xb24, 0x67e, 0x69a, +0x62a, 0x648, 0x627, 0x641, 0x63a, 0x627, 0x646, 0x633, 0x62a, 0x627, 0x646, 0x641, 0x627, 0x631, 0x633, 0x6cc, 0x627, 0x6cc, 0x631, 0x627, +0x646, 0x62f, 0x631, 0x6cc, 0x70, 0x6f, 0x6c, 0x73, 0x6b, 0x69, 0x50, 0x6f, 0x6c, 0x73, 0x6b, 0x61, 0x70, 0x6f, 0x72, 0x74, +0x75, 0x67, 0x75, 0xea, 0x73, 0x20, 0x64, 0x6f, 0x20, 0x42, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x42, 0x72, 0x61, 0x73, 0x69, +0x6c, 0x70, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x75, 0xea, 0x73, 0x41, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x43, 0x61, 0x62, 0x6f, +0x20, 0x56, 0x65, 0x72, 0x64, 0x65, 0x54, 0x69, 0x6d, 0x6f, 0x72, 0x2d, 0x4c, 0x65, 0x73, 0x74, 0x65, 0x47, 0x75, 0x69, +0x6e, 0xe9, 0x2d, 0x42, 0x69, 0x73, 0x73, 0x61, 0x75, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x2c, 0x20, 0x52, 0x41, 0x45, 0x20, +0x64, 0x61, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x4d, 0x6f, 0xe7, 0x61, 0x6d, 0x62, 0x69, 0x71, 0x75, 0x65, 0x70, 0x6f, +0x72, 0x74, 0x75, 0x67, 0x75, 0xea, 0x73, 0x20, 0x65, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x75, 0x50, 0x6f, 0x72, 0x74, 0x75, +0x67, 0x61, 0x6c, 0x53, 0xe3, 0x6f, 0x20, 0x54, 0x6f, 0x6d, 0xe9, 0x20, 0x65, 0x20, 0x50, 0x72, 0xed, 0x6e, 0x63, 0x69, +0x70, 0x65, 0xa2a, 0xa70, 0xa1c, 0xa3e, 0xa2c, 0xa40, 0xa2d, 0xa3e, 0xa30, 0xa24, 0x67e, 0x646, 0x62c, 0x627, 0x628, 0x67e, 0x6a9, 0x633, +0x62a, 0x627, 0x646, 0x72, 0x75, 0x6d, 0x61, 0x6e, 0x74, 0x73, 0x63, 0x68, 0x53, 0x76, 0x69, 0x7a, 0x72, 0x61, 0x72, 0x6f, +0x6d, 0xe2, 0x6e, 0x103, 0x52, 0x6f, 0x6d, 0xe2, 0x6e, 0x69, 0x61, 0x52, 0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, +0x20, 0x4d, 0x6f, 0x6c, 0x64, 0x6f, 0x76, 0x61, 0x440, 0x443, 0x441, 0x441, 0x43a, 0x438, 0x439, 0x420, 0x43e, 0x441, 0x441, 0x438, +0x44f, 0x41a, 0x430, 0x437, 0x430, 0x445, 0x441, 0x442, 0x430, 0x43d, 0x41a, 0x438, 0x440, 0x433, 0x438, 0x437, 0x438, 0x44f, 0x41c, 0x43e, +0x43b, 0x434, 0x43e, 0x432, 0x430, 0x423, 0x43a, 0x440, 0x430, 0x438, 0x43d, 0x430, 0x53, 0xe4, 0x6e, 0x67, 0xf6, 0x4b, 0xf6, 0x64, +0xf6, 0x72, 0xf6, 0x73, 0xea, 0x73, 0x65, 0x20, 0x74, 0xee, 0x20, 0x42, 0xea, 0x61, 0x66, 0x72, 0xee, 0x6b, 0x61, 0x421, +0x440, 0x43f, 0x441, 0x43a, 0x438, 0x421, 0x440, 0x431, 0x438, 0x458, 0x430, 0x53, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x43, 0x72, 0x6e, +0x61, 0x20, 0x47, 0x6f, 0x72, 0x61, 0x53, 0x72, 0x62, 0x69, 0x6a, 0x61, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x411, 0x43e, +0x441, 0x43d, 0x430, 0x20, 0x438, 0x20, 0x425, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x438, 0x43d, 0x430, 0x426, 0x440, 0x43d, +0x430, 0x20, 0x413, 0x43e, 0x440, 0x430, 0x41a, 0x43e, 0x441, 0x43e, 0x432, 0x43e, 0x4b, 0x6f, 0x73, 0x6f, 0x76, 0x6f, 0x438, 0x440, +0x43e, 0x43d, 0x413, 0x443, 0x44b, 0x440, 0x434, 0x437, 0x44b, 0x441, 0x442, 0x43e, 0x43d, 0x423, 0x4d5, 0x440, 0x4d5, 0x441, 0x435, 0x53, +0x65, 0x73, 0x6f, 0x74, 0x68, 0x6f, 0x53, 0x65, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x63, 0x68, 0x69, 0x53, 0x68, 0x6f, +0x6e, 0x61, 0xdc3, 0xdd2, 0xd82, 0xdc4, 0xdbd, 0xdc1, 0xdca, 0x200d, 0xdbb, 0xdd3, 0x20, 0xdbd, 0xd82, 0xd9a, 0xdcf, 0xdc0, 0x53, 0x69, +0x73, 0x77, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x10d, 0x69, 0x6e, 0x61, 0x53, 0x6c, 0x6f, 0x76, 0x65, +0x6e, 0x73, 0x6b, 0x6f, 0x73, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x161, 0x10d, 0x69, 0x6e, 0x61, 0x53, 0x6c, 0x6f, 0x76, 0x65, +0x6e, 0x69, 0x6a, 0x61, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, +0x79, 0x61, 0x4a, 0x61, 0x62, 0x75, 0x75, 0x74, 0x69, 0x49, 0x74, 0x6f, 0x6f, 0x62, 0x69, 0x79, 0x61, 0x4b, 0x69, 0x69, +0x6e, 0x69, 0x79, 0x61, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x64, 0x65, 0x20, 0x45, 0x73, 0x70, 0x61, 0xf1, +0x61, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x42, 0x6f, 0x6c, +0x69, 0x76, 0x69, 0x61, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x69, 0x61, 0x43, 0x6f, 0x73, +0x74, 0x61, 0x20, 0x52, 0x69, 0x63, 0x61, 0x43, 0x75, 0x62, 0x61, 0x52, 0x65, 0x70, 0xfa, 0x62, 0x6c, 0x69, 0x63, 0x61, +0x20, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x6e, 0x61, 0x45, 0x63, 0x75, 0x61, 0x64, 0x6f, 0x72, 0x45, 0x6c, +0x20, 0x53, 0x61, 0x6c, 0x76, 0x61, 0x64, 0x6f, 0x72, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x45, 0x63, 0x75, 0x61, +0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x47, 0x75, 0x61, 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x48, 0x6f, 0x6e, 0x64, 0x75, +0x72, 0x61, 0x73, 0x4d, 0xe9, 0x78, 0x69, 0x63, 0x6f, 0x4e, 0x69, 0x63, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x50, 0x61, +0x6e, 0x61, 0x6d, 0xe1, 0x50, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x79, 0x50, 0x65, 0x72, 0xfa, 0x46, 0x69, 0x6c, 0x69, +0x70, 0x69, 0x6e, 0x61, 0x73, 0x45, 0x73, 0x74, 0x61, 0x64, 0x6f, 0x73, 0x20, 0x55, 0x6e, 0x69, 0x64, 0x6f, 0x73, 0x55, +0x72, 0x75, 0x67, 0x75, 0x61, 0x79, 0x56, 0x65, 0x6e, 0x65, 0x7a, 0x75, 0x65, 0x6c, 0x61, 0x49, 0x73, 0x6c, 0x61, 0x73, +0x20, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x61, 0x73, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x6c, 0x61, 0x74, +0x69, 0x6e, 0x6f, 0x61, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x4c, 0x61, 0x74, 0x69, 0x6e, 0x6f, 0x61, 0x6d, +0xe9, 0x72, 0x69, 0x63, 0x61, 0x43, 0x65, 0x75, 0x74, 0x61, 0x20, 0x79, 0x20, 0x4d, 0x65, 0x6c, 0x69, 0x6c, 0x6c, 0x61, +0x4b, 0x69, 0x73, 0x77, 0x61, 0x68, 0x69, 0x6c, 0x69, 0x73, 0x76, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0x53, 0x76, 0x65, 0x72, +0x69, 0x67, 0x65, 0x46, 0x69, 0x6e, 0x6c, 0x61, 0x6e, 0x64, 0xc5, 0x6c, 0x61, 0x6e, 0x64, 0x422, 0x43e, 0x4b7, 0x438, 0x43a, +0x4e3, 0x422, 0x43e, 0x4b7, 0x438, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d, 0xba4, 0xbae, 0xbbf, 0xbb4, 0xbcd, 0xb87, 0xba8, 0xbcd, 0xba4, +0xbbf, 0xbaf, 0xbbe, 0xbae, 0xbb2, 0xbc7, 0xbb7, 0xbbf, 0xbaf, 0xbbe, 0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd, 0xbaa, 0xbc2, 0xbb0, +0xbcd, 0xb87, 0xbb2, 0xb99, 0xbcd, 0xb95, 0xbc8, 0xc24, 0xc46, 0xc32, 0xc41, 0xc17, 0xc41, 0xc2d, 0xc3e, 0xc30, 0xc24, 0x20, 0xc26, 0xc47, +0xc36, 0xc02, 0xe44, 0xe17, 0xe22, 0xf54, 0xf7c, 0xf51, 0xf0b, 0xf66, 0xf90, 0xf51, 0xf0b, 0xf62, 0xf92, 0xfb1, 0xf0b, 0xf53, 0xf42, 0xf62, +0xf92, 0xfb1, 0xf0b, 0xf42, 0xf62, 0xf0b, 0x1275, 0x130d, 0x122d, 0x129b, 0x12a4, 0x122d, 0x1275, 0x122b, 0x6c, 0x65, 0x61, 0x20, 0x66, 0x61, +0x6b, 0x61, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x58, 0x69, 0x74, 0x73, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0xfc, 0x72, 0x6b, 0xe7, +0x65, 0x54, 0xfc, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x47, 0xfc, 0x6e, 0x65, 0x79, 0x20, 0x4b, 0x131, 0x62, 0x72, 0x131, 0x73, +0x20, 0x52, 0x75, 0x6d, 0x20, 0x4b, 0x65, 0x73, 0x69, 0x6d, 0x69, 0x443, 0x43a, 0x440, 0x430, 0x457, 0x43d, 0x441, 0x44c, 0x43a, +0x430, 0x423, 0x43a, 0x440, 0x430, 0x457, 0x43d, 0x430, 0x627, 0x631, 0x62f, 0x648, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x628, +0x6be, 0x627, 0x631, 0x62a, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d, 0x627, +0x648, 0x632, 0x628, 0x6cc, 0x6a9, 0x6f, 0x2bb, 0x7a, 0x62, 0x65, 0x6b, 0x63, 0x68, 0x61, 0x4f, 0x2bb, 0x7a, 0x62, 0x65, 0x6b, +0x69, 0x73, 0x74, 0x6f, 0x6e, 0x54, 0x69, 0x1ebf, 0x6e, 0x67, 0x20, 0x56, 0x69, 0x1ec7, 0x74, 0x56, 0x69, 0x1ec7, 0x74, 0x20, +0x4e, 0x61, 0x6d, 0x43, 0x79, 0x6d, 0x72, 0x61, 0x65, 0x67, 0x79, 0x20, 0x44, 0x65, 0x79, 0x72, 0x6e, 0x61, 0x73, 0x20, +0x55, 0x6e, 0x65, 0x64, 0x69, 0x67, 0x69, 0x73, 0x69, 0x58, 0x68, 0x6f, 0x73, 0x61, 0xc8, 0x64, 0xe8, 0x20, 0x59, 0x6f, +0x72, 0xf9, 0x62, 0xe1, 0x4f, 0x72, 0xed, 0x6c, 0x1eb9, 0x301, 0xe8, 0x64, 0x65, 0x20, 0x4e, 0xe0, 0xec, 0x6a, 0xed, 0x72, +0xed, 0xe0, 0x69, 0x73, 0x69, 0x5a, 0x75, 0x6c, 0x75, 0x69, 0x4e, 0x69, 0x6e, 0x67, 0x69, 0x7a, 0x69, 0x6d, 0x75, 0x20, +0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x6e, 0x79, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x4e, 0x6f, 0x72, 0x65, 0x67, 0x62, 0x6f, +0x73, 0x61, 0x6e, 0x73, 0x6b, 0x69, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x438, 0x47, 0x61, 0x65, 0x6c, 0x67, 0x52, +0x79, 0x77, 0x76, 0x61, 0x6e, 0x65, 0x74, 0x68, 0x20, 0x55, 0x6e, 0x79, 0x73, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x77, 0x65, +0x6b, 0x41, 0x6b, 0x61, 0x6e, 0x47, 0x61, 0x61, 0x6e, 0x61, 0x915, 0x94b, 0x902, 0x915, 0x923, 0x940, 0x49, 0x67, 0x62, 0x6f, +0x4b, 0x69, 0x6b, 0x61, 0x6d, 0x62, 0x61, 0x1265, 0x120a, 0x1295, 0x1275, 0x130d, 0x1228, 0x66, 0x75, 0x72, 0x6c, 0x61, 0x6e, 0x49, +0x74, 0x61, 0x6c, 0x69, 0x65, 0x54, 0x73, 0x68, 0x69, 0x76, 0x65, 0x6e, 0x1e13, 0x61, 0x65, 0x28b, 0x65, 0x67, 0x62, 0x65, +0x47, 0x68, 0x61, 0x6e, 0x61, 0x20, 0x6e, 0x75, 0x74, 0x6f, 0x6d, 0x65, 0x54, 0x6f, 0x67, 0x6f, 0x20, 0x6e, 0x75, 0x74, +0x6f, 0x6d, 0x65, 0x12c8, 0x120b, 0x12ed, 0x1273, 0x1271, 0x2bb, 0x14c, 0x6c, 0x65, 0x6c, 0x6f, 0x20, 0x48, 0x61, 0x77, 0x61, 0x69, +0x2bb, 0x69, 0x2bb, 0x41, 0x6d, 0x65, 0x6c, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x75, 0x69, 0x20, 0x50, 0x16b, 0x20, 0x2bb, 0x49, +0x61, 0x46, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x6f, 0x50, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x61, 0x73, 0x53, 0x63, +0x68, 0x77, 0x69, 0x69, 0x7a, 0x65, 0x72, 0x74, 0xfc, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x53, 0x63, 0x68, 0x77, 0x69, 0x69, +0x7a, 0xa188, 0xa320, 0xa259, 0xa34f, 0xa1e9, 0x69, 0x73, 0x69, 0x4e, 0x64, 0x65, 0x62, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x6f, +0x74, 0x68, 0x6f, 0x20, 0x73, 0x61, 0x20, 0x4c, 0x65, 0x62, 0x6f, 0x61, 0x64, 0x61, 0x76, 0x76, 0x69, 0x73, 0xe1, 0x6d, +0x65, 0x67, 0x69, 0x65, 0x6c, 0x6c, 0x61, 0x4e, 0x6f, 0x72, 0x67, 0x61, 0x53, 0x75, 0x6f, 0x70, 0x6d, 0x61, 0x45, 0x6b, +0x65, 0x67, 0x75, 0x73, 0x69, 0x69, 0x4b, 0x69, 0x74, 0x61, 0x69, 0x74, 0x61, 0x50, 0x75, 0x6c, 0x61, 0x61, 0x72, 0x53, +0x65, 0x6e, 0x65, 0x67, 0x61, 0x61, 0x6c, 0x47, 0x69, 0x6b, 0x75, 0x79, 0x75, 0x4b, 0x69, 0x73, 0x61, 0x6d, 0x70, 0x75, +0x72, 0x73, 0x65, 0x6e, 0x61, 0x4b, 0x69, 0x68, 0x6f, 0x72, 0x6f, 0x6d, 0x62, 0x6f, 0x2d5c, 0x2d30, 0x2d4e, 0x2d30, 0x2d63, 0x2d49, +0x2d56, 0x2d5c, 0x2d4d, 0x2d4e, 0x2d56, 0x2d54, 0x2d49, 0x2d31, 0x74, 0x61, 0x6d, 0x61, 0x7a, 0x69, 0x67, 0x68, 0x74, 0x6c, 0x6d, 0x263, +0x72, 0x69, 0x62, 0x54, 0x61, 0x71, 0x62, 0x61, 0x79, 0x6c, 0x69, 0x74, 0x4c, 0x65, 0x7a, 0x7a, 0x61, 0x79, 0x65, 0x72, +0x52, 0x75, 0x6e, 0x79, 0x61, 0x6e, 0x6b, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x62, 0x65, 0x6e, 0x61, 0x48, 0x75, 0x74, 0x61, +0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x4b, 0x79, 0x69, 0x76, 0x75, 0x6e, 0x6a, 0x6f, 0x62, 0x61, 0x6d, 0x61, 0x6e, 0x61, +0x6b, 0x61, 0x6e, 0x4b, 0x129, 0x65, 0x6d, 0x62, 0x75, 0x13e3, 0x13b3, 0x13a9, 0x13a0, 0x13b9, 0x13f0, 0x13df, 0x6b, 0x72, 0x65, 0x6f, +0x6c, 0x20, 0x6d, 0x6f, 0x72, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x4d, 0x6f, 0x72, 0x69, 0x73, 0x43, 0x68, 0x69, 0x6d, 0x61, +0x6b, 0x6f, 0x6e, 0x64, 0x65, 0x4b, 0x268, 0x6c, 0x61, 0x61, 0x6e, 0x67, 0x69, 0x54, 0x61, 0x61, 0x6e, 0x73, 0x61, 0x6e, +0xed, 0x61, 0x4c, 0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x59, 0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x49, 0x63, 0x68, 0x69, +0x62, 0x65, 0x6d, 0x62, 0x61, 0x6b, 0x61, 0x62, 0x75, 0x76, 0x65, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x75, 0x4b, 0x61, 0x62, +0x75, 0x20, 0x56, 0x65, 0x72, 0x64, 0x69, 0x4b, 0x129, 0x6d, 0x129, 0x72, 0x169, 0x4b, 0x61, 0x6c, 0x65, 0x6e, 0x6a, 0x69, +0x6e, 0x45, 0x6d, 0x65, 0x74, 0x61, 0x62, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x4b, 0x68, 0x6f, 0x65, 0x6b, 0x68, 0x6f, +0x65, 0x67, 0x6f, 0x77, 0x61, 0x62, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x62, 0x4b, 0x69, 0x6d, 0x61, 0x63, 0x68, +0x61, 0x6d, 0x65, 0x4b, 0xf6, 0x6c, 0x73, 0x63, 0x68, 0x44, 0x6f, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61, 0x6e, 0x64, +0x4d, 0x61, 0x61, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69, 0x61, 0x4f, 0x6c, 0x75, 0x73, 0x6f, 0x67, 0x61, 0x4c, 0x75, +0x6c, 0x75, 0x68, 0x69, 0x61, 0x4b, 0x69, 0x70, 0x61, 0x72, 0x65, 0x54, 0x61, 0x64, 0x68, 0x61, 0x6e, 0x69, 0x61, 0x4b, +0x69, 0x74, 0x65, 0x73, 0x6f, 0x4b, 0x65, 0x6e, 0x69, 0x61, 0x4b, 0x6f, 0x79, 0x72, 0x61, 0x20, 0x63, 0x69, 0x69, 0x6e, +0x69, 0x4d, 0x61, 0x61, 0x6c, 0x69, 0x4b, 0x69, 0x72, 0x75, 0x77, 0x61, 0x44, 0x68, 0x6f, 0x6c, 0x75, 0x6f, 0x52, 0x75, +0x6b, 0x69, 0x67, 0x61, 0x54, 0x61, 0x6d, 0x61, 0x7a, 0x69, 0x263, 0x74, 0x4d, 0x65, 0x1e5b, 0x1e5b, 0x75, 0x6b, 0x4b, 0x6f, +0x79, 0x72, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69, 0x4b, 0x69, 0x73, 0x68, 0x61, 0x6d, 0x62, +0x61, 0x61, 0x92c, 0x921, 0x93c, 0x94b, 0x54, 0x73, 0x68, 0x69, 0x6c, 0x75, 0x62, 0x61, 0x44, 0x69, 0x74, 0x75, 0x6e, 0x67, +0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x75, 0x41, 0x67, 0x68, 0x65, 0x6d, 0x4b, 0xe0, 0x6d, 0xe0, 0x6c, +0xfb, 0x14b, 0x181, 0xe0, 0x73, 0xe0, 0x61, 0x4b, 0xe0, 0x6d, 0x25b, 0x300, 0x72, 0xfb, 0x6e, 0x5a, 0x61, 0x72, 0x6d, 0x61, +0x63, 0x69, 0x69, 0x6e, 0x65, 0x4e, 0x69, 0x17e, 0x65, 0x72, 0x64, 0x75, 0xe1, 0x6c, 0xe1, 0x6a, 0x6f, 0x6f, 0x6c, 0x61, +0x53, 0x65, 0x6e, 0x65, 0x67, 0x61, 0x6c, 0x65, 0x77, 0x6f, 0x6e, 0x64, 0x6f, 0x4b, 0x61, 0x6d, 0x259, 0x72, 0xfa, 0x6e, +0x72, 0x69, 0x6b, 0x70, 0x61, 0x6b, 0x61, 0x6d, 0x25b, 0x72, 0xfa, 0x6e, 0x4d, 0x61, 0x6b, 0x75, 0x61, 0x55, 0x6d, 0x6f, +0x7a, 0x61, 0x6d, 0x62, 0x69, 0x6b, 0x69, 0x4d, 0x55, 0x4e, 0x44, 0x41, 0x14a, 0x6b, 0x61, 0x6d, 0x65, 0x72, 0x75, 0x14b, +0x4b, 0x77, 0x61, 0x73, 0x69, 0x6f, 0x4b, 0x61, 0x6d, 0x65, 0x72, 0x75, 0x6e, 0x54, 0x68, 0x6f, 0x6b, 0x20, 0x4e, 0x61, +0x74, 0x68, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x441, 0x430, 0x445, 0x430, 0x20, 0x442, 0x44b, 0x43b, 0x430, 0x49, 0x73, 0x68, 0x69, +0x73, 0x61, 0x6e, 0x67, 0x75, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69, 0x79, 0x61, 0x4b, 0x69, 0x73, 0x77, 0x61, 0x68, +0x69, 0x6c, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x4a, 0x61, 0x6d, 0x68, 0x75, 0x72, 0x69, 0x20, +0x79, 0x61, 0x20, 0x4b, 0x69, 0x64, 0x65, 0x6d, 0x6f, 0x6b, 0x72, 0x61, 0x73, 0x69, 0x61, 0x20, 0x79, 0x61, 0x20, 0x4b, +0x6f, 0x6e, 0x67, 0x6f, 0x54, 0x61, 0x73, 0x61, 0x77, 0x61, 0x71, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69, 0xa559, 0xa524, 0xa55e, +0xa524, 0xa52b, 0xa569, 0x56, 0x61, 0x69, 0x4c, 0x61, 0x69, 0x62, 0x68, 0x69, 0x79, 0x61, 0x57, 0x61, 0x6c, 0x73, 0x65, 0x72, +0x53, 0x63, 0x68, 0x77, 0x69, 0x7a, 0x6e, 0x75, 0x61, 0x73, 0x75, 0x65, 0x4b, 0x65, 0x6d, 0x65, 0x6c, 0xfa, 0x6e, 0x61, +0x73, 0x74, 0x75, 0x72, 0x69, 0x61, 0x6e, 0x75, 0x4e, 0x64, 0x61, 0xa78c, 0x61, 0x4b, 0x61, 0x6d, 0x25b, 0x6c, 0xfb, 0x6e, +0x6b, 0x61, 0x6b, 0x254, 0x4b, 0x61, 0x6d, 0x25b, 0x72, 0x75, 0x6e, 0x6d, 0x65, 0x74, 0x61, 0x2bc, 0x4b, 0x61, 0x6d, 0x61, +0x6c, 0x75, 0x6e, 0x53, 0x68, 0x77, 0xf3, 0x14b, 0xf2, 0x20, 0x6e, 0x67, 0x69, 0x65, 0x6d, 0x62, 0x254, 0x254, 0x6e, 0x4b, +0xe0, 0x6d, 0x61, 0x6c, 0xfb, 0x6d }; static const char language_name_list[] = @@ -6565,6 +6569,7 @@ static const char country_name_list[] = "SouthSudan\0" "Bonaire\0" "SintMaarten\0" +"Kosovo\0" ; static const quint16 country_name_index[] = { @@ -6825,6 +6830,7 @@ static const quint16 country_name_index[] = { 2676, // SouthSudan 2687, // Bonaire 2695, // SintMaarten + 2707, // Kosovo }; static const unsigned char language_code_list[] = @@ -7507,6 +7513,7 @@ static const unsigned char country_code_list[] = "SS\0" // SouthSudan "BQ\0" // Bonaire "SX\0" // SintMaarten +"XK\0" // Kosovo ; // GENERATED PART ENDS HERE diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index 56ed6c7534..34223d5af9 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_SYSTEMLOCALE -class QSystemLocale +class Q_CORE_EXPORT QSystemLocale { public: QSystemLocale(); diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 449fcbca0a..8c15afd9f8 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -557,6 +557,18 @@ public: private: void detach_helper(); + bool isValidIterator(const const_iterator &ci) const + { +#if defined(QT_DEBUG) && !defined(Q_MAP_NO_ITERATOR_DEBUG) + const QMapNodeBase *n = ci.i; + while (n->parent()) + n = n->parent(); + return n->left == d->root(); +#else + Q_UNUSED(ci); + return true; +#endif + } }; template <class Key, class T> @@ -670,6 +682,8 @@ typename QMap<Key, T>::iterator QMap<Key, T>::insert(const_iterator pos, const K if (d->ref.isShared()) return this->insert(akey, avalue); + Q_ASSERT_X(isValidIterator(pos), "QMap::insert", "The specified const_iterator argument 'it' is invalid"); + if (pos == constEnd()) { // Hint is that the Node is larger than (or equal to) the largest value. Node *n = static_cast<Node *>(pos.i->left); @@ -753,6 +767,8 @@ typename QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const_iterator pos, co if (d->ref.isShared()) return this->insertMulti(akey, avalue); + Q_ASSERT_X(isValidIterator(pos), "QMap::insertMulti", "The specified const_iterator argument 'pos' is invalid"); + if (pos == constEnd()) { // Hint is that the Node is larger than (or equal to) the largest value. Node *n = static_cast<Node *>(pos.i->left); @@ -895,6 +911,8 @@ Q_OUTOFLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::erase(iterato if (it == iterator(d->end())) return it; + Q_ASSERT_X(isValidIterator(const_iterator(it)), "QMap::erase", "The specified iterator argument 'it' is invalid"); + Node *n = it.i; ++it; d->deleteNode(n); diff --git a/src/corelib/tools/qpair.h b/src/corelib/tools/qpair.h index 96b1b65e33..9b8691a3d8 100644 --- a/src/corelib/tools/qpair.h +++ b/src/corelib/tools/qpair.h @@ -57,6 +57,19 @@ struct QPair QPair(const T1 &t1, const T2 &t2) : first(t1), second(t2) {} // compiler-generated copy/move ctor/assignment operators are fine! + template <typename TT1, typename TT2> + QPair(const QPair<TT1, TT2> &p) : first(p.first), second(p.second) {} + template <typename TT1, typename TT2> + QPair &operator=(const QPair<TT1, TT2> &p) + { first = p.first; second = p.second; return *this; } +#ifdef Q_COMPILER_RVALUE_REFS + template <typename TT1, typename TT2> + QPair(QPair<TT1, TT2> &&p) : first(std::move(p.first)), second(std::move(p.second)) {} + template <typename TT1, typename TT2> + QPair &operator=(QPair<TT1, TT2> &&p) + { first = std::move(p.first); second = std::move(p.second); return *this; } +#endif + T1 first; T2 second; }; diff --git a/src/corelib/tools/qpair.qdoc b/src/corelib/tools/qpair.qdoc index b0caf1aaf0..dd3df8c464 100644 --- a/src/corelib/tools/qpair.qdoc +++ b/src/corelib/tools/qpair.qdoc @@ -96,6 +96,26 @@ \sa qMakePair() */ +/*! + \fn QPair::QPair(const QPair<TT1, TT2> &p) + \since 5.2 + + Constructs a pair from the other pair \a p, of types TT1 and TT2. This + constructor will fail if \c first cannot be initialized from \c p.first or + if \c second cannot be initialized from \c p.second. + + \sa qMakePair() +*/ + +/*! + \fn QPair &QPair::operator=(const QPair<TT1, TT2> &p) + \since 5.2 + + Copies the pair \a p onto this pair. + + \sa qMakePair() +*/ + /*! \fn bool operator==(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2) \relates QPair diff --git a/src/corelib/tools/qscopedpointer.cpp b/src/corelib/tools/qscopedpointer.cpp index 0848754de5..047fcbfc30 100644 --- a/src/corelib/tools/qscopedpointer.cpp +++ b/src/corelib/tools/qscopedpointer.cpp @@ -95,6 +95,9 @@ QT_BEGIN_NAMESPACE this handler for pointers that were allocated with \c{new []}. \li QScopedPointerPodDeleter - deletes the pointer using \c{free()}. Use this handler for pointers that were allocated with \c{malloc()}. + \li QScopedPointerDeleteLater - deletes a pointer by calling \c{deleteLater()} + on it. Use this handler for pointers to QObject's that are actively + participating in a QEventLoop. \endlist You can pass your own classes as handlers, provided that they have a public @@ -130,6 +133,33 @@ QT_BEGIN_NAMESPACE Constructs this QScopedPointer instance and sets its pointer to \a p. */ +#ifndef Q_QDOC // QTBUG-32675, qdoc can't parse rvalue refs +/*! + \fn QScopedPointer::QScopedPointer(QScopedPointer<T, Cleanup> &&other) + + Move-constructs a QScopedPointer instance, making it point at the same + object that \a other was pointing to. \a other is reset to point to \c{NULL}. + + \since 5.2 +*/ + +/*! + \fn QScopedPointer<T, Cleanup> &operator=(QScopedPointer<T, Cleanup> &&other) + + Move-assigns \a other to this QScopedPointer instance, transferring the + ownership of the managed pointer to this instance. + + If \a other and this instance are actually the same object, this operator + does nothing. + + Otherwise, this instance is set to point to the object \a other + is pointing to, and \a other is set to point to \c{NULL}. + If this instance was pointing to an object, that object is destroyed, + + \since 5.2 +*/ +#endif + /*! \fn QScopedPointer::~QScopedPointer() diff --git a/src/corelib/tools/qscopedpointer.h b/src/corelib/tools/qscopedpointer.h index 2155c56e27..dba37dae23 100644 --- a/src/corelib/tools/qscopedpointer.h +++ b/src/corelib/tools/qscopedpointer.h @@ -83,6 +83,17 @@ struct QScopedPointerPodDeleter static inline void cleanup(void *pointer) { if (pointer) free(pointer); } }; +#ifndef QT_NO_QOBJECT +template <typename T> +struct QScopedPointerObjectDeleteLater +{ + static inline void cleanup(T *pointer) { if (pointer) pointer->deleteLater(); } +}; + +class QObject; +typedef QScopedPointerObjectDeleteLater<QObject> QScopedPointerDeleteLater; +#endif + template <typename T, typename Cleanup = QScopedPointerDeleter<T> > class QScopedPointer { @@ -98,6 +109,19 @@ public: Cleanup::cleanup(oldD); } +#ifdef Q_COMPILER_RVALUE_REFS + inline QScopedPointer(QScopedPointer<T, Cleanup> &&other) + : d(other.take()) + { + } + + inline QScopedPointer<T, Cleanup> &operator=(QScopedPointer<T, Cleanup> &&other) + { + reset(other.take()); + return *this; + } +#endif + inline T &operator*() const { Q_ASSERT(d); diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index d5c3637293..ad2f91b983 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -70,6 +70,7 @@ public: inline QSet<T> &operator=(const QSet<T> &other) { q_hash = other.q_hash; return *this; } #ifdef Q_COMPILER_RVALUE_REFS + inline QSet(QSet &&other) : q_hash(qMove(other.q_hash)) {} inline QSet<T> &operator=(QSet<T> &&other) { qSwap(q_hash, other.q_hash); return *this; } #endif @@ -180,7 +181,10 @@ public: inline const_iterator cend() const { return q_hash.end(); } inline const_iterator constEnd() const { return q_hash.constEnd(); } iterator erase(iterator i) - { return q_hash.erase(reinterpret_cast<typename Hash::iterator &>(i)); } + { + Q_ASSERT_X(isValidIterator(i), "QSet::erase", "The specified const_iterator argument 'i' is invalid"); + return q_hash.erase(reinterpret_cast<typename Hash::iterator &>(i)); + } // more Qt typedef iterator Iterator; @@ -233,6 +237,10 @@ public: private: Hash q_hash; + bool isValidIterator(const iterator &i) const + { + return q_hash.isValidIterator(reinterpret_cast<const typename Hash::iterator&>(i)); + } }; template <class T> @@ -253,8 +261,16 @@ Q_INLINE_TEMPLATE QSet<T> &QSet<T>::unite(const QSet<T> &other) template <class T> Q_INLINE_TEMPLATE QSet<T> &QSet<T>::intersect(const QSet<T> &other) { - QSet<T> copy1(*this); - QSet<T> copy2(other); + QSet<T> copy1; + QSet<T> copy2; + if (size() <= other.size()) { + copy1 = *this; + copy2 = other; + } else { + copy1 = other; + copy2 = *this; + *this = copy1; + } typename QSet<T>::const_iterator i = copy1.constEnd(); while (i != copy1.constBegin()) { --i; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 37d28b0904..36bd61098a 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -820,17 +820,43 @@ const QString::Null QString::null = { }; */ /*! + \typedef QString::size_type + + The QString::size_type typedef provides an STL-style type for sizes (int). +*/ + +/*! + \typedef QString::difference_type + + The QString::size_type typedef provides an STL-style type for difference between pointers. +*/ + +/*! \typedef QString::const_reference The QString::const_reference typedef provides an STL-style - const reference for QString. + const reference for a QString element (QChar). */ /*! \typedef QString::reference - The QString::const_reference typedef provides an STL-style - reference for QString. + The QString::reference typedef provides an STL-style + reference for a QString element (QChar). */ + +/*! + \typedef QString::const_pointer + + The QString::const_pointer typedef provides an STL-style + const pointer to a QString element (QChar). +*/ +/*! + \typedef QString::pointer + + The QString::const_pointer typedef provides an STL-style + pointer to a QString element (QChar). +*/ + /*! \typedef QString::value_type diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index d8aaa929dc..7010a954b4 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -657,8 +657,12 @@ public: const_iterator constEnd() const; // STL compatibility + typedef int size_type; + typedef qptrdiff difference_type; typedef const QChar & const_reference; typedef QChar & reference; + typedef QChar *pointer; + typedef const QChar *const_pointer; typedef QChar value_type; inline void push_back(QChar c) { append(c); } inline void push_back(const QString &s) { append(s); } diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index 825e05ae1b..d9b85c4173 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -192,6 +192,11 @@ private: qint64 q_for_alignment_1; double q_for_alignment_2; }; + + bool isValidIterator(const const_iterator &i) const + { + return (i <= constEnd()) && (constBegin() <= i); + } }; template <class T, int Prealloc> @@ -355,6 +360,8 @@ inline void QVarLengthArray<T, Prealloc>::replace(int i, const T &t) template <class T, int Prealloc> Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, size_type n, const T &t) { + Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid"); + int offset = int(before - ptr); if (n != 0) { resize(s + n); @@ -382,6 +389,9 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA template <class T, int Prealloc> Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator abegin, const_iterator aend) { + 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"); + int f = int(abegin - ptr); int l = int(aend - ptr); int n = l - f; diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 489ee821b9..de64d7a670 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -238,7 +238,10 @@ private: void defaultConstruct(T *from, T *to); void copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom); void destruct(T *from, T *to); - + bool isValidIterator(const iterator &i) const + { + return (i <= d->end()) && (d->begin() <= i); + } class AlignmentDummy { Data header; T array[1]; }; }; @@ -578,6 +581,8 @@ inline void QVector<T>::removeLast() template <typename T> typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t) { + Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid"); + int offset = std::distance(d->begin(), before); if (n != 0) { const T copy(t); @@ -611,6 +616,9 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c template <typename T> typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend) { + Q_ASSERT_X(isValidIterator(abegin), "QVector::erase", "The specified iterator argument 'abegin' is invalid"); + Q_ASSERT_X(isValidIterator(aend), "QVector::erase", "The specified iterator argument 'aend' is invalid"); + const int itemsToErase = aend - abegin; if (!itemsToErase) diff --git a/src/dbus/doc/qtdbus.qdocconf b/src/dbus/doc/qtdbus.qdocconf index b47e02ff43..1233ae3d47 100644 --- a/src/dbus/doc/qtdbus.qdocconf +++ b/src/dbus/doc/qtdbus.qdocconf @@ -20,7 +20,7 @@ excludedirs += ../../../examples/widgets/doc examplesinstallpath = dbus -depends += qtcore +depends += qtdoc qtcore # The following parameters are for creating a qhp file, the qhelpgenerator # program can convert the qhp file into a qch file which can be opened in @@ -49,3 +49,6 @@ qhp.QtDBus.subprojects.classes.title = C++ Classes qhp.QtDBus.subprojects.classes.indexTitle = Qt D-Bus C++ Classes qhp.QtDBus.subprojects.classes.selectors = class fake:headerfile qhp.QtDBus.subprojects.classes.sortPages = true + +navigation.landingpage = "Qt D-Bus" +navigation.cppclassespage = "Qt D-Bus C++ Classes" diff --git a/src/dbus/doc/src/qtdbus-module.qdoc b/src/dbus/doc/src/qtdbus-module.qdoc index fe3b11b926..ac9cac428b 100644 --- a/src/dbus/doc/src/qtdbus-module.qdoc +++ b/src/dbus/doc/src/qtdbus-module.qdoc @@ -32,6 +32,7 @@ to perform Inter-Process Communication using the \l{D-Bus} protocol. \ingroup modules + \qtvariable dbus \target The QDBus compiler diff --git a/src/dbus/qdbusabstractadaptor.cpp b/src/dbus/qdbusabstractadaptor.cpp index 02ff40068b..04accee037 100644 --- a/src/dbus/qdbusabstractadaptor.cpp +++ b/src/dbus/qdbusabstractadaptor.cpp @@ -307,15 +307,18 @@ void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void ** // break down the parameter list QVector<int> types; - int inputCount = qDBusParametersForMethod(mm, types); - if (inputCount == -1) + QString errorMsg; + int inputCount = qDBusParametersForMethod(mm, types, errorMsg); + if (inputCount == -1) { // invalid signal signature - // qDBusParametersForMethod has already complained + qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s: %s", + senderMetaObject->className(), mm.methodSignature().constData(), + qPrintable(errorMsg)); return; + } if (inputCount + 1 != types.count() || types.at(inputCount) == QDBusMetaTypeId::message()) { // invalid signal signature - // qDBusParametersForMethod has not yet complained about this one qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s", senderMetaObject->className(), mm.methodSignature().constData()); return; diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index c702de141a..013896bd32 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -341,9 +341,9 @@ public: }; // in qdbusmisc.cpp -extern int qDBusParametersForMethod(const QMetaMethod &mm, QVector<int> &metaTypes); +extern int qDBusParametersForMethod(const QMetaMethod &mm, QVector<int> &metaTypes, QString &errorMsg); #endif // QT_BOOTSTRAPPED -extern Q_DBUS_EXPORT int qDBusParametersForMethod(const QList<QByteArray> ¶meters, QVector<int>& metaTypes); +extern Q_DBUS_EXPORT int qDBusParametersForMethod(const QList<QByteArray> ¶meters, QVector<int>& metaTypes, QString &errorMsg); extern Q_DBUS_EXPORT bool qDBusCheckAsyncTag(const char *tag); #ifndef QT_BOOTSTRAPPED extern bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name); diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 3f25f02bee..e5f3fbdc53 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -721,7 +721,8 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags, if (isAsync && returnType != QMetaType::Void) continue; - int inputCount = qDBusParametersForMethod(mm, metaTypes); + QString errorMsg; + int inputCount = qDBusParametersForMethod(mm, metaTypes, errorMsg); if (inputCount == -1) continue; // problem parsing @@ -1312,7 +1313,8 @@ int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedN if (midx == -1) return -1; - int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params); + QString errorMsg; + int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params, errorMsg); if ( inputCount == -1 || inputCount + 1 != params.count() ) return -1; // failed to parse or invalid arguments or output arguments diff --git a/src/dbus/qdbusmisc.cpp b/src/dbus/qdbusmisc.cpp index d28d5598c6..5d3512845a 100644 --- a/src/dbus/qdbusmisc.cpp +++ b/src/dbus/qdbusmisc.cpp @@ -131,14 +131,14 @@ bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name) // metaTypes.count() >= retval + 1 in all cases // // sig must be the normalised signature for the method -int qDBusParametersForMethod(const QMetaMethod &mm, QVector<int> &metaTypes) +int qDBusParametersForMethod(const QMetaMethod &mm, QVector<int> &metaTypes, QString &errorMsg) { - return qDBusParametersForMethod(mm.parameterTypes(), metaTypes); + return qDBusParametersForMethod(mm.parameterTypes(), metaTypes, errorMsg); } #endif // QT_BOOTSTRAPPED -int qDBusParametersForMethod(const QList<QByteArray> ¶meterTypes, QVector<int>& metaTypes) +int qDBusParametersForMethod(const QList<QByteArray> ¶meterTypes, QVector<int>& metaTypes, QString &errorMsg) { QDBusMetaTypeId::init(); metaTypes.clear(); @@ -151,8 +151,7 @@ int qDBusParametersForMethod(const QList<QByteArray> ¶meterTypes, QVector<in for ( ; it != end; ++it) { const QByteArray &type = *it; if (type.endsWith('*')) { - //qWarning("Could not parse the method '%s'", mm.methodSignature().constData()); - // pointer? + errorMsg = QLatin1String("Pointers are not supported: ") + QLatin1String(type); return -1; } @@ -162,8 +161,7 @@ int qDBusParametersForMethod(const QList<QByteArray> ¶meterTypes, QVector<in int id = QMetaType::type(basictype); if (id == 0) { - //qWarning("Could not parse the method '%s'", mm.methodSignature().constData()); - // invalid type in method parameter list + errorMsg = QLatin1String("Unregistered output type in parameter list: ") + QLatin1String(type); return -1; } else if (QDBusMetaType::typeToSignature(id) == 0) return -1; @@ -174,22 +172,22 @@ int qDBusParametersForMethod(const QList<QByteArray> ¶meterTypes, QVector<in } if (seenMessage) { // && !type.endsWith('&') - //qWarning("Could not parse the method '%s'", mm.methodSignature().constData()); - // non-output parameters after message or after output params + errorMsg = QLatin1String("Invalid method, non-output parameters after message or after output parameters: ") + QLatin1String(type); return -1; // not allowed } int id = QMetaType::type(type); if (id == QMetaType::UnknownType) { - //qWarning("Could not parse the method '%s'", mm.methodSignature().constData()); - // invalid type in method parameter list + errorMsg = QLatin1String("Unregistered input type in parameter list: ") + QLatin1String(type); return -1; } if (id == QDBusMetaTypeId::message()) seenMessage = true; - else if (QDBusMetaType::typeToSignature(id) == 0) + else if (QDBusMetaType::typeToSignature(id) == 0) { + errorMsg = QLatin1String("Type not registered with QtDBus in parameter list: ") + QLatin1String(type); return -1; + } metaTypes.append(id); ++inputCount; diff --git a/src/dbus/qdbusxmlgenerator.cpp b/src/dbus/qdbusxmlgenerator.cpp index 8c822162e4..c724ac573a 100644 --- a/src/dbus/qdbusxmlgenerator.cpp +++ b/src/dbus/qdbusxmlgenerator.cpp @@ -41,6 +41,7 @@ #include <QtCore/qmetaobject.h> #include <QtCore/qstringlist.h> +#include <QtCore/qdebug.h> #include "qdbusinterface_p.h" // for ANNOTATION_NO_WAIT #include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_* @@ -159,17 +160,24 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid) xml += QString::fromLatin1(" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n") .arg(typeNameToXml(QMetaType::typeName(typeId))); - } else + } else { + qWarning() << "Unsupported return type" << typeId << QMetaType::typeName(typeId) << "in method" << mm.name(); continue; + } } - else if (typeId == QMetaType::UnknownType) + else if (typeId == QMetaType::UnknownType) { + qWarning() << "Invalid return type in method" << mm.name(); continue; // wasn't a valid type + } QList<QByteArray> names = mm.parameterNames(); QVector<int> types; - int inputCount = qDBusParametersForMethod(mm, types); - if (inputCount == -1) + QString errorMsg; + int inputCount = qDBusParametersForMethod(mm, types, errorMsg); + if (inputCount == -1) { + qWarning() << "Skipped method" << mm.name() << ":" << qPrintable(errorMsg); continue; // invalid form + } if (isSignal && inputCount + 1 != types.count()) continue; // signal with output arguments? if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message()) diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf index 5073dd7f0f..ed30172376 100644 --- a/src/gui/doc/qtgui.qdocconf +++ b/src/gui/doc/qtgui.qdocconf @@ -48,3 +48,6 @@ exampledirs += ../../../examples/gui \ imagedirs += images \ ../../../examples/gui/doc/images \ ../../../doc/src/images \ + +navigation.landingpage = "Qt GUI" +navigation.cppclassespage = "Qt GUI C++ Classes" diff --git a/src/gui/doc/src/qtgui.qdoc b/src/gui/doc/src/qtgui.qdoc index 6c3e9a4938..75c74c8072 100644 --- a/src/gui/doc/src/qtgui.qdoc +++ b/src/gui/doc/src/qtgui.qdoc @@ -29,6 +29,7 @@ \module QtGui \title Qt GUI C++ Classes \ingroup modules + \qtvariable gui \brief The Qt GUI module provides the basic enablers for graphical applications written with Qt. @@ -172,11 +173,3 @@ \endlist \endlist */ - -/*! - \group events - \title Event Classes - \ingroup groups - - \brief Classes that provide UI and input events. -*/ diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index cb4e45f1d0..c03d9b8e5d 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -781,6 +781,8 @@ bool QBmpHandler::write(const QImage &img) case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB6666_Premultiplied: case QImage::Format_ARGB4444_Premultiplied: + case QImage::Format_RGBA8888: + case QImage::Format_RGBA8888_Premultiplied: image = img.convertToFormat(QImage::Format_ARGB32); break; case QImage::Format_RGB16: @@ -788,6 +790,7 @@ bool QBmpHandler::write(const QImage &img) case QImage::Format_RGB666: case QImage::Format_RGB555: case QImage::Format_RGB444: + case QImage::Format_RGBX8888: image = img.convertToFormat(QImage::Format_RGB32); break; default: diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index aef7324171..cb508ae6c7 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -1068,7 +1068,6 @@ void QIcon::setThemeName(const QString &name) */ QString QIcon::themeName() { - QIconLoader::instance()->ensureInitialized(); return QIconLoader::instance()->themeName(); } diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h index e81bea69d6..f1a78b508c 100644 --- a/src/gui/image/qicon.h +++ b/src/gui/image/qicon.h @@ -62,6 +62,10 @@ public: QIcon(); QIcon(const QPixmap &pixmap); QIcon(const QIcon &other); +#ifdef Q_COMPILER_RVALUE_REFS + QIcon(QIcon &&other) + :d(0) { qSwap(d, other.d); } +#endif explicit QIcon(const QString &fileName); // file or resource name explicit QIcon(QIconEngine *engine); ~QIcon(); diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index 105dc26c9b..d202d62957 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -128,6 +128,7 @@ void QIconLoader::ensureInitialized() QIconLoader *QIconLoader::instance() { + iconLoaderInstance()->ensureInitialized(); return iconLoaderInstance(); } @@ -368,17 +369,14 @@ bool QIconLoaderEngine::hasIcon() const // Lazily load the icon void QIconLoaderEngine::ensureLoaded() { - - iconLoaderInstance()->ensureInitialized(); - - if (!(iconLoaderInstance()->themeKey() == m_key)) { + if (!(QIconLoader::instance()->themeKey() == m_key)) { while (!m_entries.isEmpty()) delete m_entries.takeLast(); Q_ASSERT(m_entries.size() == 0); - m_entries = iconLoaderInstance()->loadIcon(m_iconName); - m_key = iconLoaderInstance()->themeKey(); + m_entries = QIconLoader::instance()->loadIcon(m_iconName); + m_key = QIconLoader::instance()->themeKey(); } } @@ -565,7 +563,7 @@ void QIconLoaderEngine::virtual_hook(int id, void *data) { QIconEngine::AvailableSizesArgument &arg = *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data); - const QList<QIconDirInfo> directoryKey = iconLoaderInstance()->theme().keyList(); + const QList<QIconDirInfo> directoryKey = QIconLoader::instance()->theme().keyList(); arg.sizes.clear(); // Gets all sizes from the DirectoryInfo entries diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 98f3aeeeb9..8e5f6391a7 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -212,6 +212,16 @@ bool QImageData::checkForAlphaPixels() const } } break; + case QImage::Format_RGBA8888: + case QImage::Format_RGBA8888_Premultiplied: { + uchar *bits = data; + for (int y=0; y<height && !has_alpha_pixels; ++y) { + for (int x=0; x<width; ++x) + has_alpha_pixels |= bits[x*4+3] != 0xff; + bits += bytes_per_line; + } + } break; + case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB8565_Premultiplied: { uchar *bits = data; @@ -621,9 +631,9 @@ bool QImageData::checkForAlphaPixels() const /*! \enum QImage::Format - The following image formats are available in Qt. Values greater - than QImage::Format_RGB16 were added in Qt 4.4. See the notes - after the table. + The following image formats are available in Qt. Values from Format_ARGB8565_Premultiplied + to Format_ARGB4444_Premultiplied were added in Qt 4.4. Values Format_RGBX8888, Format_RGBA8888 + and Format_RGBA8888_Premultiplied were added in Qt 5.2. See the notes after the table. \value Format_Invalid The image is invalid. \value Format_Mono The image is stored using 1-bit per pixel. Bytes are @@ -665,6 +675,15 @@ bool QImageData::checkForAlphaPixels() const The unused bits are always zero. \value Format_ARGB4444_Premultiplied The image is stored using a premultiplied 16-bit ARGB format (4-4-4-4). + \value Format_RGBX8888 The image is stored using a 32-bit byte-ordered RGB(x) format (8-8-8-8). + This is the same as the Format_RGBA8888 except alpha must always be 255. + \value Format_RGBA8888 The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8). + Unlike ARGB32 this is a byte-ordered format, which means the 32bit + encoding differs between big endian and little endian architectures, + being respectively (0xRRGGBBAA) and (0xAABBGGRR). The order of the colors + is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA. + \value Format_RGBA8888_Premultiplied The image is stored using a + premultiplied 32-bit byte-ordered RGBA format (8-8-8-8). \note Drawing into a QImage with QImage::Format_Indexed8 is not supported. @@ -1663,9 +1682,12 @@ void QImage::fill(uint pixel) return; } - if (d->format == Format_RGB32) + if (d->format == Format_RGB32 || d->format == Format_RGBX8888) pixel |= 0xff000000; + if (d->format == Format_RGBX8888 || d->format == Format_RGBA8888 || d->format == Format_RGBA8888_Premultiplied) + pixel = ARGB2RGBA(pixel); + qt_rectfill<uint>(reinterpret_cast<uint*>(d->data), pixel, 0, 0, d->width, d->height, d->bytes_per_line); } @@ -1716,7 +1738,7 @@ void QImage::fill(const QColor &color) if (d->depth == 32) { uint pixel = color.rgba(); - if (d->format == QImage::Format_ARGB32_Premultiplied) + if (d->format == QImage::Format_ARGB32_Premultiplied || d->format == QImage::Format_RGBA8888_Premultiplied) pixel = PREMUL(pixel); fill((uint) pixel); @@ -1871,8 +1893,8 @@ typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFla static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(src->format == QImage::Format_ARGB32); - Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888); + Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied || dest->format == QImage::Format_RGBA8888_Premultiplied); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); @@ -1912,6 +1934,191 @@ static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversio return true; } +static void convert_ARGB_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32); + Q_ASSERT(dest->format == QImage::Format_RGBX8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(0xff000000 | *src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_ARGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_ARGB32_Premultiplied); + + const int pad = (data->bytes_per_line >> 2) - data->width; + quint32 *rgb_data = (quint32 *) data->data; + + for (int i = 0; i < data->height; ++i) { + const quint32 *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = ARGB2RGBA(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + if (data->format == QImage::Format_ARGB32) + data->format = QImage::Format_RGBA8888; + else + data->format = QImage::Format_RGBA8888_Premultiplied; + return true; +} + +static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32); + Q_ASSERT(dest->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(PREMUL(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = RGBA2ARGB(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied); + + const int pad = (data->bytes_per_line >> 2) - data->width; + QRgb *rgb_data = (QRgb *) data->data; + + for (int i = 0; i < data->height; ++i) { + const QRgb *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = RGBA2ARGB(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + if (data->format == QImage::Format_RGBA8888_Premultiplied) + data->format = QImage::Format_ARGB32_Premultiplied; + else if (data->format == QImage::Format_RGBX8888) + data->format = QImage::Format_RGB32; + else + data->format = QImage::Format_ARGB32; + return true; +} + +static void convert_RGBA_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888); + Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = PREMUL(RGBA2ARGB(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGBA8888); + + const int pad = (data->bytes_per_line >> 2) - data->width; + QRgb *rgb_data = (QRgb *) data->data; + + for (int i = 0; i < data->height; ++i) { + const QRgb *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = PREMUL(RGBA2ARGB(*rgb_data)); + ++rgb_data; + } + rgb_data += pad; + } + data->format = QImage::Format_ARGB32_Premultiplied; + return true; +} + static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) { Q_ASSERT(data->format == QImage::Format_Indexed8); @@ -2099,8 +2306,8 @@ static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFl static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_ARGB32); + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); @@ -2123,20 +2330,164 @@ static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt: static void convert_ARGB_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_RGBX8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = 0xff000000 | INV_PREMUL(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_ARGB_PM_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGBX8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(0xff000000 | INV_PREMUL(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_ARGB_PM_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGBA8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(INV_PREMUL(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBX8888); Q_ASSERT(dest->format == QImage::Format_RGB32); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); const int src_pad = (src->bytes_per_line >> 2) - src->width; const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const uint *src_data = (const uint *)src->data; + uint *dest_data = (uint *)dest->data; + + for (int i = 0; i < src->height; ++i) { + const uint *end = src_data + src->width; + while (src_data < end) { + *dest_data = RGBA2ARGB(*src_data) | 0xff000000; + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGB32); + Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const uint *src_data = (const uint *)src->data; + uint *dest_data = (uint *)dest->data; + + for (int i = 0; i < src->height; ++i) { + const uint *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(*src_data | 0xff000000); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_ARGB32); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; const QRgb *src_data = (QRgb *) src->data; QRgb *dest_data = (QRgb *) dest->data; for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = 0xff000000 | INV_PREMUL(*src_data); + *dest_data = INV_PREMUL(RGBA2ARGB(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGB32); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = 0xff000000 | INV_PREMUL(RGBA2ARGB(*src_data)); ++src_data; ++dest_data; } @@ -2188,6 +2539,33 @@ static void mask_alpha_converter(QImageData *dest, const QImageData *src, Qt::Im } } +static void mask_alpha_converter_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) +{ +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + return mask_alpha_converter(dest, src, flags); +#else + Q_UNUSED(flags); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const uint *src_data = (const uint *)src->data; + uint *dest_data = (uint *)dest->data; + + for (int i = 0; i < src->height; ++i) { + const uint *end = src_data + src->width; + while (src_data < end) { + *dest_data = *src_data | 0x000000ff; + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +#endif +} + static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format) { QVector<QRgb> colorTable = ctbl; @@ -2941,6 +3319,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_Mono @@ -2960,6 +3341,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_MonoLSB @@ -2979,6 +3363,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_Indexed8 @@ -2998,7 +3385,10 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat convert_generic, convert_generic, convert_generic, - convert_generic + convert_generic, + convert_RGB_to_RGBA, + convert_RGB_to_RGBA, + convert_RGB_to_RGBA }, // Format_RGB32 { @@ -3017,7 +3407,10 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat convert_generic, convert_generic, convert_generic, - convert_generic + convert_generic, + convert_ARGB_to_RGBx, + convert_ARGB_to_RGBA, + convert_ARGB_to_RGBA_PM, }, // Format_ARGB32 { @@ -3036,7 +3429,10 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, + convert_ARGB_PM_to_RGBx, + convert_ARGB_PM_to_RGBA, + convert_ARGB_to_RGBA, }, // Format_ARGB32_Premultiplied { @@ -3059,6 +3455,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_RGB16 @@ -3078,6 +3477,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_ARGB8565_Premultiplied @@ -3097,6 +3499,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_RGB666 @@ -3116,6 +3521,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_ARGB6666_Premultiplied @@ -3139,6 +3547,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_RGB555 @@ -3158,6 +3569,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_ARGB8555_Premultiplied @@ -3177,6 +3591,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_RGB888 @@ -3196,6 +3613,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, + 0, 0 }, // Format_RGB444 @@ -3215,20 +3635,97 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + 0, + 0, 0 - } // Format_ARGB4444_Premultiplied + }, // Format_ARGB4444_Premultiplied + { + 0, + 0, + 0, + 0, + convert_RGBA_to_RGB, + convert_RGBA_to_ARGB, + convert_RGBA_to_ARGB_PM, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + mask_alpha_converter_RGBx, + mask_alpha_converter_RGBx, + }, // Format_RGBX8888 + { + 0, + 0, + 0, + 0, + convert_RGBA_to_RGB, + convert_RGBA_to_ARGB, + convert_RGBA_to_ARGB_PM, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + mask_alpha_converter_RGBx, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + 0, + convert_ARGB_to_ARGB_PM, +#else + 0, + 0 +#endif + }, // Format_RGBA8888 + + { + 0, + 0, + 0, + 0, + convert_RGBA_PM_to_RGB, + convert_RGBA_PM_to_ARGB, + convert_RGBA_to_ARGB, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + convert_ARGB_PM_to_RGB, + convert_ARGB_PM_to_ARGB, + 0, +#else + 0, + 0, + 0 +#endif + } // Format_RGBA8888_Premultiplied }; static InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 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 }, // Format_Mono { - 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 }, // Format_MonoLSB { 0, @@ -3247,6 +3744,9 @@ static InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, + 0, + 0, + 0, }, // Format_Indexed8 { 0, @@ -3265,7 +3765,10 @@ static InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - }, // Format_ARGB32 + 0, + 0, + 0, + }, // Format_RGB32 { 0, 0, @@ -3283,37 +3786,118 @@ static InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, + 0, + convert_ARGB_to_RGBA_inplace, + 0, }, // Format_ARGB32 { - 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, + convert_ARGB_to_RGBA_inplace }, // Format_ARGB32_Premultiplied { - 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 }, // Format_RGB16 { - 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 }, // Format_ARGB8565_Premultiplied { - 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 }, // Format_RGB666 { - 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 }, // Format_ARGB6666_Premultiplied { - 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 }, // Format_RGB555 { - 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 }, // Format_ARGB8555_Premultiplied { - 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 }, // Format_RGB888 { - 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 }, // Format_RGB444 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - } // Format_ARGB4444_Premultiplied + 0, + 0, + 0, + 0, + 0, + convert_RGBA_to_ARGB_inplace, + convert_RGBA_to_ARGB_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_RGBX8888 + { + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGBA_to_ARGB_inplace, + convert_RGBA_to_ARGB_PM_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_RGBA8888 + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGBA_to_ARGB_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + } // Format_RGBA8888_Premultiplied }; void qInitImageConversions() @@ -3633,6 +4217,10 @@ QRgb QImage::pixel(int x, int y) const case Format_ARGB32: // Keep old behaviour. case Format_ARGB32_Premultiplied: return reinterpret_cast<const QRgb *>(s)[x]; + case Format_RGBX8888: + case Format_RGBA8888: // Match ARGB32 behavior. + case Format_RGBA8888_Premultiplied: + return RGBA2ARGB(reinterpret_cast<const quint32 *>(s)[x]); case Format_RGB16: return qConvertRgb16To32(reinterpret_cast<const quint16 *>(s)[x]); default: @@ -3716,6 +4304,13 @@ void QImage::setPixel(int x, int y, uint index_or_rgb) case Format_RGB16: ((quint16 *)s)[x] = qConvertRgb32To16(INV_PREMUL(index_or_rgb)); return; + case Format_RGBX8888: + ((uint *)s)[x] = ARGB2RGBA(index_or_rgb | 0xff000000); + return; + case Format_RGBA8888: + case Format_RGBA8888_Premultiplied: + ((uint *)s)[x] = ARGB2RGBA(index_or_rgb); + return; case Format_Invalid: case NImageFormats: Q_ASSERT(false); @@ -3756,6 +4351,11 @@ bool QImage::allGray() const case Format_RGB32: case Format_ARGB32: case Format_ARGB32_Premultiplied: +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + case Format_RGBX8888: + case Format_RGBA8888: + case Format_RGBA8888_Premultiplied: +#endif for (int j = 0; j < d->height; ++j) { const QRgb *b = (const QRgb *)constScanLine(j); for (int i = 0; i < d->width; ++i) { @@ -4330,6 +4930,11 @@ QImage QImage::rgbSwapped() const case Format_RGB32: case Format_ARGB32: case Format_ARGB32_Premultiplied: +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + case Format_RGBX8888: + case Format_RGBA8888: + case Format_RGBA8888_Premultiplied: +#endif res = QImage(d->width, d->height, d->format); QIMAGE_SANITYCHECK_MEMORY(res); for (int i = 0; i < d->height; i++) { @@ -5373,7 +5978,11 @@ QImage QImage::alphaChannel() const } } else { QImage alpha32 = *this; - if (d->format != Format_ARGB32 && d->format != Format_ARGB32_Premultiplied) + bool canSkipConversion = (d->format == Format_ARGB32 || d->format == Format_ARGB32_Premultiplied); +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + canSkipConversion = canSkipConversion || (d->format == Format_RGBA8888 || d->format == Format_RGBA8888_Premultiplied); +#endif + if (!canSkipConversion) alpha32 = convertToFormat(Format_ARGB32); const uchar *src_data = alpha32.d->data; @@ -5408,6 +6017,8 @@ bool QImage::hasAlphaChannel() const || d->format == Format_ARGB8555_Premultiplied || d->format == Format_ARGB6666_Premultiplied || d->format == Format_ARGB4444_Premultiplied + || d->format == Format_RGBA8888 + || d->format == Format_RGBA8888_Premultiplied || (d->has_alpha_clut && (d->format == Format_Indexed8 || d->format == Format_Mono || d->format == Format_MonoLSB))); @@ -5434,6 +6045,7 @@ int QImage::bitPlaneCount() const case QImage::Format_Invalid: break; case QImage::Format_RGB32: + case QImage::Format_RGBX8888: bpc = 24; break; case QImage::Format_RGB666: @@ -5457,9 +6069,11 @@ int QImage::bitPlaneCount() const static QImage smoothScaled(const QImage &source, int w, int h) { QImage src = source; - if (src.format() == QImage::Format_ARGB32) - src = src.convertToFormat(QImage::Format_ARGB32_Premultiplied); - else if (src.depth() < 32) { + bool canSkipConversion = (src.format() == QImage::Format_RGB32 || src.format() == QImage::Format_ARGB32_Premultiplied); +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + canSkipConversion = canSkipConversion || (src.format() == QImage::Format_RGBX8888 || src.format() == QImage::Format_RGBA8888_Premultiplied); +#endif + if (!canSkipConversion) { if (src.hasAlphaChannel()) src = src.convertToFormat(QImage::Format_ARGB32_Premultiplied); else @@ -5480,6 +6094,9 @@ static QImage rotated90(const QImage &image) { case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + case QImage::Format_RGBA8888_Premultiplied: qt_memrotate270(reinterpret_cast<const quint32*>(image.bits()), w, h, image.bytesPerLine(), reinterpret_cast<quint32*>(out.bits()), @@ -5539,6 +6156,9 @@ static QImage rotated270(const QImage &image) { case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + case QImage::Format_RGBA8888_Premultiplied: qt_memrotate90(reinterpret_cast<const quint32*>(image.bits()), w, h, image.bytesPerLine(), reinterpret_cast<quint32*>(out.bits()), @@ -5684,6 +6304,9 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode case QImage::Format_RGB444: target_format = Format_ARGB4444_Premultiplied; break; + case QImage::Format_RGBX8888: + target_format = Format_RGBA8888_Premultiplied; + break; default: target_format = Format_ARGB32_Premultiplied; break; diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 50d4bc7666..02f0c18243 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -110,6 +110,9 @@ public: Format_RGB888, Format_RGB444, Format_ARGB4444_Premultiplied, + Format_RGBX8888, + Format_RGBA8888, + Format_RGBA8888_Premultiplied, #if 0 // reserved for future use Format_RGB15, @@ -139,6 +142,11 @@ public: explicit QImage(const QString &fileName, const char *format = 0); QImage(const QImage &); +#ifdef Q_COMPILER_RVALUE_REFS + inline QImage(QImage &&other) + : QPaintDevice(), d(0) + { qSwap(d, other.d); } +#endif ~QImage(); QImage &operator=(const QImage &); diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 18c686e917..36f117df60 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -128,6 +128,9 @@ inline int qt_depthForFormat(QImage::Format format) case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + case QImage::Format_RGBA8888_Premultiplied: depth = 32; break; case QImage::Format_RGB555: diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 6fc41df77c..39f63a620c 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -274,12 +274,15 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy case QImage::Format_RGB555: case QImage::Format_RGB888: case QImage::Format_RGB444: + case QImage::Format_RGBX8888: image = image.convertToFormat(QImage::Format_RGB32); break; case QImage::Format_ARGB8565_Premultiplied: case QImage::Format_ARGB6666_Premultiplied: case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB4444_Premultiplied: + case QImage::Format_RGBA8888: + case QImage::Format_RGBA8888_Premultiplied: image = image.convertToFormat(QImage::Format_ARGB32); break; default: diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index a7936f915d..3bd8ca92b4 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -1092,7 +1092,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const return false; QImage image; - if (sourceImage.depth() != 32) + if (sourceImage.format() != QImage::Format_RGB32 || sourceImage.format() != QImage::Format_ARGB32 || sourceImage.format() != QImage::Format_ARGB32_Premultiplied) image = sourceImage.convertToFormat(QImage::Format_RGB32); else image = sourceImage; diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index fa289bbf8b..49cc411c4f 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -654,6 +654,9 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta event data: \a qt4Delta specifies the rotation, and \a qt4Orientation the direction. + The phase() is initialized to QWheelEvent::Changed. Use the other constructor + to specify the phase explicitly. + \sa posF(), globalPosF(), angleDelta(), pixelDelta() */ @@ -661,9 +664,38 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) : QInputEvent(Wheel, modifiers), p(pos), g(globalPos), pixelD(pixelDelta), - angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons) + angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons), ph(Changed) {} +/*! + Constructs a wheel event object. + + The \a pos provides the location of the mouse cursor + within the window. The position in global coordinates is specified + by \a globalPos. + + \a pixelDelta contains the scrolling distance in pixels on screen, while + \a angleDelta contains the wheel rotation distance. \a pixelDelta is + optional and can be null. + + The mouse and keyboard states at the time of the event are specified by + \a buttons and \a modifiers. + + For backwards compatibility, the event can also hold monodirectional wheel + event data: \a qt4Delta specifies the rotation, and \a qt4Orientation the + direction. + + The phase of the event is specified by \a phase. + + \sa posF(), globalPosF(), angleDelta(), pixelDelta(), phase() +*/ + +QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, + QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation, + Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Phase phase) + : QInputEvent(Wheel, modifiers), p(pos), g(globalPos), pixelD(pixelDelta), + angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons), ph(phase) +{} #endif // QT_NO_WHEELEVENT @@ -794,6 +826,28 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, \sa posF() */ +/*! + \enum QWheelEvent::Phase + \since 5.2 + + This enum describes the phase of a wheel event. + + \value Started Scrolling has started, but the scrolling + distance did not yet change. + + \value Changed The scrolling distance has changed (default). + + \value Ended Scrolling has ended, but the scrolling distance + did not change anymore. +*/ + +/*! + \fn QWheelEvent::Phase QWheelEvent::phase() const + \since 5.2 + + Returns the phase of this wheel event. +*/ + /*! \class QKeyEvent diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 7142450322..2de88cf010 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -167,6 +167,8 @@ protected: class Q_GUI_EXPORT QWheelEvent : public QInputEvent { public: + enum Phase { Started, Changed, Ended }; + QWheelEvent(const QPointF &pos, int delta, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::Orientation orient = Qt::Vertical); @@ -176,6 +178,9 @@ public: QWheelEvent(const QPointF &pos, const QPointF& globalPos, QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers); + QWheelEvent(const QPointF &pos, const QPointF& globalPos, + QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation, + Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Phase phase); ~QWheelEvent(); @@ -198,6 +203,9 @@ public: inline const QPointF &globalPosF() const { return g; } inline Qt::MouseButtons buttons() const { return mouseState; } + + inline Phase phase() const { return Phase(ph); } + protected: QPointF p; QPointF g; @@ -206,7 +214,8 @@ protected: int qt4D; Qt::Orientation qt4O; Qt::MouseButtons mouseState; - int reserved; + uint ph : 2; + int reserved : 30; }; #endif diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 7d2c710c52..6be3b066d8 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -101,6 +101,8 @@ # include <QtCore/QLibraryInfo> #endif // Q_OS_WIN && !Q_OS_WINCE +#include <ctype.h> + QT_BEGIN_NAMESPACE Q_GUI_EXPORT bool qt_is_gui_used = true; @@ -215,6 +217,106 @@ static inline bool isPopupWindow(const QWindow *w) return (w->flags() & Qt::WindowType_Mask) == Qt::Popup; } +// Geometry specification for top level windows following the convention of the +// -geometry command line arguments in X11 (see XParseGeometry). +struct QWindowGeometrySpecification +{ + QWindowGeometrySpecification() : corner(Qt::TopLeftCorner), xOffset(-1), yOffset(-1), width(-1), height(-1) {} + static QWindowGeometrySpecification fromArgument(const QByteArray &a); + QRect apply(const QRect &windowGeometry, const QSize &windowMinimumSize, const QSize &windowMaximumSize, const QRect &availableGeometry) const; + inline QRect apply(const QRect &windowGeometry, const QWindow *window) const + { return apply(windowGeometry, window->minimumSize(), window->maximumSize(), window->screen()->virtualGeometry()); } + + Qt::Corner corner; + int xOffset; + int yOffset; + int width; + int height; +}; + +// Parse a token of a X11 geometry specification "200x100+10-20". +static inline int nextGeometryToken(const QByteArray &a, int &pos, char *op) +{ + *op = 0; + const int size = a.size(); + if (pos >= size) + return -1; + + *op = a.at(pos); + if (*op == '+' || *op == '-' || *op == 'x') + pos++; + else if (isdigit(*op)) + *op = 'x'; // If it starts with a digit, it is supposed to be a width specification. + else + return -1; + + const int numberPos = pos; + for ( ; pos < size && isdigit(a.at(pos)); ++pos) ; + + bool ok; + const int result = a.mid(numberPos, pos - numberPos).toInt(&ok); + return ok ? result : -1; +} + +QWindowGeometrySpecification QWindowGeometrySpecification::fromArgument(const QByteArray &a) +{ + QWindowGeometrySpecification result; + int pos = 0; + for (int i = 0; i < 4; ++i) { + char op; + const int value = nextGeometryToken(a, pos, &op); + if (value < 0) + break; + switch (op) { + case 'x': + (result.width >= 0 ? result.height : result.width) = value; + break; + case '+': + case '-': + if (result.xOffset >= 0) { + result.yOffset = value; + if (op == '-') + result.corner = result.corner == Qt::TopRightCorner ? Qt::BottomRightCorner : Qt::BottomLeftCorner; + } else { + result.xOffset = value; + if (op == '-') + result.corner = Qt::TopRightCorner; + } + } + } + return result; +} + +QRect QWindowGeometrySpecification::apply(const QRect &windowGeometry, const QSize &windowMinimumSize, const QSize &windowMaximumSize, const QRect &availableGeometry) const +{ + QRect result = windowGeometry; + if (width >= 0 || height >= 0) { + QSize size = windowGeometry.size(); + if (width >= 0) + size.setWidth(qBound(windowMinimumSize.width(), width, windowMaximumSize.width())); + if (height >= 0) + size.setHeight(qBound(windowMinimumSize.height(), height, windowMaximumSize.height())); + result.setSize(size); + } + if (xOffset >= 0 || yOffset >= 0) { + QPoint topLeft = windowGeometry.topLeft(); + if (xOffset >= 0) { + topLeft.setX(corner == Qt::TopLeftCorner || corner == Qt::BottomLeftCorner ? + xOffset : + qMax(availableGeometry.right() - result.width() - xOffset, availableGeometry.left())); + } + if (yOffset >= 0) { + topLeft.setY(corner == Qt::TopLeftCorner || corner == Qt::TopRightCorner ? + yOffset : + qMax(availableGeometry.bottom() - result.height() - yOffset, availableGeometry.top())); + } + result.moveTopLeft(topLeft); + } + return result; +} + +static QWindowGeometrySpecification windowGeometrySpecification; + /*! \class QGuiApplication \brief The QGuiApplication class manages the GUI application's control @@ -785,14 +887,14 @@ QString QGuiApplication::platformName() *QGuiApplicationPrivate::platform_name : QString(); } -static void init_platform(const QString &pluginArgument, const QString &platformPluginPath) +static void init_platform(const QString &pluginArgument, const QString &platformPluginPath, int &argc, char **argv) { // Split into platform name and arguments QStringList arguments = pluginArgument.split(QLatin1Char(':')); const QString name = arguments.takeFirst().toLower(); // Create the platform integration. - QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, platformPluginPath); + QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath); if (QGuiApplicationPrivate::platform_integration) { QGuiApplicationPrivate::platform_name = new QString(name); } else { @@ -910,6 +1012,9 @@ void QGuiApplicationPrivate::createPlatformIntegration() } else if (arg == "-platform") { if (++i < argc) platformName = argv[i]; + } else if (arg == "-qwindowgeometry" || (platformName == "xcb" && arg == "-geometry")) { + if (++i < argc) + windowGeometrySpecification = QWindowGeometrySpecification::fromArgument(argv[i]); } else { argv[j++] = argv[i]; } @@ -920,7 +1025,7 @@ void QGuiApplicationPrivate::createPlatformIntegration() argc = j; } - init_platform(QLatin1String(platformName), platformPluginPath); + init_platform(QLatin1String(platformName), platformPluginPath, argc, argv); } @@ -1375,6 +1480,8 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e)); break; #endif + case QWindowSystemInterfacePrivate::EnterWhatsThisMode: + QGuiApplication::postEvent(QGuiApplication::instance(), new QEvent(QEvent::EnterWhatsThisMode)); default: qWarning() << "Unknown user input event type:" << e->type; break; @@ -1531,7 +1638,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh return; } - QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers); + QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers, e->phase); ev.setTimestamp(e->timestamp); QGuiApplication::sendSpontaneousEvent(window, &ev); #endif /* ifndef QT_NO_WHEELEVENT */ @@ -2398,6 +2505,11 @@ void QGuiApplication::setPalette(const QPalette &pal) applicationResourceFlags |= ApplicationPaletteExplicitlySet; } +QRect QGuiApplicationPrivate::applyWindowGeometrySpecification(const QRect &windowGeometry, const QWindow *window) +{ + return windowGeometrySpecification.apply(windowGeometry, window); +} + /*! Returns the default application font. diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 3a4b692b69..11f68ba2ff 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -275,6 +275,8 @@ public: // hook reimplemented in QApplication to apply the QStyle function on the QIcon virtual QPixmap applyQIconStyleHelper(QIcon::Mode, const QPixmap &basePixmap) const { return basePixmap; } + static QRect applyWindowGeometrySpecification(const QRect &windowGeometry, const QWindow *window); + protected: virtual void notifyThemeChanged(); #ifndef QT_NO_DRAGANDDROP diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index af3a46c675..6933f26816 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -637,6 +637,14 @@ static const struct { { Qt::Key_Hangul_PostHanja,QT_TRANSLATE_NOOP("QShortcut", "Hangul PostHanja") }, { Qt::Key_Hangul_Special, QT_TRANSLATE_NOOP("QShortcut", "Hangul Special") }, + // -------------------------------------------------------------- + // Miscellaenous keys + { Qt::Key_Cancel, QT_TRANSLATE_NOOP("QShortcut", "Cancel") }, + { Qt::Key_Printer, QT_TRANSLATE_NOOP("QShortcut", "Printer") }, + { Qt::Key_Execute, QT_TRANSLATE_NOOP("QShortcut", "Execute") }, + { Qt::Key_Play, QT_TRANSLATE_NOOP("QShortcut", "Play") }, + { Qt::Key_Zoom, QT_TRANSLATE_NOOP("QShortcut", "Zoom") }, + { 0, 0 } }; diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index 05460c6651..8a989682d8 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -44,6 +44,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qstring.h> +#include <QtCore/qobjectdefs.h> QT_BEGIN_NAMESPACE @@ -68,6 +69,9 @@ class QKeySequencePrivate; class Q_GUI_EXPORT QKeySequence { + Q_GADGET + Q_ENUMS(StandardKey) + public: enum StandardKey { UnknownKey, diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp index 5f86b511f7..74442736c3 100644 --- a/src/gui/kernel/qplatformdialoghelper.cpp +++ b/src/gui/kernel/qplatformdialoghelper.cpp @@ -376,9 +376,9 @@ public: QStringList nameFilters; QString defaultSuffix; QStringList history; - QString initialDirectory; + QUrl initialDirectory; QString initiallySelectedNameFilter; - QStringList initiallySelectedFiles; + QList<QUrl> initiallySelectedFiles; }; QFileDialogOptions::QFileDialogOptions() : d(new QFileDialogOptionsPrivate) @@ -495,6 +495,8 @@ QStringList QFileDialogOptions::nameFilters() const void QFileDialogOptions::setDefaultSuffix(const QString &suffix) { d->defaultSuffix = suffix; + if (d->defaultSuffix.size() > 1 && d->defaultSuffix.startsWith(QLatin1Char('.'))) + d->defaultSuffix.remove(0, 1); // Silently change ".txt" -> "txt". } QString QFileDialogOptions::defaultSuffix() const @@ -528,12 +530,12 @@ bool QFileDialogOptions::isLabelExplicitlySet(DialogLabel label) return label >= 0 && label < DialogLabelCount && !d->labels[label].isEmpty(); } -QString QFileDialogOptions::initialDirectory() const +QUrl QFileDialogOptions::initialDirectory() const { return d->initialDirectory; } -void QFileDialogOptions::setInitialDirectory(const QString &directory) +void QFileDialogOptions::setInitialDirectory(const QUrl &directory) { d->initialDirectory = directory; } @@ -548,16 +550,21 @@ void QFileDialogOptions::setInitiallySelectedNameFilter(const QString &filter) d->initiallySelectedNameFilter = filter; } -QStringList QFileDialogOptions::initiallySelectedFiles() const +QList<QUrl> QFileDialogOptions::initiallySelectedFiles() const { return d->initiallySelectedFiles; } -void QFileDialogOptions::setInitiallySelectedFiles(const QStringList &files) +void QFileDialogOptions::setInitiallySelectedFiles(const QList<QUrl> &files) { d->initiallySelectedFiles = files; } +bool QPlatformFileDialogHelper::isSupportedUrl(const QUrl &url) const +{ + return url.isLocalFile(); +} + /*! \class QPlatformFileDialogHelper \since 5.0 diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index ecc00ed8c6..092839aaed 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -57,6 +57,7 @@ #include <QtCore/QSharedDataPointer> #include <QtCore/QSharedPointer> #include <QtCore/QDir> +#include <QtCore/QUrl> #include <QtGui/QRgb> QT_BEGIN_NAMESPACE @@ -163,7 +164,11 @@ class Q_GUI_EXPORT QFontDialogOptions public: enum FontDialogOption { NoButtons = 0x00000001, - DontUseNativeDialog = 0x00000002 + DontUseNativeDialog = 0x00000002, + ScalableFonts = 0x00000004, + NonScalableFonts = 0x00000008, + MonospacedFonts = 0x00000010, + ProportionalFonts = 0x00000020 }; Q_DECLARE_FLAGS(FontDialogOptions, FontDialogOption) @@ -217,13 +222,14 @@ public: enum FileDialogOption { - ShowDirsOnly = 0x00000001, - DontResolveSymlinks = 0x00000002, - DontConfirmOverwrite = 0x00000004, - DontUseSheet = 0x00000008, - DontUseNativeDialog = 0x00000010, - ReadOnly = 0x00000020, - HideNameFilterDetails = 0x00000040 + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseSheet = 0x00000008, + DontUseNativeDialog = 0x00000010, + ReadOnly = 0x00000020, + HideNameFilterDetails = 0x00000040, + DontUseCustomDirectoryIcons = 0x00000080 }; Q_DECLARE_FLAGS(FileDialogOptions, FileDialogOption) @@ -270,14 +276,14 @@ public: QString labelText(DialogLabel label) const; bool isLabelExplicitlySet(DialogLabel label); - QString initialDirectory() const; - void setInitialDirectory(const QString &); + QUrl initialDirectory() const; + void setInitialDirectory(const QUrl &); QString initiallySelectedNameFilter() const; void setInitiallySelectedNameFilter(const QString &); - QStringList initiallySelectedFiles() const; - void setInitiallySelectedFiles(const QStringList &); + QList<QUrl> initiallySelectedFiles() const; + void setInitiallySelectedFiles(const QList<QUrl> &); private: QSharedDataPointer<QFileDialogOptionsPrivate> d; @@ -290,14 +296,16 @@ class Q_GUI_EXPORT QPlatformFileDialogHelper : public QPlatformDialogHelper Q_OBJECT public: virtual bool defaultNameFilterDisables() const = 0; - virtual void setDirectory(const QString &directory) = 0; - virtual QString directory() const = 0; - virtual void selectFile(const QString &filename) = 0; - virtual QStringList selectedFiles() const = 0; + virtual void setDirectory(const QUrl &directory) = 0; + virtual QUrl directory() const = 0; + virtual void selectFile(const QUrl &filename) = 0; + virtual QList<QUrl> selectedFiles() const = 0; virtual void setFilter() = 0; virtual void selectNameFilter(const QString &filter) = 0; virtual QString selectedNameFilter() const = 0; + virtual bool isSupportedUrl(const QUrl &url) const; + const QSharedPointer<QFileDialogOptions> &options() const; void setOptions(const QSharedPointer<QFileDialogOptions> &options); @@ -305,10 +313,10 @@ public: static const char *filterRegExp; Q_SIGNALS: - void fileSelected(const QString &file); - void filesSelected(const QStringList &files); - void currentChanged(const QString &path); - void directoryEntered(const QString &directory); + void fileSelected(const QUrl &file); + void filesSelected(const QList<QUrl> &files); + void currentChanged(const QUrl &path); + void directoryEntered(const QUrl &directory); void filterSelected(const QString &filter); private: diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index e4f45ebb6e..434344df08 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -237,7 +237,7 @@ QPlatformServices *QPlatformIntegration::services() const bool QPlatformIntegration::hasCapability(Capability cap) const { - return cap == NonFullScreenWindows; + return cap == NonFullScreenWindows || cap == NativeWidgets; } QPlatformPixmap *QPlatformIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const @@ -328,6 +328,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const return QVariant(false); case SynthesizeMouseFromTouchEvents: return true; + case SetFocusOnTouchRelease: + return QVariant(false); } return 0; diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index b7a44b13de..9350553efd 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -91,7 +91,8 @@ public: MultipleWindows, ApplicationState, ForeignWindows, - NonFullScreenWindows + NonFullScreenWindows, + NativeWidgets }; virtual ~QPlatformIntegration() { } @@ -141,7 +142,8 @@ public: StartDragVelocity, UseRtlExtensions, SynthesizeMouseFromTouchEvents, - PasswordMaskCharacter + PasswordMaskCharacter, + SetFocusOnTouchRelease }; virtual QVariant styleHint(StyleHint hint) const; diff --git a/src/gui/kernel/qplatformintegrationfactory.cpp b/src/gui/kernel/qplatformintegrationfactory.cpp index 21f53d17de..365edd2010 100644 --- a/src/gui/kernel/qplatformintegrationfactory.cpp +++ b/src/gui/kernel/qplatformintegrationfactory.cpp @@ -55,18 +55,30 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QPlatformIntegrationFactoryInterface_iid, QLatin1String("/platforms"), Qt::CaseInsensitive)) Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader, (QPlatformIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive)) -#endif -QPlatformIntegration *QPlatformIntegrationFactory::create(const QString &platform, const QStringList ¶mList, const QString &platformPluginPath) +static inline QPlatformIntegration *loadIntegration(QFactoryLoader *loader, const QString &key, const QStringList ¶meters, int &argc, char ** argv) +{ + const int index = loader->indexOf(key); + if (index != -1) { + if (QPlatformIntegrationPlugin *factory = qobject_cast<QPlatformIntegrationPlugin *>(loader->instance(index))) + if (QPlatformIntegration *result = factory->create(key, parameters, argc, argv)) + return result; + } + return 0; +} + +#endif // !QT_NO_LIBRARY + +QPlatformIntegration *QPlatformIntegrationFactory::create(const QString &platform, const QStringList ¶mList, int &argc, char **argv, const QString &platformPluginPath) { #ifndef QT_NO_LIBRARY // Try loading the plugin from platformPluginPath first: if (!platformPluginPath.isEmpty()) { QCoreApplication::addLibraryPath(platformPluginPath); - if (QPlatformIntegration *ret = qLoadPlugin1<QPlatformIntegration, QPlatformIntegrationPlugin>(directLoader(), platform, paramList)) + if (QPlatformIntegration *ret = loadIntegration(directLoader(), platform, paramList, argc, argv)) return ret; } - if (QPlatformIntegration *ret = qLoadPlugin1<QPlatformIntegration, QPlatformIntegrationPlugin>(loader(), platform, paramList)) + if (QPlatformIntegration *ret = loadIntegration(loader(), platform, paramList, argc, argv)) return ret; #endif return 0; diff --git a/src/gui/kernel/qplatformintegrationfactory_p.h b/src/gui/kernel/qplatformintegrationfactory_p.h index fb3ba55316..bc8ce11609 100644 --- a/src/gui/kernel/qplatformintegrationfactory_p.h +++ b/src/gui/kernel/qplatformintegrationfactory_p.h @@ -64,7 +64,7 @@ class Q_GUI_EXPORT QPlatformIntegrationFactory { public: static QStringList keys(const QString &platformPluginPath = QString()); - static QPlatformIntegration *create(const QString &name, const QStringList &args, const QString &platformPluginPath = QString()); + static QPlatformIntegration *create(const QString &name, const QStringList &args, int &argc, char **argv, const QString &platformPluginPath = QString()); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformintegrationplugin.cpp b/src/gui/kernel/qplatformintegrationplugin.cpp index 0f7f365d2a..2a9a047141 100644 --- a/src/gui/kernel/qplatformintegrationplugin.cpp +++ b/src/gui/kernel/qplatformintegrationplugin.cpp @@ -52,4 +52,18 @@ QPlatformIntegrationPlugin::~QPlatformIntegrationPlugin() { } +QPlatformIntegration *QPlatformIntegrationPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(key) + Q_UNUSED(paramList); + return 0; +} + +QPlatformIntegration *QPlatformIntegrationPlugin::create(const QString &key, const QStringList ¶mList, int &argc, char **argv) +{ + Q_UNUSED(argc) + Q_UNUSED(argv) + return create(key, paramList); // Fallback for platform plugins that do not implement the argc/argv version. +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformintegrationplugin.h b/src/gui/kernel/qplatformintegrationplugin.h index 434366f0b0..e624e2d31d 100644 --- a/src/gui/kernel/qplatformintegrationplugin.h +++ b/src/gui/kernel/qplatformintegrationplugin.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE class QPlatformIntegration; -#define QPlatformIntegrationFactoryInterface_iid "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" +#define QPlatformIntegrationFactoryInterface_iid "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" class Q_GUI_EXPORT QPlatformIntegrationPlugin : public QObject { @@ -68,7 +68,8 @@ public: explicit QPlatformIntegrationPlugin(QObject *parent = 0); ~QPlatformIntegrationPlugin(); - virtual QPlatformIntegration *create(const QString &key, const QStringList ¶mList) = 0; + virtual QPlatformIntegration *create(const QString &key, const QStringList ¶mList); + virtual QPlatformIntegration *create(const QString &key, const QStringList ¶mList, int &argc, char **argv); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformservices.cpp b/src/gui/kernel/qplatformservices.cpp index f2cade0a35..d09b74c6fe 100644 --- a/src/gui/kernel/qplatformservices.cpp +++ b/src/gui/kernel/qplatformservices.cpp @@ -74,7 +74,10 @@ bool QPlatformServices::openDocument(const QUrl &url) /*! * \brief QPlatformServices::desktopEnvironment returns the active desktop environment. * - * On Unix this function returns KDE, GNOME or UNKNOWN. + * On Unix this function returns the uppercase desktop environment name, such as + * KDE, GNOME, UNITY, XFCE, LXDE etc. or UNKNOWN if none was detected. + * The primary way to detect the desktop environment is the environment variable + * XDG_CURRENT_DESKTOP. */ QByteArray QPlatformServices::desktopEnvironment() const { diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 02b69bcb4d..098b8dad66 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -208,10 +208,12 @@ QPixmap QPlatformTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) co return QPixmap(); } -QPixmap QPlatformTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +QPixmap QPlatformTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { Q_UNUSED(fileInfo); Q_UNUSED(size); + Q_UNUSED(iconOptions); // TODO Should return QCommonStyle pixmaps? return QPixmap(); } diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 80ba29a028..1d7a1ccffa 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -154,6 +154,7 @@ public: ComboLineEditFont, SmallFont, MiniFont, + FixedFont, NFonts }; @@ -253,6 +254,11 @@ public: AnimateToolBoxUiEffect = 0x40 }; + enum IconOption { + DontUseCustomDirectoryIcons = 0x01 + }; + Q_DECLARE_FLAGS(IconOptions, IconOption) + explicit QPlatformTheme(); virtual ~QPlatformTheme(); @@ -274,7 +280,8 @@ public: virtual QVariant themeHint(ThemeHint hint) const; virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const; virtual QIconEngine *createIconEngine(const QString &iconName) const; diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index cd822090e2..513e21937e 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -324,6 +324,9 @@ bool QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent *e) { Q_D(QShortcutMap); + if (e->key() == Qt::Key_unknown) + return false; + bool wasAccepted = e->isAccepted(); bool wasSpontaneous = e->spont; if (d->currentState == QKeySequence::NoMatch) { diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp index 30b12835f7..a302f2186c 100644 --- a/src/gui/kernel/qstylehints.cpp +++ b/src/gui/kernel/qstylehints.cpp @@ -218,4 +218,15 @@ bool QStyleHints::useRtlExtensions() const return hint(QPlatformIntegration::UseRtlExtensions).toBool(); } +/*! + Returns \c true if focus objects (line edits etc) should receive + input focus after a touch/mouse release. This is normal behavior on + touch platforms. On desktop platforms, the standard is to set + focus already on touch/mouse press. +*/ +bool QStyleHints::setFocusOnTouchRelease() const +{ + return hint(QPlatformIntegration::SetFocusOnTouchRelease).toBool(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h index 64ef182aab..a0facd5f94 100644 --- a/src/gui/kernel/qstylehints.h +++ b/src/gui/kernel/qstylehints.h @@ -65,6 +65,7 @@ public: QChar passwordMaskCharacter() const; qreal fontSmoothingGamma() const; bool useRtlExtensions() const; + bool setFocusOnTouchRelease() const; private: friend class QGuiApplication; diff --git a/src/gui/kernel/qtouchdevice.cpp b/src/gui/kernel/qtouchdevice.cpp index 02c6dd9efc..3ad4b4161e 100644 --- a/src/gui/kernel/qtouchdevice.cpp +++ b/src/gui/kernel/qtouchdevice.cpp @@ -140,6 +140,16 @@ QTouchDevice::Capabilities QTouchDevice::capabilities() const } /*! + Returns the maximum number of simultaneous touch points (fingers) that + can be detected. + \since 5.2 + */ +int QTouchDevice::maximumTouchPoints() const +{ + return d->maxTouchPoints; +} + +/*! Returns the touch device name. This string may often be empty. It is however useful for systems that have @@ -169,6 +179,15 @@ void QTouchDevice::setCapabilities(Capabilities caps) } /*! + Sets the maximum number of simultaneous touchpoints \a max + supported by the device and its driver. + */ +void QTouchDevice::setMaximumTouchPoints(int max) +{ + d->maxTouchPoints = max; +} + +/*! Sets the \a name (a unique identifier) for the device. In most systems it is enough to leave this unset and keep the default empty name. This identifier becomes important when having multiple touch devices and a need to diff --git a/src/gui/kernel/qtouchdevice.h b/src/gui/kernel/qtouchdevice.h index 312bdce3e6..6aca93907c 100644 --- a/src/gui/kernel/qtouchdevice.h +++ b/src/gui/kernel/qtouchdevice.h @@ -75,10 +75,12 @@ public: QString name() const; DeviceType type() const; Capabilities capabilities() const; + int maximumTouchPoints() const; void setName(const QString &name); void setType(DeviceType devType); void setCapabilities(Capabilities caps); + void setMaximumTouchPoints(int max); private: QTouchDevicePrivate *d; diff --git a/src/gui/kernel/qtouchdevice_p.h b/src/gui/kernel/qtouchdevice_p.h index 435f8a5c37..fb87f49736 100644 --- a/src/gui/kernel/qtouchdevice_p.h +++ b/src/gui/kernel/qtouchdevice_p.h @@ -64,12 +64,14 @@ class QTouchDevicePrivate public: QTouchDevicePrivate() : type(QTouchDevice::TouchScreen), - caps(QTouchDevice::Position) + caps(QTouchDevice::Position), + maxTouchPoints(1) { } QTouchDevice::DeviceType type; QTouchDevice::Capabilities caps; QString name; + int maxTouchPoints; static void registerDevice(QTouchDevice *dev); static bool isRegistered(QTouchDevice *dev); diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 6fc63fe96c..b094ccb33b 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -298,13 +298,13 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con handleWheelEvent(tlw, timestamp, local, global, QPoint(), point, mods); } -void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods) +void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, QWheelEvent::Phase phase) { unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleWheelEvent(w, time, local, global, pixelDelta, angleDelta, mods); + handleWheelEvent(w, time, local, global, pixelDelta, angleDelta, mods, phase); } -void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods) +void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, QWheelEvent::Phase phase) { // Qt 4 sends two separate wheel events for horizontal and vertical // deltas. For Qt 5 we want to send the deltas in one event, but at the @@ -315,19 +315,21 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Angle deltas must always be sent in addition to pixel deltas. QWindowSystemInterfacePrivate::WheelEvent *e; - if (angleDelta.isNull()) + // Pass QWheelEvent::Started and QWheelEvent::Ended through + // even if the wheel delta is null. + if (angleDelta.isNull() && phase == QWheelEvent::Changed) return; // Simple case: vertical deltas only: if (angleDelta.y() != 0 && angleDelta.x() == 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } // Simple case: horizontal deltas only: if (angleDelta.y() == 0 && angleDelta.x() != 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } @@ -335,12 +337,12 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Both horizontal and vertical deltas: Send two wheel events. // The first event contains the Qt 5 pixel and angle delta as points, // and in addition the Qt 4 compatibility vertical angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); // The second event contains null pixel and angle points and the // Qt 4 compatibility horizontal angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -692,6 +694,15 @@ void QWindowSystemInterface::handleContextMenuEvent(QWindow *w, bool mouseTrigge } #endif +#ifndef QT_NO_WHATSTHIS +void QWindowSystemInterface::handleEnterWhatsThisEvent() +{ + QWindowSystemInterfacePrivate::WindowSystemEvent *e = + new QWindowSystemInterfacePrivate::WindowSystemEvent(QWindowSystemInterfacePrivate::EnterWhatsThisMode); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); +} +#endif + #ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPoint &p) { dbg.nospace() << "TouchPoint(" << p.id << " @" << p.normalPosition << " press " << p.pressure << " vel " << p.velocity << " state " << (int)p.state; diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index b0327701bb..f9efdbf8ce 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -61,6 +61,7 @@ #include <QtGui/QTouchEvent> #include <QtCore/QEventLoop> #include <QtGui/QVector2D> +#include <QtGui/QWheelEvent> QT_BEGIN_NAMESPACE @@ -103,8 +104,8 @@ public: quint32 nativeModifiers, const QString& text = QString(), bool autorep = false, ushort count = 1); - static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier); - static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier); + static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, QWheelEvent::Phase phase = QWheelEvent::Changed); + static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, QWheelEvent::Phase phase = QWheelEvent::Changed); // Wheel event compatibility functions. Will be removed: do not use. static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier); @@ -183,6 +184,9 @@ public: const QPoint &pos, const QPoint &globalPos, Qt::KeyboardModifiers modifiers); #endif +#ifndef QT_NO_WHATSTHIS + static void handleEnterWhatsThisEvent(); +#endif // For event dispatcher implementations static bool sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 398df0a96f..7dbc3ad8ed 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -90,6 +90,7 @@ public: TabletLeaveProximity = UserInputEvent | 0x16, PlatformPanel = UserInputEvent | 0x17, ContextMenu = UserInputEvent | 0x18, + EnterWhatsThisMode = UserInputEvent | 0x19, ApplicationStateChanged = 0x19, FlushEvents = 0x20, WindowScreenChanged = 0x21 @@ -217,14 +218,15 @@ public: class WheelEvent : public InputEvent { public: WheelEvent(QWindow *w, ulong time, const QPointF & local, const QPointF & global, QPoint pixelD, QPoint angleD, int qt4D, Qt::Orientation qt4O, - Qt::KeyboardModifiers mods) - : InputEvent(w, time, Wheel, mods), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D), qt4Orientation(qt4O), localPos(local), globalPos(global) { } + Qt::KeyboardModifiers mods, QWheelEvent::Phase phase = QWheelEvent::Changed) + : InputEvent(w, time, Wheel, mods), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D), qt4Orientation(qt4O), localPos(local), globalPos(global), phase(phase) { } QPoint pixelDelta; QPoint angleDelta; int qt4Delta; Qt::Orientation qt4Orientation; QPointF localPos; QPointF globalPos; + QWheelEvent::Phase phase; }; class KeyEvent : public InputEvent { diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index 90416db72b..247ecf7351 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -1012,23 +1012,28 @@ QOpenGLFramebufferObjectFormat QOpenGLFramebufferObject::format() const Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) { - QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied - : QImage::Format_RGB32); int w = size.width(); int h = size.height(); + while (glGetError()); + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_RGB32); #ifdef QT_OPENGL_ES GLint fmt = GL_BGRA_EXT; #else GLint fmt = GL_BGRA; #endif - while (glGetError()); glReadPixels(0, 0, w, h, fmt, GL_UNSIGNED_BYTE, img.bits()); - if (glGetError()) { - glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - img = img.rgbSwapped(); - } - return img.mirrored(); + if (!glGetError()) + return img.mirrored(); +#endif + + QImage rgbaImage(size, (alpha_format && include_alpha) ? QImage::Format_RGBA8888_Premultiplied + : QImage::Format_RGBX8888); + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits()); + return rgbaImage.mirrored(); } /*! diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index 3737df7497..60591a34d2 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -141,8 +141,8 @@ QT_BEGIN_NAMESPACE /*! \enum QOpenGLFunctions::OpenGLFeature - This enum defines OpenGL/ES 2.0 features that may be optional - on other platforms. + This enum defines OpenGL and OpenGL ES features whose presence + may depend on the implementation. \value Multitexture glActiveTexture() function is available. \value Shaders Shader functions are available. @@ -158,6 +158,7 @@ QT_BEGIN_NAMESPACE \value StencilSeparate Separate stencil functions are available. \value NPOTTextures Non power of two textures are available. \value NPOTTextureRepeat Non power of two textures can use GL_REPEAT as wrap parameter. + \value FixedFunctionPipeline The fixed function pipeline is available. */ // Hidden private fields for additional extension data. @@ -331,6 +332,13 @@ static int qt_gl_resolve_features() if (format.majorVersion() >= 3) features |= QOpenGLFunctions::Framebuffers; + const QPair<int, int> version = format.version(); + if (version < qMakePair(3, 0) + || (version == qMakePair(3, 0) && format.testOption(QSurfaceFormat::DeprecatedFunctions)) + || (version == qMakePair(3, 1) && extensions.match("GL_ARB_compatibility")) + || (version >= qMakePair(3, 2) && format.profile() == QSurfaceFormat::CompatibilityProfile)) { + features |= QOpenGLFunctions::FixedFunctionPipeline; + } return features; #endif } diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h index 1548ad4a24..9d8da209ad 100644 --- a/src/gui/opengl/qopenglfunctions.h +++ b/src/gui/opengl/qopenglfunctions.h @@ -199,7 +199,8 @@ public: Multisample = 0x0400, StencilSeparate = 0x0800, NPOTTextures = 0x1000, - NPOTTextureRepeat = 0x2000 + NPOTTextureRepeat = 0x2000, + FixedFunctionPipeline = 0x4000 }; Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature) diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 47ba27d72a..aadcc0f686 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -91,9 +91,12 @@ SSE2_SOURCES += painting/qdrawhelper_sse2.cpp SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp IWMMXT_SOURCES += painting/qdrawhelper_iwmmxt.cpp AVX_SOURCES += painting/qdrawhelper_avx.cpp -NEON_SOURCES += painting/qdrawhelper_neon.cpp -NEON_HEADERS += painting/qdrawhelper_neon_p.h -NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S + +!ios { + NEON_SOURCES += painting/qdrawhelper_neon.cpp + NEON_HEADERS += painting/qdrawhelper_neon_p.h + NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S +} MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 6d9168ecf4..23eaa9a3e7 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -604,7 +604,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_Mono 0, // Format_Invalid, @@ -622,7 +625,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_MonoLSB 0, // Format_Invalid, @@ -640,7 +646,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_Indexed8 0, // Format_Invalid, @@ -658,7 +667,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB32 0, // Format_Invalid, @@ -676,7 +688,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB32 0, // Format_Invalid, @@ -694,7 +709,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB32_Premultiplied 0, // Format_Invalid, @@ -712,7 +730,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB16 0, // Format_Invalid, @@ -730,7 +751,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB8565_Premultiplied 0, // Format_Invalid, @@ -748,7 +772,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB666 0, // Format_Invalid, @@ -766,7 +793,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB6666_Premultiplied 0, // Format_Invalid, @@ -784,7 +814,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB555 0, // Format_Invalid, @@ -802,7 +835,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB8555_Premultiplied 0, // Format_Invalid, @@ -820,7 +856,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB888 0, // Format_Invalid, @@ -838,7 +877,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB444 0, // Format_Invalid, @@ -856,7 +898,10 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB4444_Premultiplied 0, // Format_Invalid, @@ -874,7 +919,85 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, + }, + { // Format_RGBX8888 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, + 0, // Format_RGBA8888, + qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, +#else + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, +#endif + }, + { // Format_RGBA8888 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, + }, + { // Format_RGBA8888_Premultiplied + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, + 0, // Format_RGBA8888, + qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, +#else + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, +#endif } }; @@ -896,7 +1019,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_Mono 0, // Format_Invalid, @@ -914,7 +1040,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_MonoLSB 0, // Format_Invalid, @@ -932,7 +1061,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_Indexed8 0, // Format_Invalid, @@ -950,7 +1082,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB32 0, // Format_Invalid, @@ -968,7 +1103,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB32 0, // Format_Invalid, @@ -986,7 +1124,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB32_Premultiplied 0, // Format_Invalid, @@ -1004,7 +1145,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB16 0, // Format_Invalid, @@ -1022,7 +1166,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB8565_Premultiplied 0, // Format_Invalid, @@ -1040,7 +1187,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB666 0, // Format_Invalid, @@ -1058,7 +1208,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB6666_Premultiplied 0, // Format_Invalid, @@ -1076,7 +1229,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB555 0, // Format_Invalid, @@ -1094,7 +1250,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB8555_Premultiplied 0, // Format_Invalid, @@ -1112,7 +1271,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB888 0, // Format_Invalid, @@ -1130,7 +1292,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB444 0, // Format_Invalid, @@ -1148,7 +1313,10 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB4444_Premultiplied 0, // Format_Invalid, @@ -1166,7 +1334,85 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, + }, + { // Format_RGBX8888 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_blend_rgb32_on_rgb32, // Format_RGBX8888, + 0, // Format_RGBA8888, + qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, +#else + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, +#endif + }, + { // Format_RGBA8888 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, + }, + { // Format_RGBA8888_Premultiplied + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_blend_rgb32_on_rgb32, // Format_RGBX8888, + 0, // Format_RGBA8888, + qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, +#else + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, +#endif } }; @@ -1187,7 +1433,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_Mono 0, // Format_Invalid, @@ -1205,7 +1454,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_MonoLSB 0, // Format_Invalid, @@ -1223,7 +1475,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_Indexed8 0, // Format_Invalid, @@ -1241,7 +1496,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB32 0, // Format_Invalid, @@ -1259,7 +1517,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB32 0, // Format_Invalid, @@ -1277,7 +1538,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB32_Premultiplied 0, // Format_Invalid, @@ -1295,7 +1559,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB16 0, // Format_Invalid, @@ -1313,7 +1580,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB8565_Premultiplied 0, // Format_Invalid, @@ -1331,7 +1601,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB666 0, // Format_Invalid, @@ -1349,7 +1622,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB6666_Premultiplied 0, // Format_Invalid, @@ -1367,7 +1643,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB555 0, // Format_Invalid, @@ -1385,7 +1664,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB8555_Premultiplied 0, // Format_Invalid, @@ -1403,7 +1685,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB888 0, // Format_Invalid, @@ -1421,7 +1706,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_RGB444 0, // Format_Invalid, @@ -1439,7 +1727,10 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, }, { // Format_ARGB4444_Premultiplied 0, // Format_Invalid, @@ -1457,7 +1748,85 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_ARGB8555_Premultiplied, 0, // Format_RGB888, 0, // Format_RGB444, - 0 // Format_ARGB4444_Premultiplied, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, + }, + { // Format_RGBX8888 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, + 0, // Format_RGBA8888, + qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, +#else + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, +#endif + }, + { // Format_RGBA8888 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, + }, + { // Format_RGBA8888_Premultiplied + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, + 0, // Format_RGBA8888, + qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, +#else + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0 // Format_RGBA8888_Premultiplied, +#endif } }; diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 12ca84d8d1..c93320c491 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -90,7 +90,8 @@ QT_BEGIN_NAMESPACE specified. A color can be set by passing an RGB string (such as "#112233"), - or a color name (such as "blue"), to the setNamedColor() function. + or an ARGB string (such as "#ff112233") or a color name (such as "blue"), + to the setNamedColor() function. The color names are taken from the SVG 1.0 color names. The name() function returns the name of the color in the format "#RRGGBB". Colors can also be set using setRgb(), setHsv() and @@ -301,6 +302,17 @@ QT_BEGIN_NAMESPACE */ /*! + \enum QColor::NameFormat + + How to format the output of the name() function + + \value HexRgb #RRGGBB A "#" character followed by three two-digit hexadecimal numbers (i.e. \c{#RRGGBB}). + \value HexArgb #AARRGGBB A "#" character followed by four two-digit hexadecimal numbers (i.e. \c{#AARRGGBB}). + + \sa name() +*/ + +/*! \fn Spec QColor::spec() const Returns how the color was specified. @@ -489,8 +501,28 @@ QColor::QColor(Spec spec) QString QColor::name() const { + return name(HexRgb); +} + +/*! + \since 5.2 + + Returns the name of the color in the specified \a format. + + \sa setNamedColor(), NameFormat +*/ + +QString QColor::name(NameFormat format) const +{ QString s; - s.sprintf("#%02x%02x%02x", red(), green(), blue()); + switch (format) { + case HexRgb: + s.sprintf("#%02x%02x%02x", red(), green(), blue()); + break; + case HexArgb: + s.sprintf("#%02x%02x%02x%02x", alpha(), red(), green(), blue()); + break; + } return s; } @@ -501,6 +533,7 @@ QString QColor::name() const \list \li #RGB (each of R, G, and B is a single hex digit) \li #RRGGBB + \li #AARRGGBB (Since 5.2) \li #RRRGGGBBB \li #RRRRGGGGBBBB \li A name from the list of colors defined in the list of \l{http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG color keyword names} @@ -545,9 +578,9 @@ bool QColor::setColorFromString(const QString &name) } if (name.startsWith(QLatin1Char('#'))) { - QRgb rgb; - if (qt_get_hex_rgb(name.constData(), name.length(), &rgb)) { - setRgb(rgb); + QRgb rgba; + if (qt_get_hex_rgb(name.constData(), name.length(), &rgba)) { + setRgba(rgba); return true; } else { invalidate(); diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index ef3503e8d8..1ede5a3682 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -65,6 +65,7 @@ class Q_GUI_EXPORT QColor { public: enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl }; + enum NameFormat { HexRgb, HexArgb }; QColor(); QColor(Qt::GlobalColor color); @@ -77,7 +78,9 @@ public: bool isValid() const; + // ### Qt 6: merge overloads QString name() const; + QString name(NameFormat format) const; void setNamedColor(const QString& name); static QStringList colorNames(); diff --git a/src/gui/painting/qcolor_p.cpp b/src/gui/painting/qcolor_p.cpp index 35e607ec54..b913f5338c 100644 --- a/src/gui/painting/qcolor_p.cpp +++ b/src/gui/painting/qcolor_p.cpp @@ -79,7 +79,8 @@ bool qt_get_hex_rgb(const char *name, QRgb *rgb) return false; name++; int len = qstrlen(name); - int r, g, b; + int a, r, g, b; + a = 255; if (len == 12) { r = hex2int(name); g = hex2int(name + 4); @@ -88,6 +89,11 @@ bool qt_get_hex_rgb(const char *name, QRgb *rgb) r = hex2int(name); g = hex2int(name + 3); b = hex2int(name + 6); + } else if (len == 8) { + a = hex2int(name); + r = hex2int(name + 2); + g = hex2int(name + 4); + b = hex2int(name + 6); } else if (len == 6) { r = hex2int(name); g = hex2int(name + 2); @@ -99,11 +105,11 @@ bool qt_get_hex_rgb(const char *name, QRgb *rgb) } else { r = g = b = -1; } - if ((uint)r > 255 || (uint)g > 255 || (uint)b > 255) { + if ((uint)r > 255 || (uint)g > 255 || (uint)b > 255 || (uint)a > 255) { *rgb = 0; return false; } - *rgb = qRgb(r, g ,b); + *rgb = qRgba(r, g ,b, a); return true; } diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index de0ab53c1b..a037545dc2 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -255,6 +255,33 @@ static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src return buffer; } +static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *layout, const QRgb *) +{ + Q_ASSERT(layout->redWidth <= 8); + Q_ASSERT(layout->greenWidth <= 8); + Q_ASSERT(layout->blueWidth <= 8); + Q_ASSERT(layout->alphaWidth == 0); + + const uint redMask = (1 << layout->redWidth) - 1; + const uint greenMask = (1 << layout->greenWidth) - 1; + const uint blueMask = (1 << layout->blueWidth) - 1; + + const uchar redRightShift = 24 - layout->redWidth; + const uchar greenRightShift = 16 - layout->greenWidth; + const uchar blueRightShift = 8 - layout->blueWidth; + + for (int i = 0; i < count; ++i) { + uint color = INV_PREMUL(src[i]); + uint red = ((color >> redRightShift) & redMask) << layout->redShift; + uint green = ((color >> greenRightShift) & greenMask) << layout->greenShift; + uint blue = ((color >> blueRightShift) & blueMask) << layout->blueShift; + uint alpha = 0xff << layout->alphaShift; + buffer[i] = red | green | blue | alpha; + } + return buffer; +} + template <QPixelLayout::BPP bpp> static uint QT_FASTCALL fetchPixel(const uchar *src, int index); @@ -386,7 +413,16 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8555_Premultiplied { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB888 { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB444 - { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM } // Format_ARGB4444_Premultiplied + { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB4444_Premultiplied +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertToRGB32, convertRGBFromARGB32PM }, // Format_RGBX8888 + { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM }, // Format_RGBA8888 + { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM }, // Format_RGBA8888_Premultiplied +#else + { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertToRGB32, convertRGBFromARGB32PM }, // Format_RGBX8888 + { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM }, // Format_RGBA8888 (ABGR32) + { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM } // Format_RGBA8888_Premultiplied +#endif }; FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { @@ -490,7 +526,10 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = destFetch, // Format_ARGB8555_Premultiplied destFetch, // Format_RGB888 destFetch, // Format_RGB444 - destFetch // Format_ARGB4444_Premultiplied + destFetch, // Format_ARGB4444_Premultiplied + destFetch, // Format_RGBX8888 + destFetch, // Format_RGBA8888 + destFetch, // Format_RGBA8888_Premultiplied }; /* @@ -622,7 +661,10 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] = destStore, // Format_ARGB8555_Premultiplied destStore, // Format_RGB888 destStore, // Format_RGB444 - destStore // Format_ARGB4444_Premultiplied + destStore, // Format_ARGB4444_Premultiplied + destStore, // Format_RGBX8888 + destStore, // Format_RGBA8888 + destStore // Format_RGBA8888_Premultiplied }; /* @@ -1766,7 +1808,10 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchUntransformed, // ARGB8555_Premultiplied fetchUntransformed, // RGB888 fetchUntransformed, // RGB444 - fetchUntransformed // ARGB4444_Premultiplied + fetchUntransformed, // ARGB4444_Premultiplied + fetchUntransformed, // RGBX8888 + fetchUntransformed, // RGBA8888 + fetchUntransformed // RGBA8888_Premultiplied }, // Tiled { @@ -1785,7 +1830,10 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchUntransformed, // ARGB8555_Premultiplied fetchUntransformed, // RGB888 fetchUntransformed, // RGB444 - fetchUntransformed // ARGB4444_Premultiplied + fetchUntransformed, // ARGB4444_Premultiplied + fetchUntransformed, // RGBX8888 + fetchUntransformed, // RGBA8888 + fetchUntransformed // RGBA8888_Premultiplied }, // Transformed { @@ -1805,6 +1853,9 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformed<BlendTransformed>, // RGB888 fetchTransformed<BlendTransformed>, // RGB444 fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied + fetchTransformed<BlendTransformed>, // RGBX8888 + fetchTransformed<BlendTransformed>, // RGBA8888 + fetchTransformed<BlendTransformed>, // RGBA8888_Premultiplied }, { 0, // TransformedTiled @@ -1823,6 +1874,9 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformed<BlendTransformedTiled>, // RGB888 fetchTransformed<BlendTransformedTiled>, // RGB444 fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied + fetchTransformed<BlendTransformedTiled>, // RGBX8888 + fetchTransformed<BlendTransformedTiled>, // RGBA8888 + fetchTransformed<BlendTransformedTiled>, // RGBA8888_Premultiplied }, { 0, // Bilinear @@ -1840,7 +1894,10 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB8555_Premultiplied fetchTransformedBilinear<BlendTransformedBilinear>, // RGB888 fetchTransformedBilinear<BlendTransformedBilinear>, // RGB444 - fetchTransformedBilinear<BlendTransformedBilinear> // ARGB4444_Premultiplied + fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB4444_Premultiplied + fetchTransformedBilinear<BlendTransformedBilinear>, // RGBX8888 + fetchTransformedBilinear<BlendTransformedBilinear>, // RGBA8888 + fetchTransformedBilinear<BlendTransformedBilinear> // RGBA8888_Premultiplied }, { 0, // BilinearTiled @@ -1858,7 +1915,10 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB8555_Premultiplied fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB888 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB444 - fetchTransformedBilinear<BlendTransformedBilinearTiled> // ARGB4444_Premultiplied + fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB4444_Premultiplied + fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGBX8888 + fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGBA8888 + fetchTransformedBilinear<BlendTransformedBilinearTiled> // RGBA8888_Premultiplied }, }; @@ -5268,6 +5328,9 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_untransformed_generic, blend_untransformed_generic, blend_untransformed_generic, + blend_untransformed_generic, + blend_untransformed_generic, + blend_untransformed_generic, }, // Tiled { @@ -5287,6 +5350,9 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_tiled_generic, blend_tiled_generic, blend_tiled_generic, + blend_tiled_generic, + blend_tiled_generic, + blend_tiled_generic, }, // Transformed { @@ -5306,6 +5372,9 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, + blend_src_generic, + blend_src_generic, + blend_src_generic, }, // TransformedTiled { @@ -5324,6 +5393,9 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, + blend_src_generic, + blend_src_generic, + blend_src_generic, blend_src_generic }, // Bilinear @@ -5344,6 +5416,9 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, + blend_src_generic, + blend_src_generic, + blend_src_generic, }, // BilinearTiled { @@ -5363,6 +5438,9 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, // RGB888 blend_src_generic, // RGB444 blend_src_generic, // ARGB4444_Premultiplied + blend_src_generic, // RGBX8888 + blend_src_generic, // RGBA8888 + blend_src_generic, // RGBA8888_Premultiplied } }; @@ -5823,9 +5901,9 @@ static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer, } } -static void qt_rectfill_quint32(QRasterBuffer *rasterBuffer, - int x, int y, int width, int height, - quint32 color) +static void qt_rectfill_argb32(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + quint32 color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), color, x, y, width, height, rasterBuffer->bytesPerLine()); @@ -5839,14 +5917,30 @@ static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer, qConvertRgb32To16(color), x, y, width, height, rasterBuffer->bytesPerLine()); } -static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer, - int x, int y, int width, int height, - quint32 color) +static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + quint32 color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine()); } +static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + quint32 color) +{ + qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), + ARGB2RGBA(color), x, y, width, height, rasterBuffer->bytesPerLine()); +} + +static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + quint32 color) +{ + qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), + ARGB2RGBA(INV_PREMUL(color)), x, y, width, height, rasterBuffer->bytesPerLine()); +} + // Map table for destination image format. Contains function pointers // for blends of various types unto the destination @@ -5880,7 +5974,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = qt_bitmapblit_quint32, qt_alphamapblit_quint32, qt_alphargbblit_quint32, - qt_rectfill_quint32 + qt_rectfill_argb32 }, // Format_ARGB32, { @@ -5889,7 +5983,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = qt_bitmapblit_quint32, qt_alphamapblit_quint32, qt_alphargbblit_quint32, - qt_rectfill_nonpremul_quint32 + qt_rectfill_nonpremul_argb32 }, // Format_ARGB32_Premultiplied { @@ -5898,7 +5992,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = qt_bitmapblit_quint32, qt_alphamapblit_quint32, qt_alphargbblit_quint32, - qt_rectfill_quint32 + qt_rectfill_argb32 }, // Format_RGB16 { @@ -5956,6 +6050,48 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = blend_color_generic, blend_src_generic, 0, 0, 0, 0 + }, + // Format_RGBX8888 + { + blend_color_generic, + qt_gradient_quint32, + qt_bitmapblit_quint32, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_alphamapblit_quint32, + qt_alphargbblit_quint32, +#else + 0, + 0, +#endif + qt_rectfill_rgba + }, + // Format_RGBA8888 + { + blend_color_generic, + qt_gradient_quint32, + qt_bitmapblit_quint32, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_alphamapblit_quint32, + qt_alphargbblit_quint32, +#else + 0, + 0, +#endif + qt_rectfill_nonpremul_rgba + }, + // Format_RGB8888_Premultiplied + { + blend_color_generic, + qt_gradient_quint32, + qt_bitmapblit_quint32, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qt_alphamapblit_quint32, + qt_alphargbblit_quint32, +#else + 0, + 0, +#endif + qt_rectfill_rgba } }; @@ -6043,6 +6179,9 @@ void qInitDrawhelperAsm() qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_avx; qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_avx; qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_avx; + qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit32_avx; + qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit32_avx; + qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit32_avx; extern void qt_scale_image_argb32_on_argb32_avx(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, @@ -6052,6 +6191,10 @@ void qInitDrawhelperAsm() int const_alpha); qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; +#endif #endif #ifdef QT_COMPILER_SUPPORTS_SSE2 } else if (features & SSE2) { @@ -6061,6 +6204,9 @@ void qInitDrawhelperAsm() qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2; qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2; qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2; + qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit32_sse2; + qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit32_sse2; + qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2; extern void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, @@ -6070,6 +6216,10 @@ void qInitDrawhelperAsm() int const_alpha); qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; +#endif #endif } @@ -6088,6 +6238,12 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2; +#endif extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length); @@ -6104,6 +6260,10 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; +#endif } #endif // SSSE3 @@ -6122,6 +6282,12 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx; +#endif extern const uint * QT_FASTCALL qt_fetch_radial_gradient_avx(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length); @@ -6163,7 +6329,7 @@ void qInitDrawhelperAsm() } #endif // IWMMXT -#if defined(QT_COMPILER_SUPPORTS_NEON) +#if defined(QT_COMPILER_SUPPORTS_NEON) && !defined(Q_OS_IOS) if (features & NEON) { qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; @@ -6172,6 +6338,12 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon; qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon; +#endif qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon; qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon; diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 0b8a41c904..f4c29996b4 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -653,6 +653,30 @@ static Q_ALWAYS_INLINE uint PREMUL(uint x) { } #endif +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { + quint32 rgb = x >> 8; + quint32 a = x << 24; + return a | rgb; +} + +static Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) { + quint32 rgb = x << 8; + quint32 a = x >> 24; + return a | rgb; +} +#else +static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { + // RGBA8888 is ABGR32 on little endian. + quint32 ag = x & 0xff00ff00; + quint32 rg = x & 0x00ff00ff; + return ag | (rg << 16) | (rg >> 16); +} + +static Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) { + return RGBA2ARGB(x); +} +#endif static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16(uint x, uint a) { a += 1; diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 27cb08f353..89ccdd42f0 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -1017,7 +1017,7 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh) return QImage(); } - if (src.format() == QImage::Format_ARGB32_Premultiplied) + if (src.format() == QImage::Format_ARGB32_Premultiplied || src.format() == QImage::Format_RGBA8888_Premultiplied) qt_qimageScaleArgb(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); else diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp index 747881bbd1..087231df43 100644 --- a/src/gui/painting/qmemrotate.cpp +++ b/src/gui/painting/qmemrotate.cpp @@ -529,7 +529,10 @@ MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3] = { 0, 0, 0 }, // Format_ARGB8555_Premultiplied, { 0, 0, 0 }, // Format_RGB888, { 0, 0, 0 }, // Format_RGB444, - { 0, 0, 0 } // Format_ARGB4444_Premultiplied, + { 0, 0, 0 }, // Format_ARGB4444_Premultiplied, + { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGBX8888, + { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGBA8888, + { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 } // Format_RGBA8888_Premultiplied, }; QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index bb0c441b40..f855e9e32d 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -89,9 +89,9 @@ QTextItemIntCopy::QTextItemIntCopy(const QTextItem &item) QTextItemIntCopy::~QTextItemIntCopy() { - delete m_item.chars; - delete m_item.logClusters; - delete m_item.glyphs.data(); + delete [] m_item.chars; + delete [] m_item.logClusters; + delete [] m_item.glyphs.data(); if (!m_item.fontEngine->ref.deref()) delete m_item.fontEngine; } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index d1e9b81faa..7112380043 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -435,6 +435,8 @@ void QRasterPaintEngine::init() case QImage::Format_ARGB4444_Premultiplied: case QImage::Format_ARGB32_Premultiplied: case QImage::Format_ARGB32: + case QImage::Format_RGBA8888_Premultiplied: + case QImage::Format_RGBA8888: gccaps |= PorterDuff; break; case QImage::Format_RGB32: @@ -443,6 +445,7 @@ void QRasterPaintEngine::init() case QImage::Format_RGB666: case QImage::Format_RGB888: case QImage::Format_RGB16: + case QImage::Format_RGBX8888: break; default: break; @@ -2261,6 +2264,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe case QImage::Format_ARGB6666_Premultiplied: case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB4444_Premultiplied: + case QImage::Format_RGBA8888_Premultiplied: // Combine premultiplied color with the opacity set on the painter. d->solid_color_filler.solid.color = ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 62379cd592..2e4f341e39 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -53,6 +53,7 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformfontdatabase.h> +#include <qpa/qplatformtheme.h> #include <stdlib.h> #include <limits.h> @@ -1103,6 +1104,17 @@ QFontDatabase::QFontDatabase() */ /*! + \enum QFontDatabase::SystemFont + + \value GeneralFont The default system font. + \value FixedFont The fixed font that the system recommends. + \value TitleFont The system standard font for titles. + \value SmallestReadableFont The smallest readable system font. + + \since 5.2 +*/ + +/*! Returns a sorted list of the available writing systems. This is list generated from information about all installed fonts on the system. @@ -2114,6 +2126,43 @@ QStringList QFontDatabase::applicationFontFamilies(int id) } /*! + \since 5.2 + + Returns the most adequate font for a given \a type case for proper integration + with the system's look and feel. + + \sa QGuiApplication::font() +*/ + +QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type) +{ + const QFont *font = 0; + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + switch (type) { + case GeneralFont: + font = theme->font(QPlatformTheme::SystemFont); + break; + case FixedFont: + font = theme->font(QPlatformTheme::FixedFont); + break; + case TitleFont: + font = theme->font(QPlatformTheme::TitleBarFont); + break; + case SmallestReadableFont: + font = theme->font(QPlatformTheme::MiniFont); + break; + } + } + + if (font) + return *font; + else if (QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration()) + return integration->fontDatabase()->defaultFont(); + else + return QFont(); +} + +/*! \fn bool QFontDatabase::removeApplicationFont(int id) \since 4.2 diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 05f1a85f24..bd603c3c4a 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -60,6 +60,7 @@ class Q_GUI_EXPORT QFontDatabase { Q_GADGET Q_ENUMS(WritingSystem) + Q_ENUMS(SystemFont) public: // do not re-order or delete entries from this enum without updating the // QPF2 format and makeqpf!! @@ -106,6 +107,13 @@ public: WritingSystemsCount }; + enum SystemFont { + GeneralFont, + FixedFont, + TitleFont, + SmallestReadableFont + }; + static QList<int> standardSizes(); QFontDatabase(); @@ -144,6 +152,8 @@ public: static bool supportsThreadedFontRendering(); + static QFont systemFont(SystemFont type); + private: static void createDatabase(); static void parseFontName(const QString &name, QString &foundry, QString &family); diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp index 62b99968bc..8e6ad7cd97 100644 --- a/src/gui/text/qfontdatabase_qpa.cpp +++ b/src/gui/text/qfontdatabase_qpa.cpp @@ -85,7 +85,7 @@ Q_GUI_EXPORT void qt_registerFont(const QString &familyName, const QString &sty size->handle = handle; } -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias) +void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias) { if (alias.isEmpty()) return; diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index 4399aff9da..293535a2e1 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -53,6 +53,8 @@ extern void qt_registerFont(const QString &familyname, const QString &stylename, bool scalable, int pixelSize, bool fixedPitch, const QSupportedWritingSystems &writingSystems, void *hanlde); +void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); + /*! \fn void QPlatformFontDatabase::registerQPF2Font(const QByteArray &dataArray, void *handle) @@ -517,6 +519,17 @@ QSupportedWritingSystems QPlatformFontDatabase::writingSystemsFromTrueTypeBits(q } /*! + Helper function that register the \a alias for the \a familyName. + + \since 5.2 +*/ + +void QPlatformFontDatabase::registerAliasToFontFamily(const QString &familyName, const QString &alias) +{ + qt_registerAliasToFontFamily(familyName, alias); +} + +/*! \class QPlatformFontDatabase \since 5.0 \internal diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index 6e53eba98b..6053f11051 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -122,6 +122,8 @@ public: QFont::Style style, QFont::Stretch stretch, bool antialiased, bool scalable, int pixelSize, bool fixedPitch, const QSupportedWritingSystems &writingSystems, void *handle); + + static void registerAliasToFontFamily(const QString &familyName, const QString &alias); }; QT_END_NAMESPACE diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 2fa7f0232d..229db80186 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -59,9 +59,9 @@ #include <algorithm> #include <stdlib.h> +#ifndef QT_NO_RAWFONT #include "qfontengine_qpa_p.h" - -#include <private/qharfbuzz_p.h> +#endif QT_BEGIN_NAMESPACE @@ -838,21 +838,6 @@ void QTextEngine::bidiReorder(int numItems, const quint8 *levels, int *visualOrd #endif } -// ask the font engine to find out which glyphs (as an index in the specific font) to use for the text in one item. -static bool stringToGlyphs(HB_ShaperItem *item, QGlyphLayout *glyphs, QFontEngine *fontEngine) -{ - int nGlyphs = item->num_glyphs; - - QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); - if (item->item.bidiLevel % 2) - shaperFlags |= QFontEngine::RightToLeft; - - bool result = fontEngine->stringToCMap(reinterpret_cast<const QChar *>(item->string + item->item.pos), item->item.length, glyphs, &nGlyphs, shaperFlags); - item->num_glyphs = nGlyphs; - glyphs->numGlyphs = nGlyphs; - return result; -} - // shape all the items that intersect with the line, taking tab widths into account to find out what text actually fits in the line. void QTextEngine::shapeLine(const QScriptLine &line) { @@ -892,19 +877,48 @@ void QTextEngine::shapeText(int item) const if (si.num_glyphs) return; - shapeTextWithHarfbuzz(item); - si.width = 0; + si.glyph_data_offset = layoutData->used; - if (!si.num_glyphs) - return; - QGlyphLayout glyphs = shapedGlyphs(&si); + const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.constData()) + si.position; + const int itemLength = length(item); + + if (!ensureSpace(itemLength)) + return; // ### report OOM error somehow + + QString casedString; + if (si.analysis.flags && si.analysis.flags <= QScriptAnalysis::SmallCaps) { + casedString.resize(itemLength); + ushort *uc = reinterpret_cast<ushort *>(casedString.data()); + for (int i = 0; i < itemLength; ++i) { + uint ucs4 = string[i]; + if (QChar::isHighSurrogate(ucs4) && i + 1 < itemLength) { + uint low = string[i + 1]; + if (QChar::isLowSurrogate(low)) { + ++i; + ucs4 = QChar::surrogateToUcs4(ucs4, low); + ucs4 = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) + : QChar::toUpper(ucs4); + // high part never changes in simple casing + uc[i] = QChar::lowSurrogate(ucs4); + } + } else { + uc[i] = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) + : QChar::toUpper(ucs4); + } + } + string = reinterpret_cast<const ushort *>(casedString.constData()); + } + QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading); + + bool kerningEnabled; bool letterSpacingIsAbsolute; QFixed letterSpacing, wordSpacing; #ifndef QT_NO_RAWFONT if (useRawFont) { QTextCharFormat f = format(&si); + kerningEnabled = f.fontKerning(); wordSpacing = QFixed::fromReal(f.fontWordSpacing()); letterSpacing = QFixed::fromReal(f.fontLetterSpacing()); letterSpacingIsAbsolute = true; @@ -912,6 +926,7 @@ void QTextEngine::shapeText(int item) const #endif { QFont font = this->font(si); + kerningEnabled = font.d->kerning; letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute; letterSpacing = font.d->letterSpacing; wordSpacing = font.d->wordSpacing; @@ -920,6 +935,13 @@ void QTextEngine::shapeText(int item) const letterSpacing *= font.d->dpi / qt_defaultDpiY(); } + si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, kerningEnabled); + if (!si.num_glyphs) + return; // ### report shaping errors somehow + layoutData->used += si.num_glyphs; + + QGlyphLayout glyphs = shapedGlyphs(&si); + if (letterSpacing != 0) { for (int i = 1; i < si.num_glyphs; ++i) { if (glyphs.attributes[i].clusterStart) { @@ -940,12 +962,12 @@ void QTextEngine::shapeText(int item) const } if (wordSpacing != 0) { for (int i = 0; i < si.num_glyphs; ++i) { - if (glyphs.attributes[i].justification == HB_Space - || glyphs.attributes[i].justification == HB_Arabic_Space) { + if (glyphs.attributes[i].justification == QGlyphAttributes::Space + || glyphs.attributes[i].justification == QGlyphAttributes::Arabic_Space) { // word spacing only gets added once to a consecutive run of spaces (see CSS spec) if (i + 1 == si.num_glyphs - ||(glyphs.attributes[i+1].justification != HB_Space - && glyphs.attributes[i+1].justification != HB_Arabic_Space)) + ||(glyphs.attributes[i+1].justification != QGlyphAttributes::Space + && glyphs.attributes[i+1].justification != QGlyphAttributes::Arabic_Space)) glyphs.advances_x[i] += wordSpacing; } } @@ -955,14 +977,6 @@ void QTextEngine::shapeText(int item) const si.width += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint; } -static inline bool hasCaseChange(const QScriptItem &si) -{ - return si.analysis.flags == QScriptAnalysis::SmallCaps || - si.analysis.flags == QScriptAnalysis::Uppercase || - si.analysis.flags == QScriptAnalysis::Lowercase; -} - - static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num) { if (num > 0 && destination.glyphs != source.glyphs) { @@ -973,84 +987,60 @@ static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLa } } +QT_BEGIN_INCLUDE_NAMESPACE + +#include <private/qharfbuzz_p.h> + +QT_END_INCLUDE_NAMESPACE + Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t)); Q_STATIC_ASSERT(sizeof(HB_GlyphAttributes) == sizeof(QGlyphAttributes)); Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed)); Q_STATIC_ASSERT(sizeof(HB_FixedPoint) == sizeof(QFixedPoint)); -/// take the item from layoutData->items and -void QTextEngine::shapeTextWithHarfbuzz(int item) const +// ask the font engine to find out which glyphs (as an index in the specific font) to use for the text in one item. +static bool stringToGlyphs(HB_ShaperItem *item, QGlyphLayout *glyphs, QFontEngine *fontEngine) { - QScriptItem &si = layoutData->items[item]; - - si.glyph_data_offset = layoutData->used; + int nGlyphs = item->num_glyphs; - QFontEngine *font = fontEngine(si, &si.ascent, &si.descent, &si.leading); + QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); + if (item->item.bidiLevel % 2) + shaperFlags |= QFontEngine::RightToLeft; - bool kerningEnabled; -#ifndef QT_NO_RAWFONT - if (useRawFont) { - QTextCharFormat f = format(&si); - kerningEnabled = f.fontKerning(); - } else -#endif - kerningEnabled = this->font(si).d->kerning; + bool result = fontEngine->stringToCMap(reinterpret_cast<const QChar *>(item->string + item->item.pos), item->item.length, glyphs, &nGlyphs, shaperFlags); + item->num_glyphs = nGlyphs; + glyphs->numGlyphs = nGlyphs; + return result; +} +int QTextEngine::shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, bool kerningEnabled) const +{ HB_ShaperItem entire_shaper_item; memset(&entire_shaper_item, 0, sizeof(entire_shaper_item)); - entire_shaper_item.string = reinterpret_cast<const HB_UChar16 *>(layoutData->string.constData()); - entire_shaper_item.stringLength = layoutData->string.length(); + entire_shaper_item.string = reinterpret_cast<const HB_UChar16 *>(string); + entire_shaper_item.stringLength = itemLength; entire_shaper_item.item.script = script_to_hbscript(si.analysis.script); - entire_shaper_item.item.pos = si.position; - entire_shaper_item.item.length = length(item); + entire_shaper_item.item.pos = 0; + entire_shaper_item.item.length = itemLength; entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel; - QVarLengthArray<HB_UChar16, 256> casedString; - if (hasCaseChange(si)) { - if (casedString.size() < static_cast<int>(entire_shaper_item.item.length)) - casedString.resize(entire_shaper_item.item.length); - HB_UChar16 *uc = casedString.data(); - for (uint i = 0; i < entire_shaper_item.item.length; ++i) { - uint ucs4 = entire_shaper_item.string[si.position + i]; - if (QChar::isHighSurrogate(ucs4)) { - uc[i] = ucs4; // high part never changes in simple casing - if (i + 1 < entire_shaper_item.item.length) { - ushort low = entire_shaper_item.string[si.position + i + 1]; - if (QChar::isLowSurrogate(low)) { - ucs4 = QChar::surrogateToUcs4(ucs4, low); - ucs4 = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) - : QChar::toUpper(ucs4); - uc[++i] = QChar::lowSurrogate(ucs4); - } - } - } else { - uc[i] = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) - : QChar::toUpper(ucs4); - } - } - entire_shaper_item.item.pos = 0; - entire_shaper_item.string = uc; - entire_shaper_item.stringLength = entire_shaper_item.item.length; - } - entire_shaper_item.shaperFlags = 0; if (!kerningEnabled) entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning; if (option.useDesignMetrics()) entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics; - entire_shaper_item.num_glyphs = qMax(layoutData->glyphLayout.numGlyphs - layoutData->used, int(entire_shaper_item.item.length)); - if (!ensureSpace(entire_shaper_item.num_glyphs)) - return; + entire_shaper_item.num_glyphs = itemLength; + QGlyphLayout initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); - if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { + if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, fontEngine)) { if (!ensureSpace(entire_shaper_item.num_glyphs)) - return; + return 0; initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); - if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { + if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, fontEngine)) { // ############ if this happens there's a bug in the fontengine - return; + return 0; } } @@ -1060,7 +1050,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const itemBoundaries[0] = entire_shaper_item.item.pos; itemBoundaries[1] = 0; - if (font->type() == QFontEngine::Multi) { + if (fontEngine->type() == QFontEngine::Multi) { uint lastEngine = 0; int charIdx = entire_shaper_item.item.pos; const int stringEnd = charIdx + entire_shaper_item.item.length; @@ -1099,18 +1089,17 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const if (shaper_item.num_glyphs < shaper_item.item.length) shaper_item.num_glyphs = shaper_item.item.length; - QFontEngine *actualFontEngine = font; + QFontEngine *actualFontEngine = fontEngine; uint engineIdx = 0; - if (font->type() == QFontEngine::Multi) { + if (fontEngine->type() == QFontEngine::Multi) { engineIdx = uint(availableGlyphs(&si).glyphs[glyph_pos] >> 24); - actualFontEngine = static_cast<QFontEngineMulti *>(font)->engine(engineIdx); + actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx); + si.ascent = qMax(actualFontEngine->ascent(), si.ascent); + si.descent = qMax(actualFontEngine->descent(), si.descent); + si.leading = qMax(actualFontEngine->leading(), si.leading); } - si.ascent = qMax(actualFontEngine->ascent(), si.ascent); - si.descent = qMax(actualFontEngine->descent(), si.descent); - si.leading = qMax(actualFontEngine->leading(), si.leading); - shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont(); shaper_item.face = (HB_Face)actualFontEngine->harfbuzzFace(); @@ -1120,7 +1109,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const do { if (!ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs)) - return; + return 0; const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos); if (shaper_item.num_glyphs > shaper_item.item.length) @@ -1137,8 +1126,6 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const } shaper_item.log_clusters = logClusters(&si) + shaper_item.item.pos - entire_shaper_item.item.pos; - -// qDebug(" .. num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs); } while (!qShapeItem(&shaper_item)); // this does the actual shaping via harfbuzz. QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos, shaper_item.num_glyphs); @@ -1158,10 +1145,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const glyph_pos += shaper_item.num_glyphs; } -// qDebug(" -> item: script=%d num_glyphs=%d", shaper_item.script, shaper_item.num_glyphs); - si.num_glyphs = glyph_pos; - - layoutData->used += si.num_glyphs; + return glyph_pos; } void QTextEngine::init(QTextEngine *e) @@ -1821,7 +1805,7 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, point->type = type; point->glyph = glyph; - if (type >= HB_Arabic_Normal) { + if (type >= QGlyphAttributes::Arabic_Normal) { QChar ch(0x640); // Kashida character QGlyphLayoutArray<8> glyphs; int nglyphs = 7; @@ -1829,7 +1813,7 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, if (glyphs.glyphs[0] && glyphs.advances_x[0] != 0) { point->kashidaWidth = glyphs.advances_x[0]; } else { - point->type = HB_NoJustification; + point->type = QGlyphAttributes::NoJustification; point->kashidaWidth = 0; } } @@ -1897,7 +1881,7 @@ void QTextEngine::justify(const QScriptLine &line) for (int i = 0; i < nItems; ++i) { QScriptItem &si = layoutData->items[firstItem + i]; - int kashida_type = HB_Arabic_Normal; + int kashida_type = QGlyphAttributes::Arabic_Normal; int kashida_pos = -1; int start = qMax(line.from - si.position, 0); @@ -1921,11 +1905,11 @@ void QTextEngine::justify(const QScriptLine &line) int justification = g.attributes[i].justification; switch(justification) { - case HB_NoJustification: + case QGlyphAttributes::NoJustification: break; - case HB_Space : + case QGlyphAttributes::Space : // fall through - case HB_Arabic_Space : + case QGlyphAttributes::Arabic_Space : if (kashida_pos >= 0) { // qDebug("kashida position at %d in word", kashida_pos); set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si)); @@ -1936,19 +1920,19 @@ void QTextEngine::justify(const QScriptLine &line) } } kashida_pos = -1; - kashida_type = HB_Arabic_Normal; + kashida_type = QGlyphAttributes::Arabic_Normal; // fall through - case HB_Character : + case QGlyphAttributes::Character : set(&justificationPoints[nPoints++], justification, g.mid(i), fontEngine(si)); maxJustify = qMax(maxJustify, justification); break; - case HB_Arabic_Normal : - case HB_Arabic_Waw : - case HB_Arabic_BaRa : - case HB_Arabic_Alef : - case HB_Arabic_HaaDal : - case HB_Arabic_Seen : - case HB_Arabic_Kashida : + case QGlyphAttributes::Arabic_Normal : + case QGlyphAttributes::Arabic_Waw : + case QGlyphAttributes::Arabic_BaRa : + case QGlyphAttributes::Arabic_Alef : + case QGlyphAttributes::Arabic_HaaDal : + case QGlyphAttributes::Arabic_Seen : + case QGlyphAttributes::Arabic_Kashida : if (justification >= kashida_type) { kashida_pos = i; kashida_type = justification; @@ -1977,9 +1961,9 @@ void QTextEngine::justify(const QScriptLine &line) // qDebug(" minKashida=%f, need=%f", minKashida.toReal(), need.toReal()); // distribute in priority order - if (maxJustify >= HB_Arabic_Normal) { + if (maxJustify >= QGlyphAttributes::Arabic_Normal) { while (need >= minKashida) { - for (int type = maxJustify; need >= minKashida && type >= HB_Arabic_Normal; --type) { + for (int type = maxJustify; need >= minKashida && type >= QGlyphAttributes::Arabic_Normal; --type) { for (int i = 0; need >= minKashida && i < nPoints; ++i) { if (justificationPoints[i].type == type && justificationPoints[i].kashidaWidth <= need) { justificationPoints[i].glyph.justifications->nKashidas++; @@ -1996,7 +1980,7 @@ void QTextEngine::justify(const QScriptLine &line) if (!need) goto end; - maxJustify = qMin(maxJustify, (int)HB_Space); + maxJustify = qMin(maxJustify, int(QGlyphAttributes::Space)); for (int type = maxJustify; need != 0 && type > 0; --type) { int n = 0; for (int i = 0; i < nPoints; ++i) { @@ -2438,12 +2422,13 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int const int end = si.position + length(&si); for (int i = si.position; i < end - 1; ++i) { - if (layoutData->string.at(i) == QLatin1Char('&')) { + if (layoutData->string.at(i) == QLatin1Char('&') + && !attributes[i + 1].whiteSpace && attributes[i + 1].graphemeBoundary) { const int gp = logClusters[i - si.position]; glyphs.attributes[gp].dontPrint = true; - attributes[i + 1].graphemeBoundary = false; - attributes[i + 1].lineBreak = false; - attributes[i + 1].whiteSpace = false; + // emulate grapheme cluster + attributes[i] = attributes[i + 1]; + memset(attributes + i + 1, 0, sizeof(QCharAttributes)); if (layoutData->string.at(i + 1) == QLatin1Char('&')) ++i; } diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index ec7f7407b2..6d46231c67 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -96,6 +96,20 @@ typedef quint8 q_hb_bitfield; #endif typedef struct { + typedef enum { + NoJustification= 0, /* Justification can't be applied after this glyph */ + Arabic_Space = 1, /* This glyph represents a space inside arabic text */ + Character = 2, /* Inter-character justification point follows this glyph */ + Space = 4, /* This glyph represents a blank outside an Arabic run */ + Arabic_Normal = 7, /* Normal Middle-Of-Word glyph that connects to the right (begin) */ + Arabic_Waw = 8, /* Next character is final form of Waw/Ain/Qaf/Fa */ + Arabic_BaRa = 9, /* Next two chars are Ba + Ra/Ya/AlefMaksura */ + Arabic_Alef = 10, /* Next character is final form of Alef/Tah/Lam/Kaf/Gaf */ + Arabic_HaaDal = 11, /* Next character is final form of Haa/Dal/Taa Marbutah */ + Arabic_Seen = 12, /* Initial or Medial form Of Seen/Sad */ + Arabic_Kashida = 13 /* Kashida(U+640) in middle of word */ + } JustificationClass; + q_hb_bitfield justification :4; /* Justification class */ q_hb_bitfield clusterStart :1; /* First glyph of representation of cluster */ q_hb_bitfield mark :1; /* needs to be positioned around base char */ @@ -685,7 +699,7 @@ private: void setBoundary(int strPos) const; void addRequiredBoundaries() const; void shapeText(int item) const; - void shapeTextWithHarfbuzz(int item) const; + int shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, bool kerningEnabled) const; void splitItem(int item, int pos) const; int endOfLine(int lineNum); diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index a279990f4c..c3e3716b26 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -85,6 +85,7 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif + , preConnectRequests(0) { channels = new QHttpNetworkConnectionChannel[channelCount]; } @@ -96,6 +97,7 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 channelCoun #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif + , preConnectRequests(0) { channels = new QHttpNetworkConnectionChannel[channelCount]; } @@ -541,6 +543,9 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor reply->d_func()->connectionChannel = &channels[0]; // will have the correct one set later HttpMessagePair pair = qMakePair(request, reply); + if (request.isPreConnect()) + preConnectRequests++; + switch (request.priority()) { case QHttpNetworkRequest::HighPriority: highPriorityQueue.prepend(pair); @@ -925,13 +930,24 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() // 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 // connected or not. This is to reuse connected channels before we connect new once. - int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count(); - for (int i = 0; i < channelCount; ++i) { + int queuedRequests = highPriorityQueue.count() + lowPriorityQueue.count(); + + // in case we have in-flight preconnect requests and normal requests, + // we only need one socket for each (preconnect, normal request) pair + int neededOpenChannels = queuedRequests; + if (preConnectRequests > 0) { + int normalRequests = queuedRequests - preConnectRequests; + neededOpenChannels = qMax(normalRequests, preConnectRequests); + } + for (int i = 0; i < channelCount && neededOpenChannels > 0; ++i) { bool connectChannel = false; if (channels[i].socket) { - if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) || (channels[i].socket->state() == QAbstractSocket::HostLookupState)) - queuedRequest--; - if ( queuedRequest <=0 ) + if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) + || (channels[i].socket->state() == QAbstractSocket::HostLookupState) + || channels[i].pendingEncrypt) // pendingEncrypt == "EncryptingState" + neededOpenChannels--; + + if (neededOpenChannels <= 0) break; if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) connectChannel = true; @@ -945,11 +961,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() else if (networkLayerState == IPv6) channels[i].networkLayerPreference = QAbstractSocket::IPv6Protocol; channels[i].ensureConnection(); - queuedRequest--; + neededOpenChannels--; } - - if ( queuedRequest <=0 ) - break; } } @@ -1270,6 +1283,11 @@ void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int #endif //QT_NO_SSL +void QHttpNetworkConnection::preConnectFinished() +{ + d_func()->preConnectRequests--; +} + #ifndef QT_NO_NETWORKPROXY // only called from QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, not // from QHttpNetworkConnectionChannel::handleAuthenticationChallenge diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 956499ddab..c54250f6ed 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -131,6 +131,8 @@ public: void setSslContext(QSharedPointer<QSslContext> context); #endif + void preConnectFinished(); + private: Q_DECLARE_PRIVATE(QHttpNetworkConnection) Q_DISABLE_COPY(QHttpNetworkConnection) @@ -239,6 +241,8 @@ public: QList<HttpMessagePair> highPriorityQueue; QList<HttpMessagePair> lowPriorityQueue; + int preConnectRequests; + #ifndef QT_NO_SSL QSharedPointer<QSslContext> sslContext; #endif diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index e14f426583..6e61eea5a4 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -183,6 +183,9 @@ void QHttpNetworkConnectionChannel::close() else state = QHttpNetworkConnectionChannel::ClosingState; + // pendingEncrypt must only be true in between connected and encrypted states + pendingEncrypt = false; + if (socket) socket->close(); } @@ -205,6 +208,17 @@ bool QHttpNetworkConnectionChannel::sendRequest() // _q_connected or _q_encrypted return false; } + QString scheme = request.url().scheme(); + if (scheme == QLatin1String("preconnect-http") + || scheme == QLatin1String("preconnect-https")) { + state = QHttpNetworkConnectionChannel::IdleState; + reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState; + allDone(); + connection->preConnectFinished(); // will only decrease the counter + reply = 0; // so we can reuse this channel + return true; // we have a working connection and are done + } + written = 0; // excluding the header bytesTotal = 0; diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index eb8a8869cc..1b9e1f5a53 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -290,6 +290,11 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) #endif { + QString scheme = newUrl.scheme(); + if (scheme == QLatin1String("preconnect-http") + || scheme == QLatin1String("preconnect-https")) + // make sure we do not close the socket after preconnecting + connectionCloseEnabled = false; } QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate() diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index e5b2eced99..d9f9b555d7 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -49,7 +49,8 @@ QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, QHttpNetworkRequest::Priority pri, const QUrl &newUrl) : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0), - autoDecompress(false), pipeliningAllowed(false), withCredentials(true) + autoDecompress(false), pipeliningAllowed(false), withCredentials(true), + preConnect(false) { } @@ -64,6 +65,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest customVerb = other.customVerb; withCredentials = other.withCredentials; ssl = other.ssl; + preConnect = other.preConnect; } QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate() @@ -74,8 +76,15 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot { return QHttpNetworkHeaderPrivate::operator==(other) && (operation == other.operation) + && (priority == other.priority) + && (uploadByteDevice == other.uploadByteDevice) + && (autoDecompress == other.autoDecompress) + && (pipeliningAllowed == other.pipeliningAllowed) + // we do not clear the customVerb in setOperation + && (operation != QHttpNetworkRequest::Custom || (customVerb == other.customVerb)) + && (withCredentials == other.withCredentials) && (ssl == other.ssl) - && (uploadByteDevice == other.uploadByteDevice); + && (preConnect == other.preConnect); } QByteArray QHttpNetworkRequestPrivate::methodName() const @@ -205,6 +214,15 @@ void QHttpNetworkRequest::setSsl(bool s) d->ssl = s; } +bool QHttpNetworkRequest::isPreConnect() const +{ + return d->preConnect; +} +void QHttpNetworkRequest::setPreConnect(bool preConnect) +{ + d->preConnect = preConnect; +} + qint64 QHttpNetworkRequest::contentLength() const { return d->contentLength(); diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index fc4a6928c6..ce9fbb1509 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -120,6 +120,9 @@ public: bool isSsl() const; void setSsl(bool); + bool isPreConnect() const; + void setPreConnect(bool preConnect); + void setUploadByteDevice(QNonContiguousByteDevice *bd); QNonContiguousByteDevice* uploadByteDevice() const; @@ -151,6 +154,7 @@ public: bool pipeliningAllowed; bool withCredentials; bool ssl; + bool preConnect; }; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index a2cee48b22..ee3911c72c 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -107,8 +107,14 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy) { QString result; QUrl copy = url; - bool isEncrypted = copy.scheme().toLower() == QLatin1String("https"); + QString scheme = copy.scheme().toLower(); + bool isEncrypted = scheme == QLatin1String("https"); copy.setPort(copy.port(isEncrypted ? 443 : 80)); + if (scheme == QLatin1String("preconnect-http")) { + copy.setScheme(QLatin1String("http")); + } else if (scheme == QLatin1String("preconnect-https")) { + copy.setScheme(QLatin1String("https")); + } result = copy.toString(QUrl::RemoveUserInfo | QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment | QUrl::FullyEncoded); diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index a895864d76..47cd928541 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -47,6 +47,7 @@ #include "qnetworkreply_p.h" #include "QtCore/qhash.h" #include "QtCore/qmutex.h" +#include "QtCore/qstringlist.h" #include "QtNetwork/private/qnetworksession_p.h" #include "qnetworkaccesscachebackend_p.h" @@ -110,6 +111,22 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM return 0; } +QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const +{ + if (QNetworkAccessBackendFactoryData::valid.load()) { + QMutexLocker locker(&factoryData()->mutex); + QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(); + QNetworkAccessBackendFactoryData::ConstIterator end = factoryData()->constEnd(); + QStringList schemes; + while (it != end) { + schemes += (*it)->supportedSchemes(); + ++it; + } + return schemes; + } + return QStringList(); +} + QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() { if (reply->outgoingDataBuffer) diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index bf284414e0..d9657cf750 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -62,6 +62,7 @@ class QAuthenticator; class QNetworkProxy; class QNetworkProxyQuery; class QNetworkRequest; +class QStringList; class QUrl; class QUrlInfo; class QSslConfiguration; @@ -219,6 +220,7 @@ class QNetworkAccessBackendFactory public: QNetworkAccessBackendFactory(); virtual ~QNetworkAccessBackendFactory(); + virtual QStringList supportedSchemes() const = 0; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const = 0; }; diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp index b6c04dddea..a91751523a 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend.cpp +++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp @@ -42,6 +42,7 @@ #include "qnetworkaccessdebugpipebackend_p.h" #include "QtCore/qdatastream.h" #include <QCoreApplication> +#include <QStringList> #include <QUrlQuery> #include "private/qnoncontiguousbytedevice_p.h" @@ -54,6 +55,11 @@ enum { WriteBufferSize = ReadBufferSize }; +QStringList QNetworkAccessDebugPipeBackendFactory::supportedSchemes() const +{ + return QStringList(QStringLiteral("debugpipe")); +} + QNetworkAccessBackend * QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const diff --git a/src/network/access/qnetworkaccessdebugpipebackend_p.h b/src/network/access/qnetworkaccessdebugpipebackend_p.h index 0ae49de132..7593dfa9b7 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend_p.h +++ b/src/network/access/qnetworkaccessdebugpipebackend_p.h @@ -102,6 +102,7 @@ private: class QNetworkAccessDebugPipeBackendFactory: public QNetworkAccessBackendFactory { public: + virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const; }; diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index 13428cc802..13e7394003 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -49,6 +49,17 @@ QT_BEGIN_NAMESPACE +QStringList QNetworkAccessFileBackendFactory::supportedSchemes() const +{ + QStringList schemes; + schemes << QStringLiteral("file") + << QStringLiteral("qrc"); +#if defined(Q_OS_ANDROID) + schemes << QStringLiteral("assets"); +#endif + return schemes; +} + QNetworkAccessBackend * QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const diff --git a/src/network/access/qnetworkaccessfilebackend_p.h b/src/network/access/qnetworkaccessfilebackend_p.h index a52ecef165..157461fee7 100644 --- a/src/network/access/qnetworkaccessfilebackend_p.h +++ b/src/network/access/qnetworkaccessfilebackend_p.h @@ -88,6 +88,7 @@ private: class QNetworkAccessFileBackendFactory: public QNetworkAccessBackendFactory { public: + virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const; }; diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index 737d7d0151..246eb41657 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -43,6 +43,7 @@ #include "qnetworkaccessmanager_p.h" #include "QtNetwork/qauthenticator.h" #include "private/qnoncontiguousbytedevice_p.h" +#include <QStringList> #ifndef QT_NO_FTP @@ -61,6 +62,11 @@ static QByteArray makeCacheKey(const QUrl &url) QUrl::RemoveFragment); } +QStringList QNetworkAccessFtpBackendFactory::supportedSchemes() const +{ + return QStringList(QStringLiteral("ftp")); +} + QNetworkAccessBackend * QNetworkAccessFtpBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h index 1bc377d80e..c006d450b8 100644 --- a/src/network/access/qnetworkaccessftpbackend_p.h +++ b/src/network/access/qnetworkaccessftpbackend_p.h @@ -111,6 +111,7 @@ private: class QNetworkAccessFtpBackendFactory: public QNetworkAccessBackendFactory { public: + virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const; }; diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 10d19bb7aa..91655ef485 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -96,9 +96,11 @@ bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& SecProtocolType protocolType = kSecProtocolTypeAny; if (scheme.compare(QLatin1String("ftp"),Qt::CaseInsensitive)==0) { protocolType = kSecProtocolTypeFTP; - } else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0) { + } else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0 + || scheme.compare(QLatin1String("preconnect-http"),Qt::CaseInsensitive)==0) { protocolType = kSecProtocolTypeHTTP; - } else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0) { + } else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0 + || scheme.compare(QLatin1String("preconnect-https"),Qt::CaseInsensitive)==0) { protocolType = kSecProtocolTypeHTTPS; } QByteArray proxyHostnameUtf8(proxyHostname.toUtf8()); @@ -431,6 +433,7 @@ static void ensureInitialized() QNetworkAccessManager::QNetworkAccessManager(QObject *parent) : QObject(*new QNetworkAccessManagerPrivate, parent) { + Q_D(QNetworkAccessManager); ensureInitialized(); qRegisterMetaType<QNetworkReply::NetworkError>(); @@ -447,6 +450,19 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) #endif qRegisterMetaType<QNetworkReply::NetworkError>(); qRegisterMetaType<QSharedPointer<char> >(); + +#ifndef QT_NO_BEARERMANAGEMENT + if (!d->networkSessionRequired) { + // if a session is required, we track online state through + // the QNetworkSession's signals + connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), + SLOT(_q_onlineStateChanged(bool))); + // we would need all active configurations to check for + // d->networkConfigurationManager.isOnline(), which is asynchronous + // and potentially expensive. We can just check the configuration here + d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active); + } +#endif } /*! @@ -833,6 +849,11 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ To restore the default network configuration set the network configuration to the value returned from QNetworkConfigurationManager::defaultConfiguration(). + Setting a network configuration means that the QNetworkAccessManager instance will only + be using the specified one. In particular, if the default network configuration changes + (upon e.g. Wifi being available), this new configuration needs to be enabled + manually if desired. + \snippet code/src_network_access_qnetworkaccessmanager.cpp 2 If an invalid network configuration is set, a network session will not be created. In this @@ -844,7 +865,10 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ */ void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config) { - d_func()->createSession(config); + Q_D(QNetworkAccessManager); + d->networkConfiguration = config; + d->customNetworkConfiguration = true; + d->createSession(config); } /*! @@ -926,19 +950,73 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess { Q_D(const QNetworkAccessManager); - QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession()); - if (networkSession) { - // d->online holds online/offline state of this network session. + if (d->networkSessionRequired) { + QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession()); + if (networkSession) { + // d->online holds online/offline state of this network session. + if (d->online) + return d->networkAccessible; + else + return NotAccessible; + } else { + // Network accessibility is either disabled or unknown. + return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility; + } + } else { if (d->online) return d->networkAccessible; else return NotAccessible; - } else { - // Network accessibility is either disabled or unknown. - return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility; } } +#ifndef QT_NO_SSL +/*! + \since 5.2 + + Initiates a connection to the host given by \a hostName at port \a port, using + \a sslConfiguration. This function is useful to complete the TCP and SSL handshake + to a host before the HTTPS request is made, resulting in a lower network latency. + + \note This function has no possibility to report errors. + + \sa connectToHost(), get(), post(), put(), deleteResource() +*/ +void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port, + const QSslConfiguration &sslConfiguration) +{ + QUrl url; + url.setHost(hostName); + url.setPort(port); + url.setScheme(QLatin1String("preconnect-https")); + QNetworkRequest request(url); + if (sslConfiguration != QSslConfiguration::defaultConfiguration()) + request.setSslConfiguration(sslConfiguration); + get(request); +} +#endif + +/*! + \since 5.2 + + Initiates a connection to the host given by \a hostName at port \a port. + This function is useful to complete the TCP handshake + to a host before the HTTP request is made, resulting in a lower network latency. + + \note This function has no possibility to report errors. + + \sa connectToHostEncrypted(), get(), post(), put(), deleteResource() +*/ +void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port) +{ + QUrl url; + url.setHost(hostName); + url.setPort(port); + url.setScheme(QLatin1String("preconnect-http")); + QNetworkRequest request(url); + get(request); +} + /*! \internal @@ -1050,10 +1128,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera return new QDisabledNetworkReply(this, req, op); } - if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.isEmpty())) { + if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) { QNetworkConfigurationManager manager; - if (!d->networkConfiguration.isEmpty()) { - d->createSession(manager.configurationFromIdentifier(d->networkConfiguration)); + if (!d->networkConfiguration.identifier().isEmpty()) { + d->createSession(d->networkConfiguration); } else { if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) d->createSession(manager.defaultConfiguration()); @@ -1083,9 +1161,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera #ifndef QT_NO_HTTP // Since Qt 5 we use the new QNetworkReplyHttpImpl - if (scheme == QLatin1String("http") + if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http") #ifndef QT_NO_SSL - || scheme == QLatin1String("https") + || scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https") #endif ) { QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData); @@ -1130,6 +1208,57 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera return reply; } +/*! + \since 5.2 + + Lists all the URL schemes supported by the access manager. + + \sa supportedSchemesImplementation() +*/ +QStringList QNetworkAccessManager::supportedSchemes() const +{ + QStringList schemes; + QNetworkAccessManager *self = const_cast<QNetworkAccessManager *>(this); // We know we call a const slot + QMetaObject::invokeMethod(self, "supportedSchemesImplementation", Qt::DirectConnection, + Q_RETURN_ARG(QStringList, schemes)); + schemes.removeDuplicates(); + return schemes; +} + +/*! + \since 5.2 + + Lists all the URL schemes supported by the access manager. + + You should not call this function directly; use + QNetworkAccessManager::supportedSchemes() instead. + + Reimplement this slot to provide your own supported schemes + in a QNetworkAccessManager subclass. It is for instance necessary + when your subclass provides support for new protocols. + + Because of binary compatibility constraints, the supportedSchemes() + method (introduced in Qt 5.2) is not virtual. Instead, supportedSchemes() + will dynamically detect and call this slot. + + \sa supportedSchemes() +*/ +QStringList QNetworkAccessManager::supportedSchemesImplementation() const +{ + Q_D(const QNetworkAccessManager); + + QStringList schemes = d->backendSupportedSchemes(); + // Those ones don't exist in backends +#ifndef QT_NO_HTTP + schemes << QStringLiteral("http"); +#ifndef QT_NO_SSL + if (QSslSocket::supportsSsl()) + schemes << QStringLiteral("https"); +#endif +#endif + schemes << QStringLiteral("data"); + return schemes; +} /*! \since 5.0 @@ -1403,7 +1532,7 @@ void QNetworkAccessManagerPrivate::_q_networkSessionClosed() Q_Q(QNetworkAccessManager); QSharedPointer<QNetworkSession> networkSession(getNetworkSession()); if (networkSession) { - networkConfiguration = networkSession->configuration().identifier(); + networkConfiguration = networkSession->configuration(); //disconnect from old session QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); @@ -1437,6 +1566,18 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession } } } + +void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) +{ + // if the user set a config, we only care whether this one is active. + // Otherwise, this QNAM is online if there is an online config. + if (customNetworkConfiguration) { + online = (networkConfiguration.state() & QNetworkConfiguration::Active); + } else { + online = isOnline; + } +} + #endif // QT_NO_BEARERMANAGEMENT QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart) diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 826c8e47d7..67b9bbcb07 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -43,6 +43,9 @@ #define QNETWORKACCESSMANAGER_H #include <QtCore/QObject> +#ifndef QT_NO_SSL +#include <QtNetwork/QSslConfiguration> +#endif QT_BEGIN_NAMESPACE @@ -97,6 +100,9 @@ public: explicit QNetworkAccessManager(QObject *parent = 0); ~QNetworkAccessManager(); + // ### Qt 6: turn into virtual + QStringList supportedSchemes() const; + void clearAccessCache(); #ifndef QT_NO_NETWORKPROXY @@ -132,6 +138,12 @@ public: NetworkAccessibility networkAccessible() const; #endif +#ifndef QT_NO_SSL + void connectToHostEncrypted(const QString &hostName, quint16 port = 443, + const QSslConfiguration &sslConfiguration = QSslConfiguration::defaultConfiguration()); +#endif + void connectToHost(const QString &hostName, quint16 port = 80); + Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); @@ -153,6 +165,9 @@ protected: virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData = 0); +protected Q_SLOTS: + QStringList supportedSchemesImplementation() const; + private: friend class QNetworkReplyImplPrivate; friend class QNetworkReplyHttpImpl; @@ -165,6 +180,7 @@ private: #ifndef QT_NO_BEARERMANAGEMENT Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) + Q_PRIVATE_SLOT(d_func(), void _q_onlineStateChanged(bool)) #endif }; diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index cf756dad7b..292755e7eb 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -60,6 +60,9 @@ #include "QtNetwork/qnetworkproxy.h" #include "QtNetwork/qnetworksession.h" #include "qnetworkaccessauthenticationmanager_p.h" +#ifndef QT_NO_BEARERMANAGEMENT +#include "QtNetwork/qnetworkconfigmanager.h" +#endif QT_BEGIN_NAMESPACE @@ -79,6 +82,10 @@ public: #endif #ifndef QT_NO_BEARERMANAGEMENT lastSessionState(QNetworkSession::Invalid), + networkConfiguration(networkConfigurationManager.defaultConfiguration()), + customNetworkConfiguration(false), + networkSessionRequired(networkConfigurationManager.capabilities() + & QNetworkConfigurationManager::NetworkSessionRequired), networkAccessible(QNetworkAccessManager::Accessible), activeReplyCount(0), online(false), @@ -117,6 +124,7 @@ public: #endif QNetworkAccessBackend *findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request); + QStringList backendSupportedSchemes() const; #ifndef QT_NO_BEARERMANAGEMENT void createSession(const QNetworkConfiguration &config); @@ -127,6 +135,7 @@ public: void _q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &config, bool isSeamless); void _q_networkSessionStateChanged(QNetworkSession::State state); + void _q_onlineStateChanged(bool isOnline); #endif QNetworkRequest prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart); @@ -148,7 +157,12 @@ public: QSharedPointer<QNetworkSession> networkSessionStrongRef; QWeakPointer<QNetworkSession> networkSessionWeakRef; QNetworkSession::State lastSessionState; - QString networkConfiguration; + QNetworkConfigurationManager networkConfigurationManager; + QNetworkConfiguration networkConfiguration; + // we need to track whether the user set a config or not, + // because the default config might change + bool customNetworkConfiguration; + bool networkSessionRequired; QNetworkAccessManager::NetworkAccessibility networkAccessible; int activeReplyCount; bool online; diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index c7d3846465..ddef970966 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -629,10 +629,15 @@ void QNetworkReplyHttpImplPrivate::postRequest() QUrl url = request.url(); httpRequest.setUrl(url); - bool ssl = url.scheme().toLower() == QLatin1String("https"); + QString scheme = url.scheme().toLower(); + bool ssl = (scheme == QLatin1String("https") + || scheme == QLatin1String("preconnect-https")); q->setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl); httpRequest.setSsl(ssl); + bool preConnect = (scheme == QLatin1String("preconnect-http") + || scheme == QLatin1String("preconnect-https")); + httpRequest.setPreConnect(preConnect); #ifndef QT_NO_NETWORKPROXY QNetworkProxy transparentProxy, cacheProxy; diff --git a/src/network/bearer/qnetworkconfiguration.cpp b/src/network/bearer/qnetworkconfiguration.cpp index 615ef21661..fae4aad76e 100644 --- a/src/network/bearer/qnetworkconfiguration.cpp +++ b/src/network/bearer/qnetworkconfiguration.cpp @@ -41,6 +41,12 @@ #include "qnetworkconfiguration.h" #include "qnetworkconfiguration_p.h" +#include <QDebug> + +#ifdef Q_OS_BLACKBERRY +#include "private/qcore_unix_p.h" // qt_safe_open +#include <sys/pps.h> +#endif // Q_OS_BLACKBERRY QT_BEGIN_NAMESPACE @@ -193,13 +199,88 @@ QT_BEGIN_NAMESPACE \value BearerEthernet The configuration is for an Ethernet interfaces. \value BearerWLAN The configuration is for a Wireless LAN interface. \value Bearer2G The configuration is for a CSD, GPRS, HSCSD, EDGE or cdmaOne interface. + \value Bearer3G The configuration is for a 3G interface. + \value Bearer4G The configuration is for a 4G interface. \value BearerCDMA2000 The configuration is for CDMA interface. \value BearerWCDMA The configuration is for W-CDMA/UMTS interface. \value BearerHSPA The configuration is for High Speed Packet Access (HSPA) interface. \value BearerBluetooth The configuration is for a Bluetooth interface. \value BearerWiMAX The configuration is for a WiMAX interface. + \value BearerEVDO The configuration is for an EVDO (3G) interface. + \value BearerLTE The configuration is for a LTE (4G) interface. */ +#ifdef Q_OS_BLACKBERRY +static const char cellularStatusFile[] = "/pps/services/radioctrl/modem0/status_public"; + +static QNetworkConfiguration::BearerType cellularStatus() +{ + QNetworkConfiguration::BearerType ret = QNetworkConfiguration::BearerUnknown; + + int cellularStatusFD; + if ((cellularStatusFD = qt_safe_open(cellularStatusFile, O_RDONLY)) == -1) { + qWarning() << Q_FUNC_INFO << "failed to open" << cellularStatusFile; + return ret; + } + char buf[2048]; + if (qt_safe_read(cellularStatusFD, &buf, sizeof(buf)) == -1) { + qWarning() << Q_FUNC_INFO << "read from PPS file failed:" << strerror(errno); + qt_safe_close(cellularStatusFD); + return ret; + } + pps_decoder_t ppsDecoder; + if (pps_decoder_initialize(&ppsDecoder, buf) != PPS_DECODER_OK) { + qWarning() << Q_FUNC_INFO << "failed to initialize PPS decoder"; + qt_safe_close(cellularStatusFD); + return ret; + } + pps_decoder_error_t err; + if ((err = pps_decoder_push(&ppsDecoder, 0)) != PPS_DECODER_OK) { + qWarning() << Q_FUNC_INFO << "pps_decoder_push failed" << err; + pps_decoder_cleanup(&ppsDecoder); + qt_safe_close(cellularStatusFD); + return ret; + } + if (!pps_decoder_is_integer(&ppsDecoder, "network_technology")) { + qWarning() << Q_FUNC_INFO << "field has not the expected data type"; + pps_decoder_cleanup(&ppsDecoder); + qt_safe_close(cellularStatusFD); + return ret; + } + int type; + if (!pps_decoder_get_int(&ppsDecoder, "network_technology", &type) + == PPS_DECODER_OK) { + qWarning() << Q_FUNC_INFO << "could not read bearer type from PPS"; + pps_decoder_cleanup(&ppsDecoder); + qt_safe_close(cellularStatusFD); + return ret; + } + switch (type) { + case 0: // 0 == NONE + break; // unhandled + case 1: // fallthrough, 1 == GSM + case 4: // 4 == CDMA_1X + ret = QNetworkConfiguration::Bearer2G; + break; + case 2: // 2 == UMTS + ret = QNetworkConfiguration::BearerWCDMA; + break; + case 8: // 8 == EVDO + ret = QNetworkConfiguration::BearerEVDO; + break; + case 16: // 16 == LTE + ret = QNetworkConfiguration::BearerLTE; + break; + default: + qWarning() << Q_FUNC_INFO << "unhandled bearer type" << type; + break; + } + pps_decoder_cleanup(&ppsDecoder); + qt_safe_close(cellularStatusFD); + return ret; +} +#endif // Q_OS_BLACKBERRY + /*! Constructs an invalid configuration object. @@ -412,6 +493,8 @@ QList<QNetworkConfiguration> QNetworkConfiguration::children() const function can be used to retrieve a textural type name for the bearer. An invalid network configuration always returns the BearerUnknown value. + + \sa bearerTypeName(), bearerTypeFamily() */ QNetworkConfiguration::BearerType QNetworkConfiguration::bearerType() const { @@ -420,10 +503,74 @@ QNetworkConfiguration::BearerType QNetworkConfiguration::bearerType() const QMutexLocker locker(&d->mutex); +#ifdef Q_OS_BLACKBERRY + // for cellular configurations, we need to determine the exact + // type right now, because it might have changed after the last scan + if (d->bearerType == QNetworkConfiguration::Bearer2G) { + QNetworkConfiguration::BearerType type = cellularStatus(); + // if reading the status failed for some reason, just + // fall back to 2G + return (type == QNetworkConfiguration::BearerUnknown) + ? QNetworkConfiguration::Bearer2G : type; + } +#endif // Q_OS_BLACKBERRY + return d->bearerType; } /*! + \since 5.2 + + Returns the bearer type family used by this network configuration. + The following table lists how bearerType() values map to + bearerTypeFamily() values: + + \table + \header + \li bearer type + \li bearer type family + \row + \li BearerUnknown, Bearer2G, BearerEthernet, BearerWLAN, + BearerBluetooth + \li (same type) + \row + \li BearerCDMA2000, BearerEVDO, BearerWCDMA, BearerHSPA, Bearer3G + \li Bearer3G + \row + \li BearerWiMAX, BearerLTE, Bearer4G + \li Bearer4G + \endtable + + An invalid network configuration always returns the BearerUnknown value. + + \sa bearerType(), bearerTypeName() +*/ +QNetworkConfiguration::BearerType QNetworkConfiguration::bearerTypeFamily() const +{ + QNetworkConfiguration::BearerType type = bearerType(); + switch (type) { + case QNetworkConfiguration::BearerUnknown: // fallthrough + case QNetworkConfiguration::Bearer2G: // fallthrough + case QNetworkConfiguration::BearerEthernet: // fallthrough + case QNetworkConfiguration::BearerWLAN: // fallthrough + case QNetworkConfiguration::BearerBluetooth: + return type; + case QNetworkConfiguration::BearerCDMA2000: // fallthrough + case QNetworkConfiguration::BearerEVDO: // fallthrough + case QNetworkConfiguration::BearerWCDMA: // fallthrough + case QNetworkConfiguration::BearerHSPA: // fallthrough + case QNetworkConfiguration::Bearer3G: + return QNetworkConfiguration::Bearer3G; + case QNetworkConfiguration::BearerWiMAX: // fallthrough + case QNetworkConfiguration::BearerLTE: // fallthrough + case QNetworkConfiguration::Bearer4G: + return QNetworkConfiguration::Bearer4G; + default: + qWarning() << "unknown bearer type" << type; + return QNetworkConfiguration::BearerUnknown; + } +} +/*! Returns the type of bearer used by this network configuration as a string. The string is not translated and therefore can not be shown to the user. The subsequent table @@ -450,6 +597,12 @@ QNetworkConfiguration::BearerType QNetworkConfiguration::bearerType() const \li Bearer2G \li 2G \row + \li Bearer3G + \li 3G + \row + \li Bearer4G + \li 4G + \row \li BearerCDMA2000 \li CDMA2000 \row @@ -464,13 +617,19 @@ QNetworkConfiguration::BearerType QNetworkConfiguration::bearerType() const \row \li BearerWiMAX \li WiMAX + \row + \li BearerEVDO + \li EVDO + \row + \li BearerLTE + \li LTE \endtable This function returns an empty string if this is an invalid configuration, a network configuration of type \l QNetworkConfiguration::ServiceNetwork or \l QNetworkConfiguration::UserChoice. - \sa bearerType() + \sa bearerType(), bearerTypeFamily() */ QString QNetworkConfiguration::bearerTypeName() const { @@ -489,7 +648,25 @@ QString QNetworkConfiguration::bearerTypeName() const case BearerWLAN: return QStringLiteral("WLAN"); case Bearer2G: +#ifdef Q_OS_BLACKBERRY + { + // for cellular configurations, we need to determine the exact + // type right now, because it might have changed after the last scan + QNetworkConfiguration::BearerType type = cellularStatus(); + if (type == QNetworkConfiguration::BearerWCDMA) { + return QStringLiteral("WCDMA"); + } else if (type == QNetworkConfiguration::BearerEVDO) { + return QStringLiteral("EVDO"); + }else if (type == QNetworkConfiguration::BearerLTE) { + return QStringLiteral("LTE"); + } + } +#endif // Q_OS_BLACKBERRY return QStringLiteral("2G"); + case Bearer3G: + return QStringLiteral("3G"); + case Bearer4G: + return QStringLiteral("4G"); case BearerCDMA2000: return QStringLiteral("CDMA2000"); case BearerWCDMA: @@ -500,6 +677,10 @@ QString QNetworkConfiguration::bearerTypeName() const return QStringLiteral("Bluetooth"); case BearerWiMAX: return QStringLiteral("WiMAX"); + case BearerEVDO: + return QStringLiteral("EVDO"); + case BearerLTE: + return QStringLiteral("LTE"); case BearerUnknown: break; } diff --git a/src/network/bearer/qnetworkconfiguration.h b/src/network/bearer/qnetworkconfiguration.h index 25dafcb282..8887525a2f 100644 --- a/src/network/bearer/qnetworkconfiguration.h +++ b/src/network/bearer/qnetworkconfiguration.h @@ -97,7 +97,11 @@ public: BearerWCDMA, BearerHSPA, BearerBluetooth, - BearerWiMAX + BearerWiMAX, + BearerEVDO, + BearerLTE, + Bearer3G, + Bearer4G }; StateFlags state() const; @@ -105,6 +109,7 @@ public: Purpose purpose() const; BearerType bearerType() const; + BearerType bearerTypeFamily() const; QString bearerTypeName() const; QString identifier() const; diff --git a/src/network/doc/qtnetwork.qdocconf b/src/network/doc/qtnetwork.qdocconf index 048b3325b6..f4779ae8fe 100644 --- a/src/network/doc/qtnetwork.qdocconf +++ b/src/network/doc/qtnetwork.qdocconf @@ -40,3 +40,6 @@ exampledirs += ../../../examples/network \ imagedirs += images \ ../../../examples/network/doc/images + +navigation.landingpage = "Qt Network" +navigation.cppclassespage = "Qt Network C++ Classes" diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc index 6d9f6023ab..2faafff82e 100644 --- a/src/network/doc/src/qtnetwork.qdoc +++ b/src/network/doc/src/qtnetwork.qdoc @@ -65,6 +65,7 @@ \module QtNetwork \title Qt Network C++ Classes \ingroup modules + \qtvariable network \brief Provides classes to make network programming easier and portable To include the definitions of the module's classes, use the diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index dc67b0d835..5ef428305c 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -189,7 +189,7 @@ static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, } else { scopeId->clear(); } - return QIPAddressUtils::parseIp6(addr, tmp.constBegin(), tmp.constEnd()); + return QIPAddressUtils::parseIp6(addr, tmp.constBegin(), tmp.constEnd()) == 0; } bool QHostAddressPrivate::parse() diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index 4e33001d8d..ec771e1f49 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -161,12 +161,20 @@ QT_BEGIN_NAMESPACE mechanism for renegotiating the connection parameters. When enabled, this option can allow connections for legacy servers, but it introduces the possibility that an attacker could inject plaintext into the SSL session. + \value SslOptionDisableSessionSharing Disables SSL session sharing via + the session ID handshake attribute. + \value SslOptionDisableSessionPersistence Disables storing the SSL session + in ASN.1 format as returned by QSslConfiguration::session(). Enabling + this feature adds memory overhead of approximately 1K per used session + ticket. By default, SslOptionDisableEmptyFragments is turned on since this causes problems with a large number of servers. SslOptionDisableLegacyRenegotiation is also turned on, since it introduces a security risk. SslOptionDisableCompression is turned on to prevent the attack publicised by - CRIME. The other options are turned off. + CRIME. + SslOptionDisableSessionPersistence is turned on to optimize memory usage. + The other options are turned off. Note: Availability of above options depends on the version of the SSL backend in use. diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h index 06d80965e2..21d03cb703 100644 --- a/src/network/ssl/qssl.h +++ b/src/network/ssl/qssl.h @@ -95,7 +95,9 @@ namespace QSsl { SslOptionDisableSessionTickets = 0x02, SslOptionDisableCompression = 0x04, SslOptionDisableServerNameIndication = 0x08, - SslOptionDisableLegacyRenegotiation = 0x10 + SslOptionDisableLegacyRenegotiation = 0x10, + SslOptionDisableSessionSharing = 0x20, + SslOptionDisableSessionPersistence = 0x40 }; Q_DECLARE_FLAGS(SslOptions, SslOption) } diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index afbd4fac77..6cc06dfbd2 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -49,7 +49,8 @@ QT_BEGIN_NAMESPACE const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOptionDisableEmptyFragments |QSsl::SslOptionDisableLegacyRenegotiation - |QSsl::SslOptionDisableCompression; + |QSsl::SslOptionDisableCompression + |QSsl::SslOptionDisableSessionPersistence; /*! \class QSslConfiguration @@ -182,7 +183,9 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->peerVerifyMode == other.d->peerVerifyMode && d->peerVerifyDepth == other.d->peerVerifyDepth && d->allowRootCertOnDemandLoading == other.d->allowRootCertOnDemandLoading && - d->sslOptions == other.d->sslOptions; + d->sslOptions == other.d->sslOptions && + d->sslSession == other.d->sslSession && + d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint; } /*! @@ -216,7 +219,9 @@ bool QSslConfiguration::isNull() const d->privateKey.isNull() && d->peerCertificate.isNull() && d->peerCertificateChain.count() == 0 && - d->sslOptions == QSslConfigurationPrivate::defaultSslOptions); + d->sslOptions == QSslConfigurationPrivate::defaultSslOptions && + d->sslSession.isNull() && + d->sslSessionTicketLifeTimeHint == -1); } /*! @@ -594,6 +599,60 @@ bool QSslConfiguration::testSslOption(QSsl::SslOption option) const } /*! + \since 5.2 + + If QSsl::SslOptionDisableSessionPersistence was turned off, this + function returns the session used in the SSL handshake in ASN.1 + format, suitable to e.g. be persisted to disk. If no session was + used or QSsl::SslOptionDisableSessionPersistence was not turned off, + this function returns an empty QByteArray. + + \b{Note:} When persisting the session to disk or similar, be + careful not to expose the session to a potential attacker, as + knowledge of the session allows for eavesdropping on data + encrypted with the session parameters. + + \sa setSession(), QSsl::SslOptionDisableSessionPersistence, setSslOption() + */ +QByteArray QSslConfiguration::session() const +{ + return d->sslSession; +} + +/*! + \since 5.2 + + Sets the session to be used in an SSL handshake. + QSsl::SslOptionDisableSessionPersistence must be turned off + for this to work, and \a session must be in ASN.1 format + as returned by session(). + + \sa session(), QSsl::SslOptionDisableSessionPersistence, setSslOption() + */ +void QSslConfiguration::setSession(const QByteArray &session) +{ + d->sslSession = session; +} + +/*! + \since 5.2 + + If QSsl::SslOptionDisableSessionPersistence was turned off, this + function returns the session ticket life time hint sent by the + server (which might be 0). + If the server did not send a session ticket (e.g. when + resuming a session or when the server does not support it) or + QSsl::SslOptionDisableSessionPersistence was not turned off, + this function returns -1. + + \sa session(), QSsl::SslOptionDisableSessionPersistence, setSslOption() + */ +int QSslConfiguration::sessionTicketLifeTimeHint() const +{ + return d->sslSessionTicketLifeTimeHint; +} + +/*! Returns the default SSL configuration to be used in new SSL connections. diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 0000382ed5..949ce70d4c 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -124,6 +124,10 @@ public: void setSslOption(QSsl::SslOption option, bool on); bool testSslOption(QSsl::SslOption option) const; + QByteArray session() const; + void setSession(const QByteArray &session); + int sessionTicketLifeTimeHint() const; + static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h index 54b7264d3d..71ee8d2bfe 100644 --- a/src/network/ssl/qsslconfiguration_p.h +++ b/src/network/ssl/qsslconfiguration_p.h @@ -85,7 +85,8 @@ public: peerVerifyDepth(0), allowRootCertOnDemandLoading(true), peerSessionShared(false), - sslOptions(QSslConfigurationPrivate::defaultSslOptions) + sslOptions(QSslConfigurationPrivate::defaultSslOptions), + sslSessionTicketLifeTimeHint(-1) { } QSslCertificate peerCertificate; @@ -110,6 +111,9 @@ public: Q_AUTOTEST_EXPORT static const QSsl::SslOptions defaultSslOptions; + QByteArray sslSession; + int sslSessionTicketLifeTimeHint; + // in qsslsocket.cpp: static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslcontext.cpp b/src/network/ssl/qsslcontext.cpp index 22ad42116b..6d281c390d 100644 --- a/src/network/ssl/qsslcontext.cpp +++ b/src/network/ssl/qsslcontext.cpp @@ -57,7 +57,8 @@ extern QString getErrorsFromOpenSsl(); QSslContext::QSslContext() : ctx(0), pkey(0), - session(0) + session(0), + m_sessionTicketLifeTimeHint(-1) { } @@ -258,6 +259,10 @@ init_context: if (sslContext->sslConfiguration.peerVerifyDepth() != 0) q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth()); + // set persisted session if the user set it + if (!configuration.session().isEmpty()) + sslContext->setSessionASN1(configuration.session()); + return sslContext; } @@ -267,6 +272,12 @@ SSL* QSslContext::createSsl() SSL* ssl = q_SSL_new(ctx); q_SSL_clear(ssl); + if (!session && !sessionASN1().isEmpty() + && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) { + const unsigned char *data = reinterpret_cast<const unsigned char *>(m_sessionASN1.constData()); + session = q_d2i_SSL_SESSION(0, &data, m_sessionASN1.size()); // refcount is 1 already, set by function above + } + if (session) { // Try to resume the last session we cached if (!q_SSL_set_session(ssl, session)) { @@ -292,8 +303,34 @@ bool QSslContext::cacheSession(SSL* ssl) // cache the session the caller gave us and increase reference count session = q_SSL_get1_session(ssl); - return (session != NULL); + if (session && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) { + int sessionSize = q_i2d_SSL_SESSION(session, 0); + if (sessionSize > 0) { + m_sessionASN1.resize(sessionSize); + unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data()); + if (!q_i2d_SSL_SESSION(session, &data)) + qWarning("could not store persistent version of SSL session"); + m_sessionTicketLifeTimeHint = session->tlsext_tick_lifetime_hint; + } + } + + return (session != 0); +} + +QByteArray QSslContext::sessionASN1() const +{ + return m_sessionASN1; +} + +void QSslContext::setSessionASN1(const QByteArray &session) +{ + m_sessionASN1 = session; +} + +int QSslContext::sessionTicketLifeTimeHint() const +{ + return m_sessionTicketLifeTimeHint; } QSslError::SslError QSslContext::error() const diff --git a/src/network/ssl/qsslcontext_p.h b/src/network/ssl/qsslcontext_p.h index c8578d349e..2b596798a6 100644 --- a/src/network/ssl/qsslcontext_p.h +++ b/src/network/ssl/qsslcontext_p.h @@ -69,6 +69,9 @@ public: SSL* createSsl(); bool cacheSession(SSL*); // should be called when handshake completed + QByteArray sessionASN1() const; + void setSessionASN1(const QByteArray &sessionASN1); + int sessionTicketLifeTimeHint() const; protected: QSslContext(); @@ -76,6 +79,8 @@ private: SSL_CTX* ctx; EVP_PKEY *pkey; SSL_SESSION *session; + QByteArray m_sessionASN1; + int m_sessionTicketLifeTimeHint; QSslError::SslError errorCode; QString errorStr; QSslConfiguration sslConfiguration; diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index f2310356df..0e7ac39d14 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -903,6 +903,8 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.peerVerifyMode = configuration.peerVerifyMode(); d->configuration.protocol = configuration.protocol(); d->configuration.sslOptions = configuration.d->sslOptions; + d->configuration.sslSession = configuration.session(); + d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint(); // if the CA certificates were set explicitly (either via // QSslConfiguration::setCaCertificates() or QSslSocket::setCaCertificates(), diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 30103edc29..e94df10fed 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE #if defined(Q_OS_MACX) #define kSecTrustSettingsDomainSystem 2 // so we do not need to include the header file - PtrSecCertificateGetData QSslSocketPrivate::ptrSecCertificateGetData = 0; + PtrSecCertificateCopyData QSslSocketPrivate::ptrSecCertificateCopyData = 0; PtrSecTrustSettingsCopyCertificates QSslSocketPrivate::ptrSecTrustSettingsCopyCertificates = 0; PtrSecTrustCopyAnchorCertificates QSslSocketPrivate::ptrSecTrustCopyAnchorCertificates = 0; #elif defined(Q_OS_WIN) @@ -492,8 +492,8 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if defined(Q_OS_MACX) QLibrary securityLib("/System/Library/Frameworks/Security.framework/Versions/Current/Security"); if (securityLib.load()) { - ptrSecCertificateGetData = (PtrSecCertificateGetData) securityLib.resolve("SecCertificateGetData"); - if (!ptrSecCertificateGetData) + ptrSecCertificateCopyData = (PtrSecCertificateCopyData) securityLib.resolve("SecCertificateCopyData"); + if (!ptrSecCertificateCopyData) qWarning("could not resolve symbols in security library"); // should never happen ptrSecTrustSettingsCopyCertificates = (PtrSecTrustSettingsCopyCertificates) securityLib.resolve("SecTrustSettingsCopyCertificates"); @@ -629,12 +629,11 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() CFArrayRef cfCerts; OSStatus status = 1; - OSStatus SecCertificateGetData ( - SecCertificateRef certificate, - CSSM_DATA_PTR data + CFDataRef SecCertificateCopyData ( + SecCertificateRef certificate ); - if (ptrSecCertificateGetData) { + if (ptrSecCertificateCopyData) { if (ptrSecTrustSettingsCopyCertificates) status = ptrSecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts); else if (ptrSecTrustCopyAnchorCertificates) @@ -643,15 +642,16 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() CFIndex size = CFArrayGetCount(cfCerts); for (CFIndex i = 0; i < size; ++i) { SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); - CSSM_DATA data; - CSSM_DATA_PTR dataPtr = &data; - if (ptrSecCertificateGetData(cfCert, dataPtr)) { + CFDataRef data; + + data = ptrSecCertificateCopyData(cfCert); + + if (data == NULL) { qWarning("error retrieving a CA certificate from the system store"); } else { - int len = data.Length; - char *rawData = reinterpret_cast<char *>(data.Data); - QByteArray rawCert(rawData, len); + QByteArray rawCert = QByteArray::fromRawData((const char *)CFDataGetBytePtr(data), CFDataGetLength(data)); systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der)); + CFRelease(data); } } CFRelease(cfCerts); @@ -1458,9 +1458,17 @@ void QSslSocketBackendPrivate::continueHandshake() #endif // Cache this SSL session inside the QSslContext - if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionTickets)) { - if (!sslContextPointer->cacheSession(ssl)) + if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) { + if (!sslContextPointer->cacheSession(ssl)) { sslContextPointer.clear(); // we could not cache the session + } else { + // Cache the session for permanent usage as well + if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) { + if (!sslContextPointer->sessionASN1().isEmpty()) + configuration.sslSession = sslContextPointer->sessionASN1(); + configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint(); + } + } } connectionEncrypted = true; diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index d2a349455e..a010075436 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -332,6 +332,8 @@ DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYA DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return) DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return) DEFINEFUNC(const char *, SSLeay_version, int a, a, return 0, return) +DEFINEFUNC2(int, i2d_SSL_SESSION, SSL_SESSION *in, in, unsigned char **pp, pp, return 0, return) +DEFINEFUNC3(SSL_SESSION *, d2i_SSL_SESSION, SSL_SESSION **a, a, const unsigned char **pp, pp, long length, length, return 0, return) #define RESOLVEFUNC(func) \ if (!(_q_##func = _q_PTR_##func(libs.first->resolve(#func))) \ @@ -548,7 +550,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() #ifdef Q_OS_OPENBSD libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint); #endif -#ifdef SHLIB_VERSION_NUMBER +#if defined(SHLIB_VERSION_NUMBER) && !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER> libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER)); libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER)); @@ -801,6 +803,8 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(SSL_CTX_load_verify_locations) RESOLVEFUNC(SSLeay) RESOLVEFUNC(SSLeay_version) + RESOLVEFUNC(i2d_SSL_SESSION) + RESOLVEFUNC(d2i_SSL_SESSION) symbolsResolved = true; delete libs.first; diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 2e01ee4d31..1fd98cc7fb 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -469,6 +469,8 @@ void q_OPENSSL_add_all_algorithms_conf(); int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath); long q_SSLeay(); const char *q_SSLeay_version(int type); +int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp); +SSL_SESSION *q_d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length); // Helper function class QDateTime; diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 6ce34ba06f..6281753225 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE #if defined(Q_OS_MACX) - typedef OSStatus (*PtrSecCertificateGetData)(SecCertificateRef, CSSM_DATA_PTR); + typedef CFDataRef (*PtrSecCertificateCopyData)(SecCertificateRef); typedef OSStatus (*PtrSecTrustSettingsCopyCertificates)(int, CFArrayRef*); typedef OSStatus (*PtrSecTrustCopyAnchorCertificates)(CFArrayRef*); #endif @@ -146,7 +146,7 @@ public: static void addDefaultCaCertificates(const QList<QSslCertificate> &certs); #if defined(Q_OS_MACX) - static PtrSecCertificateGetData ptrSecCertificateGetData; + static PtrSecCertificateCopyData ptrSecCertificateCopyData; static PtrSecTrustSettingsCopyCertificates ptrSecTrustSettingsCopyCertificates; static PtrSecTrustCopyAnchorCertificates ptrSecTrustCopyAnchorCertificates; #elif defined(Q_OS_WIN) diff --git a/src/opengl/doc/qtopengl.qdocconf b/src/opengl/doc/qtopengl.qdocconf index e76a23844b..5b6d09dfcd 100644 --- a/src/opengl/doc/qtopengl.qdocconf +++ b/src/opengl/doc/qtopengl.qdocconf @@ -19,7 +19,7 @@ exampledirs += ../../../examples/opengl \ imagedirs += images \ ../../../examples/opengl/doc/images -depends += qtcore qtgui qtwidgets +depends += qtdoc qtcore qtgui qtwidgets examplesinstallpath = opengl @@ -50,3 +50,6 @@ qhp.QtOpenGL.subprojects.classes.title = C++ Classes qhp.QtOpenGL.subprojects.classes.indexTitle = Qt OpenGL C++ Classes qhp.QtOpenGL.subprojects.classes.selectors = class fake:headerfile qhp.QtOpenGL.subprojects.classes.sortPages = true + +navigation.landingpage = "Qt OpenGL" +navigation.cppclassespage = "Qt OpenGL C++ Classes" diff --git a/src/opengl/doc/src/qtopengl-module.qdoc b/src/opengl/doc/src/qtopengl-module.qdoc index 901766ae46..8619f04a97 100644 --- a/src/opengl/doc/src/qtopengl-module.qdoc +++ b/src/opengl/doc/src/qtopengl-module.qdoc @@ -29,6 +29,7 @@ \module QtOpenGL \title Qt OpenGL C++ Classes \ingroup modules + \qtvariable opengl \brief The Qt OpenGL module offers classes that make it easy to use OpenGL in Qt applications. diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_p.h b/src/platformsupport/devicediscovery/qdevicediscovery_p.h index c78c57b86f..d9bd9a78e4 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_p.h +++ b/src/platformsupport/devicediscovery/qdevicediscovery_p.h @@ -72,7 +72,8 @@ public: Device_Touchscreen = 0x04, Device_Keyboard = 0x08, Device_DRM = 0x10, - Device_Tablet = 0x20, + Device_DRM_PrimaryGPU = 0x20, + Device_Tablet = 0x40, Device_InputMask = Device_Mouse | Device_Touchpad | Device_Touchscreen | Device_Keyboard | Device_Tablet, Device_VideoMask = Device_DRM }; diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp index 9e0ce47e18..ac902b4140 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp +++ b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp @@ -149,8 +149,16 @@ QStringList QDeviceDiscovery::scanConnectedDevices() QString candidate = QString::fromUtf8(udev_device_get_devnode(udevice)); if ((m_types & Device_InputMask) && candidate.startsWith(QLatin1String(QT_EVDEV_DEVICE))) devices << candidate; - if ((m_types & Device_VideoMask) && candidate.startsWith(QLatin1String(QT_DRM_DEVICE))) - devices << candidate; + if ((m_types & Device_VideoMask) && candidate.startsWith(QLatin1String(QT_DRM_DEVICE))) { + if (m_types & Device_DRM_PrimaryGPU) { + udev_device *pci = udev_device_get_parent_with_subsystem_devtype(udevice, "pci", 0); + if (pci) { + if (qstrcmp(udev_device_get_sysattr_value(pci, "boot_vga"), "1") == 0) + devices << candidate; + } + } else + devices << candidate; + } udev_device_unref(udevice); } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 8152f74067..34ba21afdc 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -106,6 +106,14 @@ bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface) EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface); + // shortcut: on some GPUs, eglMakeCurrent is not a cheap operation + if (eglGetCurrentContext() == m_eglContext && + eglGetCurrentDisplay() == m_eglDisplay && + eglGetCurrentSurface(EGL_READ) == eglSurface && + eglGetCurrentSurface(EGL_DRAW) == eglSurface) { + return true; + } + bool ok = eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_eglContext); if (!ok) qWarning("QEGLPlatformContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this); diff --git a/src/platformsupport/eglconvenience/qxlibeglintegration.cpp b/src/platformsupport/eglconvenience/qxlibeglintegration.cpp index 58f24c0a04..80453816fc 100644 --- a/src/platformsupport/eglconvenience/qxlibeglintegration.cpp +++ b/src/platformsupport/eglconvenience/qxlibeglintegration.cpp @@ -41,17 +41,6 @@ #include "qxlibeglintegration_p.h" -static int countBits(unsigned long mask) -{ - int count = 0; - while (mask != 0) { - if (mask & 1) - ++count; - mask >>= 1; - } - return count; -} - VisualID QXlibEglIntegration::getCompatibleVisualId(Display *display, EGLDisplay eglDisplay, EGLConfig config) { VisualID visualId = 0; @@ -92,9 +81,9 @@ VisualID QXlibEglIntegration::getCompatibleVisualId(Display *display, EGLDisplay return visualId; } - int visualRedSize = countBits(chosenVisualInfo->red_mask); - int visualGreenSize = countBits(chosenVisualInfo->green_mask); - int visualBlueSize = countBits(chosenVisualInfo->blue_mask); + int visualRedSize = qPopulationCount(chosenVisualInfo->red_mask); + int visualGreenSize = qPopulationCount(chosenVisualInfo->green_mask); + int visualBlueSize = qPopulationCount(chosenVisualInfo->blue_mask); int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size bool visualMatchesConfig = false; diff --git a/src/platformsupport/eventdispatchers/eventdispatchers.pri b/src/platformsupport/eventdispatchers/eventdispatchers.pri index 6e16a46b34..ec556486b1 100644 --- a/src/platformsupport/eventdispatchers/eventdispatchers.pri +++ b/src/platformsupport/eventdispatchers/eventdispatchers.pri @@ -8,6 +8,14 @@ HEADERS +=\ $$PWD/qgenericunixeventdispatcher_p.h\ } +ios { +OBJECTIVE_SOURCES +=\ + $$PWD/qioseventdispatcher.mm + +HEADERS +=\ + $$PWD/qioseventdispatcher_p.h +} + contains(QT_CONFIG, glib) { SOURCES +=$$PWD/qeventdispatcher_glib.cpp HEADERS +=$$PWD/qeventdispatcher_glib_p.h diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/platformsupport/eventdispatchers/qioseventdispatcher.mm index e9bf039047..ab3036143d 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/platformsupport/eventdispatchers/qioseventdispatcher.mm @@ -39,8 +39,7 @@ ** ****************************************************************************/ -#include "qioseventdispatcher.h" -#import "qiosapplicationdelegate.h" +#include "qioseventdispatcher_p.h" #include <qdebug.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/QThread> @@ -118,7 +117,9 @@ void QIOSEventDispatcher::maybeStartCFRunLoopTimer() m_runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QIOSEventDispatcher::nonBlockingTimerRunLoopCallback, &info); Q_ASSERT(m_runLoopTimerRef != 0); - CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimerRef, kCFRunLoopCommonModes); + CFRunLoopRef mainRunLoop = CFRunLoopGetMain(); + CFRunLoopAddTimer(mainRunLoop, m_runLoopTimerRef, kCFRunLoopCommonModes); + CFRunLoopAddTimer(mainRunLoop, m_runLoopTimerRef, (CFStringRef) UITrackingRunLoopMode); } else { struct timespec tv; // Calculate when the next timer should fire: @@ -168,6 +169,7 @@ QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent) m_blockingTimerRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); Q_ASSERT(m_blockingTimerRunLoopSource); CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); + CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, (CFStringRef) UITrackingRunLoopMode); // source used to handle posted events: context.perform = QIOSEventDispatcher::postedEventsRunLoopCallback; @@ -184,7 +186,9 @@ QIOSEventDispatcher::~QIOSEventDispatcher() qDeleteAll(m_timerInfoList); maybeStopCFRunLoopTimer(); - CFRunLoopRemoveSource(CFRunLoopGetMain(), m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); + + CFRunLoopRemoveSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); + CFRunLoopRemoveSource(mainRunLoop, m_blockingTimerRunLoopSource, (CFStringRef) UITrackingRunLoopMode); CFRelease(m_blockingTimerRunLoopSource); m_cfSocketNotifier.removeSocketNotifiers(); @@ -199,14 +203,42 @@ bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec); bool useExecMode = execFlagSet && !excludeUserEvents; + CFTimeInterval distantFuture = CFTimeInterval(3600. * 24. * 365. * 10.); + SInt32 result; + if (useExecMode) { - NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; - while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted); + while (!m_interrupted) { + // Run a single pass on the runloop to unblock it + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + + // Run the default runloop until interrupted (by Qt or UIKit) + if (result != kCFRunLoopRunFinished) + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, distantFuture, false); + + // App has quit or Qt has interrupted? + if (result == kCFRunLoopRunFinished || m_interrupted) + break; + + // Runloop was interrupted by UIKit? + if (result == kCFRunLoopRunStopped && !m_interrupted) { + // Run runloop in UI tracking mode + if (CFRunLoopRunInMode((CFStringRef) UITrackingRunLoopMode, + distantFuture, false) == kCFRunLoopRunFinished) + break; + } + } eventsProcessed = true; } else { if (!(flags & QEventLoop::WaitForMoreEvents)) wakeUp(); - eventsProcessed = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + + // Run runloop in default mode + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, distantFuture, true); + if (result != kCFRunLoopRunFinished) { + // Run runloop in UI tracking mode + CFRunLoopRunInMode((CFStringRef) UITrackingRunLoopMode, distantFuture, false); + } + eventsProcessed = (result == kCFRunLoopRunHandledSource); } return eventsProcessed; } @@ -309,8 +341,9 @@ void QIOSEventDispatcher::wakeUp() void QIOSEventDispatcher::interrupt() { - wakeUp(); + // Stop the runloop, which will cause processEvents() to exit m_interrupted = true; + CFRunLoopStop(CFRunLoopGetMain()); } void QIOSEventDispatcher::flush() diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/platformsupport/eventdispatchers/qioseventdispatcher_p.h index 53a75618ce..53a75618ce 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.h +++ b/src/platformsupport/eventdispatchers/qioseventdispatcher_p.h diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index afe634dc4b..6b8a82352d 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -317,8 +317,6 @@ static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) return stylehint; } -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); - void QFontconfigDatabase::populateFontDatabase() { FcFontSet *fonts; @@ -453,7 +451,7 @@ void QFontconfigDatabase::populateFontDatabase() // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; for (int k = 1; FcPatternGetString(fonts->fonts[i], FC_FAMILY, k, &value) == FcResultMatch; ++k) - qt_registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value)); + QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value)); } FcFontSetDestroy (fonts); diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 1e15a9e62c..5139f11d23 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -176,6 +176,10 @@ QCoreTextFontDatabase::~QCoreTextFontDatabase() void QCoreTextFontDatabase::populateFontDatabase() { + // The caller (QFontDB) expects the db to be populate only with system fonts, so we need + // to make sure that any previously registered app fonts become invisible. + removeApplicationFonts(); + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; QCFType<CTFontCollectionRef> collection = CTFontCollectionCreateFromAvailableFonts(0); @@ -186,82 +190,87 @@ void QCoreTextFontDatabase::populateFontDatabase() if (! fonts) return; - QString foundryName = QLatin1String("CoreText"); const int numFonts = CFArrayGetCount(fonts); for (int i = 0; i < numFonts; ++i) { CTFontDescriptorRef font = (CTFontDescriptorRef) CFArrayGetValueAtIndex(fonts, i); - QCFString familyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL); - QCFString styleName = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL); - QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute); - QFont::Weight weight = QFont::Normal; - QFont::Style style = QFont::StyleNormal; - QFont::Stretch stretch = QFont::Unstretched; - bool fixedPitch = false; - - if (styles) { - if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) { - Q_ASSERT(CFNumberIsFloatType(weightValue)); - double d; - if (CFNumberGetValue(weightValue, kCFNumberDoubleType, &d)) - weight = (d > 0.0) ? QFont::Bold : QFont::Normal; - } - if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) { - Q_ASSERT(CFNumberIsFloatType(italic)); - double d; - if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) { - if (d > 0.0) - style = QFont::StyleItalic; - } - } - if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) { - int d; - if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) { - if (d & kCTFontMonoSpaceTrait) - fixedPitch = true; - if (d & kCTFontExpandedTrait) - stretch = QFont::Expanded; - else if (d & kCTFontCondensedTrait) - stretch = QFont::Condensed; - } - } - } + populateFromDescriptor(font); + } - int pixelSize = 0; - if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) { - if (CFNumberIsFloatType(size)) { - double d; - CFNumberGetValue(size, kCFNumberDoubleType, &d); - pixelSize = d; - } else { - CFNumberGetValue(size, kCFNumberIntType, &pixelSize); + [pool release]; +} + +void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font) +{ + QString foundryName = QStringLiteral("CoreText"); + QCFString familyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL); + QCFString styleName = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL); + QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute); + QFont::Weight weight = QFont::Normal; + QFont::Style style = QFont::StyleNormal; + QFont::Stretch stretch = QFont::Unstretched; + bool fixedPitch = false; + + if (styles) { + if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) { + Q_ASSERT(CFNumberIsFloatType(weightValue)); + double d; + if (CFNumberGetValue(weightValue, kCFNumberDoubleType, &d)) + weight = (d > 0.0) ? QFont::Bold : QFont::Normal; + } + if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) { + Q_ASSERT(CFNumberIsFloatType(italic)); + double d; + if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) { + if (d > 0.0) + style = QFont::StyleItalic; } } - - QSupportedWritingSystems writingSystems; - if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) { - CFIndex length = CFArrayGetCount(languages); - for (int i = 1; i < LanguageCount; ++i) { - if (!languageForWritingSystem[i]) - continue; - QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII); - if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang)) - writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) { + int d; + if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) { + if (d & kCTFontMonoSpaceTrait) + fixedPitch = true; + if (d & kCTFontExpandedTrait) + stretch = QFont::Expanded; + else if (d & kCTFontCondensedTrait) + stretch = QFont::Condensed; } } + } - CFRetain(font); - QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, - true /* antialiased */, true /* scalable */, - pixelSize, fixedPitch, writingSystems, (void *) font); + int pixelSize = 0; + if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) { + if (CFNumberIsFloatType(size)) { + double d; + CFNumberGetValue(size, kCFNumberDoubleType, &d); + pixelSize = d; + } else { + CFNumberGetValue(size, kCFNumberIntType, &pixelSize); + } + } - // We need to map back and forth between PostScript-names and family-names for fallback list construction - CFStringRef psName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute); - psNameToFamily[QCFString::toQString((NSString *) psName)] = familyName; - familyNameToPsName[familyName] = QCFString::toQString((NSString *) psName); - CFRelease(psName); + QSupportedWritingSystems writingSystems; + if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) { + CFIndex length = CFArrayGetCount(languages); + for (int i = 1; i < LanguageCount; ++i) { + if (!languageForWritingSystem[i]) + continue; + QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII); + if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang)) + writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + } } - [pool release]; + CFRetain(font); + QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, + true /* antialiased */, true /* scalable */, + pixelSize, fixedPitch, writingSystems, (void *) font); + + // We need to map back and forth between PostScript-names and family-names for fallback list construction + CFStringRef psName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute); + psNameToFamily[QCFString::toQString((NSString *) psName)] = familyName; + familyNameToPsName[familyName] = QCFString::toQString((NSString *) psName); + CFRelease(psName); } void QCoreTextFontDatabase::releaseHandle(void *handle) @@ -473,6 +482,7 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData bool success = CTFontManagerRegisterGraphicsFont(cgFont, &error); if (success) { font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); + m_applicationGraphicsFonts.append(QCFType<CGFontRef>::constructFromGet(cgFont)); } else { NSLog(@"Unable to register font: %@", error); CFRelease(error); @@ -484,12 +494,13 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false); bool success = CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error); if (success) { - const void *keys[] = { fontURL }; - const void *values[] = { kCTFontURLAttribute }; + const void *keys[] = { kCTFontURLAttribute }; + const void *values[] = { fontURL }; QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithAttributes(attributes); font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL); + m_applicationURLFonts.append(QCFType<CFURLRef>::constructFromGet(fontURL)); } else { NSLog(@"Unable to register font: %@", error); CFRelease(error); @@ -499,6 +510,10 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData if (font) { QStringList families; families.append(QCFString(CTFontCopyFamilyName(font))); + + QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font); + populateFromDescriptor(descriptor); + CFRelease(font); return families; } @@ -534,9 +549,12 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData QStringList families; for (int i = 0; i < containedFonts.size(); ++i) { QCFType<CTFontRef> font = CTFontCreateWithPlatformFont(containedFonts[i], 12.0, NULL, NULL); + QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font); + populateFromDescriptor(descriptor); families.append(QCFString(CTFontCopyFamilyName(font))); } + m_applicationFonts.append(fontContainer); return families; } #endif @@ -569,5 +587,28 @@ QList<int> QCoreTextFontDatabase::standardSizes() const return ret; } +void QCoreTextFontDatabase::removeApplicationFonts() +{ +#ifdef Q_OS_MACX +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { + CFErrorRef error; + for (int i = 0; i < m_applicationGraphicsFonts.count(); ++i) + CTFontManagerUnregisterGraphicsFont(m_applicationGraphicsFonts[i], &error); + m_applicationGraphicsFonts.clear(); + + for (int i = 0; i < m_applicationURLFonts.count(); ++i) + CTFontManagerUnregisterFontsForURL(m_applicationURLFonts[i], kCTFontManagerScopeProcess, &error); + m_applicationURLFonts.clear(); + } +#else + for (int i = 0; i < m_applicationFonts.count(); ++i) + ATSFontDeactivate(m_applicationFonts[i], 0, kATSOptionFlagsDoNotNotify); + m_applicationFonts.clear(); + ATSFontNotify(kATSFontNotifyActionFontsChanged, 0); +#endif +#endif +} + QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index 8536ad9123..c3bb4d428a 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -43,6 +43,14 @@ #define QCORETEXTFONTDATABASE_H #include <qpa/qplatformfontdatabase.h> +#include <private/qcore_mac_p.h> + +#ifndef Q_OS_IOS +#include <ApplicationServices/ApplicationServices.h> +#else +#include <CoreText/CoreText.h> +#include <CoreGraphics/CoreGraphics.h> +#endif QT_BEGIN_NAMESPACE @@ -63,9 +71,21 @@ public: QList<int> standardSizes() const; private: + void populateFromDescriptor(CTFontDescriptorRef font); + mutable QString defaultFontName; mutable QHash<QString, QString> psNameToFamily; mutable QHash<QString, QString> familyNameToPsName; + + void removeApplicationFonts(); +#ifdef Q_OS_MACX +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + QVector<QCFType<CGFontRef> > m_applicationGraphicsFonts; + QVector<QCFType<CFURLRef> > m_applicationURLFonts; +#else + QVector<ATSFontContainerRef> m_applicationFonts; +#endif +#endif }; QT_END_NAMESPACE diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp index fedaa3a655..77ea0f1db8 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp +++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp @@ -54,16 +54,24 @@ enum { debug = 0 }; static inline QByteArray detectDesktopEnvironment() { - if (!qEnvironmentVariableIsEmpty("KDE_FULL_SESSION")) - return QByteArray("KDE"); - // Check Unity first, whose older versions also have "GNOME_DESKTOP_SESSION_ID" set. const QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP"); - if (xdgCurrentDesktop == "Unity") - return QByteArrayLiteral("UNITY"); - // GNOME_DESKTOP_SESSION_ID is deprecated for some reason, but still check it - if (qgetenv("DESKTOP_SESSION") == "gnome" || !qEnvironmentVariableIsEmpty("GNOME_DESKTOP_SESSION_ID")) - return QByteArray("GNOME"); - return QByteArray("UNKNOWN"); + if (!xdgCurrentDesktop.isEmpty()) + return xdgCurrentDesktop.toUpper(); // KDE, GNOME, UNITY, LXDE, MATE, XFCE... + + // Classic fallbacks + if (!qEnvironmentVariableIsEmpty("KDE_FULL_SESSION")) + return QByteArrayLiteral("KDE"); + if (!qEnvironmentVariableIsEmpty("GNOME_DESKTOP_SESSION_ID")) + return QByteArrayLiteral("GNOME"); + + // Fallback to checking $DESKTOP_SESSION (unreliable) + const QByteArray desktopSession = qgetenv("DESKTOP_SESSION"); + if (desktopSession == "gnome") + return QByteArrayLiteral("GNOME"); + if (desktopSession == "xfce") + return QByteArrayLiteral("XFCE"); + + return QByteArrayLiteral("UNKNOWN"); } static inline bool checkExecutable(const QString &candidate, QString *result) diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index fdd45a49c5..fb50230382 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -95,9 +95,13 @@ public: QGenericUnixThemePrivate() : QPlatformThemePrivate() , systemFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize) - { } + , fixedFont(QStringLiteral("monospace"), systemFont.pointSize()) + { + fixedFont.setStyleHint(QFont::TypeWriter); + } const QFont systemFont; + QFont fixedFont; }; QGenericUnixTheme::QGenericUnixTheme() @@ -108,9 +112,14 @@ QGenericUnixTheme::QGenericUnixTheme() const QFont *QGenericUnixTheme::font(Font type) const { Q_D(const QGenericUnixTheme); - if (type == QPlatformTheme::SystemFont) + switch (type) { + case QPlatformTheme::SystemFont: return &d->systemFont; - return 0; + case QPlatformTheme::FixedFont: + return &d->fixedFont; + default: + return 0; + } } // Helper to return the icon theme paths from XDG. @@ -240,11 +249,18 @@ void QKdeThemePrivate::refresh() toolButtonStyle = Qt::ToolButtonTextUnderIcon; } - // Read system font, ignore 'fixed' 'smallestReadableFont' - if (QFont *systemFont = readKdeFontSetting(kdeSettings, QStringLiteral("font"))) { + // Read system font, ignore 'smallestReadableFont' + if (QFont *systemFont = readKdeFontSetting(kdeSettings, QStringLiteral("font"))) resources.fonts[QPlatformTheme::SystemFont] = systemFont; - } else { + else resources.fonts[QPlatformTheme::SystemFont] = new QFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize); + + if (QFont *fixedFont = readKdeFontSetting(kdeSettings, QStringLiteral("fixed"))) { + resources.fonts[QPlatformTheme::FixedFont] = fixedFont; + } else { + fixedFont = new QFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize); + fixedFont->setStyleHint(QFont::TypeWriter); + resources.fonts[QPlatformTheme::FixedFont] = fixedFont; } } @@ -461,9 +477,13 @@ class QGnomeThemePrivate : public QPlatformThemePrivate public: QGnomeThemePrivate() : systemFont(QLatin1Literal(defaultSystemFontNameC), defaultSystemFontSize) - {} + , fixedFont(QStringLiteral("monospace"), systemFont.pointSize()) + { + fixedFont.setStyleHint(QFont::TypeWriter); + } const QFont systemFont; + QFont fixedFont; }; QGnomeTheme::QGnomeTheme() @@ -501,10 +521,14 @@ QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const const QFont *QGnomeTheme::font(Font type) const { Q_D(const QGnomeTheme); - if (type == QPlatformTheme::SystemFont) - return &d->systemFont; - - return 0; + switch (type) { + case QPlatformTheme::SystemFont: + return &d->systemFont; + case QPlatformTheme::FixedFont: + return &d->fixedFont; + default: + return 0; + } } /*! @@ -534,7 +558,11 @@ QStringList QGenericUnixTheme::themeNames() #ifndef QT_NO_SETTINGS result.push_back(QLatin1String(QKdeTheme::name)); #endif - } else { // Gnome, Unity, other Gtk-based desktops like XFCE. + } else if (desktopEnvironment == QByteArrayLiteral("GNOME") || + desktopEnvironment == QByteArrayLiteral("UNITY") || + desktopEnvironment == QByteArrayLiteral("MATE") || + desktopEnvironment == QByteArrayLiteral("XFCE") || + desktopEnvironment == QByteArrayLiteral("LXDE")) { // Gtk-based desktops // prefer the GTK2 theme implementation with native dialogs etc. result.push_back(QStringLiteral("gtk2")); // fallback to the generic Gnome theme if loading the GTK2 theme fails diff --git a/src/plugins/bearer/blackberry/qbbengine.cpp b/src/plugins/bearer/blackberry/qbbengine.cpp index ab1ba9aa19..37093a09ec 100644 --- a/src/plugins/bearer/blackberry/qbbengine.cpp +++ b/src/plugins/bearer/blackberry/qbbengine.cpp @@ -98,10 +98,9 @@ interfaceType(netstatus_interface_type_t type) return QNetworkConfiguration::BearerBluetooth; case NETSTATUS_INTERFACE_TYPE_CELLULAR: - //### TODO not sure which BearerType would be the best - //to return here. We need to be able to get more - //information on the bearer type in order to return - //the exact match. + // The exact bearer type is determined in QNetworkConfiguration + // at the time this info is queried, because opposed to the + // information here the type might change quickly. return QNetworkConfiguration::Bearer2G; case NETSTATUS_INTERFACE_TYPE_VPN: diff --git a/src/plugins/platforms/android/src/androidjniinput.cpp b/src/plugins/platforms/android/src/androidjniinput.cpp index 75cb617ca8..b31e74bb52 100644 --- a/src/plugins/platforms/android/src/androidjniinput.cpp +++ b/src/plugins/platforms/android/src/androidjniinput.cpp @@ -411,6 +411,24 @@ namespace QtAndroidInput case 0x00000018: return Qt::Key_VolumeUp; + case 0x000000b7: // KEYCODE_PROG_RED + return Qt::Key_Red; + + case 0x000000b8: // KEYCODE_PROG_GREEN + return Qt::Key_Green; + + case 0x000000b9: // KEYCODE_PROG_YELLOW + return Qt::Key_Yellow; + + case 0x000000ba: // KEYCODE_PROG_BLUE + return Qt::Key_Blue; + + case 0x000000a6: // KEYCODE_CHANNEL_UP + return Qt::Key_ChannelUp; + + case 0x000000a7: // KEYCODE_CHANNEL_DOWN + return Qt::Key_ChannelDown; + case 0x00000000: // KEYCODE_UNKNOWN case 0x00000011: // KEYCODE_STAR ?!?!? case 0x00000012: // KEYCODE_POUND ?!?!? diff --git a/src/plugins/platforms/android/src/androidplatformplugin.cpp b/src/plugins/platforms/android/src/androidplatformplugin.cpp index 71c5096e16..79e23c2d32 100644 --- a/src/plugins/platforms/android/src/androidplatformplugin.cpp +++ b/src/plugins/platforms/android/src/androidplatformplugin.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QAndroidPlatformIntegrationPlugin: public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "android.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "android.json") public: QPlatformIntegration *create(const QString &key, const QStringList ¶mList); }; diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp index 91ad2b368f..5ef0998a49 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp @@ -66,6 +66,7 @@ #endif #include "qandroidplatformtheme.h" +#include "qandroidsystemlocale.h" QT_BEGIN_NAMESPACE @@ -108,6 +109,8 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ m_androidFDB = new QAndroidPlatformFontDatabase(); m_androidPlatformServices = new QAndroidPlatformServices(); m_androidPlatformClipboard = new QAndroidPlatformClipboard(); + + m_androidSystemLocale = new QAndroidSystemLocale; } bool QAndroidPlatformIntegration::hasCapability(Capability cap) const @@ -115,6 +118,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const switch (cap) { case ThreadedPixmaps: return true; case NonFullScreenWindows: return false; + case NativeWidgets: return false; default: #ifndef ANDROID_PLUGIN_OPENGL return QPlatformIntegration::hasCapability(cap); @@ -183,6 +187,7 @@ QAndroidPlatformIntegration::~QAndroidPlatformIntegration() { delete m_androidPlatformNativeInterface; delete m_androidFDB; + delete m_androidSystemLocale; QtAndroid::setAndroidPlatformIntegration(NULL); } QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.h b/src/plugins/platforms/android/src/qandroidplatformintegration.h index 6cc191701d..346d0c0953 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.h @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE class QDesktopWidget; class QAndroidPlatformServices; +class QAndroidSystemLocale; #ifdef ANDROID_PLUGIN_OPENGL class QAndroidOpenGLPlatformWindow; @@ -154,6 +155,7 @@ private: QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface; QAndroidPlatformServices *m_androidPlatformServices; QPlatformClipboard *m_androidPlatformClipboard; + QAndroidSystemLocale *m_androidSystemLocale; mutable QAndroidInputContext m_platformInputContext; }; diff --git a/src/plugins/platforms/android/src/qandroidsystemlocale.cpp b/src/plugins/platforms/android/src/qandroidsystemlocale.cpp new file mode 100644 index 0000000000..24ae503335 --- /dev/null +++ b/src/plugins/platforms/android/src/qandroidsystemlocale.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qandroidsystemlocale.h" +#include "androidjnimain.h" +#include "private/qjniobject_p.h" +#include "private/qjnihelpers_p.h" +#include "qdatetime.h" +#include "qstringlist.h" +#include "qvariant.h" + +QT_BEGIN_NAMESPACE + +QAndroidSystemLocale::QAndroidSystemLocale() : m_locale(QLocale::C) +{ +} + +void QAndroidSystemLocale::getLocaleFromJava() const +{ + QWriteLocker locker(&m_lock); + + QJNILocalRef<jobject> javaLocaleRef; + QJNIObject javaActivity(QtAndroid::activity()); + if (javaActivity.isValid()) { + QJNIObject resources(javaActivity.callObjectMethod<jobject>("getResources", "()Landroid/content/res/Resources;").object()); + QJNIObject configuration(resources.callObjectMethod<jobject>("getConfiguration", "()Landroid/content/res/Configuration;").object()); + + javaLocaleRef = configuration.getObjectField<jobject>("locale", "Ljava/util/Locale;"); + } else { + javaLocaleRef = QJNIObject::callStaticObjectMethod<jobject>("java/util/Locale", "getDefault", "()Ljava/util/Locale;"); + } + + QJNIObject javaLocaleObject(javaLocaleRef.object()); + QString languageCode = qt_convertJString(javaLocaleObject.callObjectMethod<jstring>("getLanguage", "()Ljava/lang/String;").object()); + QString countryCode = qt_convertJString(javaLocaleObject.callObjectMethod<jstring>("getCountry", "()Ljava/lang/String;").object()); + + m_locale = QLocale(languageCode + QLatin1Char('_') + countryCode); +} + +QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const +{ + if (type == LocaleChanged) { + getLocaleFromJava(); + return QVariant(); + } + + QReadLocker locker(&m_lock); + + switch (type) { + case DecimalPoint: + return m_locale.decimalPoint(); + case GroupSeparator: + return m_locale.groupSeparator(); + case ZeroDigit: + return m_locale.zeroDigit(); + case NegativeSign: + return m_locale.negativeSign(); + case DateFormatLong: + return m_locale.dateFormat(QLocale::LongFormat); + case DateFormatShort: + return m_locale.dateFormat(QLocale::ShortFormat); + case TimeFormatLong: + return m_locale.timeFormat(QLocale::LongFormat); + case TimeFormatShort: + return m_locale.timeFormat(QLocale::ShortFormat); + case DayNameLong: + return m_locale.dayName(in.toInt(), QLocale::LongFormat); + case DayNameShort: + return m_locale.dayName(in.toInt(), QLocale::ShortFormat); + case MonthNameLong: + return m_locale.monthName(in.toInt(), QLocale::LongFormat); + case MonthNameShort: + return m_locale.monthName(in.toInt(), QLocale::ShortFormat); + case StandaloneMonthNameLong: + return m_locale.standaloneMonthName(in.toInt(), QLocale::LongFormat); + case StandaloneMonthNameShort: + return m_locale.standaloneMonthName(in.toInt(), QLocale::ShortFormat); + case DateToStringLong: + return m_locale.toString(in.toDate(), QLocale::LongFormat); + case DateToStringShort: + return m_locale.toString(in.toDate(), QLocale::ShortFormat); + case TimeToStringLong: + return m_locale.toString(in.toTime(), QLocale::LongFormat); + case TimeToStringShort: + return m_locale.toString(in.toTime(), QLocale::ShortFormat); + case DateTimeFormatLong: + return m_locale.dateTimeFormat(QLocale::LongFormat); + case DateTimeFormatShort: + return m_locale.dateTimeFormat(QLocale::ShortFormat); + case DateTimeToStringLong: + return m_locale.toString(in.toDateTime(), QLocale::LongFormat); + case DateTimeToStringShort: + return m_locale.toString(in.toDateTime(), QLocale::ShortFormat); + case PositiveSign: + return m_locale.positiveSign(); + case AMText: + return m_locale.amText(); + case PMText: + return m_locale.pmText(); + case FirstDayOfWeek: + return m_locale.firstDayOfWeek(); + case CurrencySymbol: + return m_locale .currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())); + case CurrencyToString: { + switch (in.type()) { + case QVariant::Int: + return m_locale .toCurrencyString(in.toInt()); + case QVariant::UInt: + return m_locale .toCurrencyString(in.toUInt()); + case QVariant::Double: + return m_locale .toCurrencyString(in.toDouble()); + case QVariant::LongLong: + return m_locale .toCurrencyString(in.toLongLong()); + case QVariant::ULongLong: + return m_locale .toCurrencyString(in.toULongLong()); + default: + break; + } + return QString(); + } + case StringToStandardQuotation: + return m_locale.quoteString(in.value<QStringRef>()); + case StringToAlternateQuotation: + return m_locale.quoteString(in.value<QStringRef>(), QLocale::AlternateQuotation); + case ListToSeparatedString: + return m_locale.createSeparatedList(in.value<QStringList>()); + case LocaleChanged: + Q_ASSERT_X(false, Q_FUNC_INFO, "This can't happen."); + default: + break; + } + return QVariant(); +} + +QLocale QAndroidSystemLocale::fallbackUiLocale() const +{ + QReadLocker locker(&m_lock); + return m_locale; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsudevdrmhandler.h b/src/plugins/platforms/android/src/qandroidsystemlocale.h index 4ceecb11a8..fc2f6fad98 100644 --- a/src/plugins/platforms/kms/qkmsudevdrmhandler.h +++ b/src/plugins/platforms/android/src/qandroidsystemlocale.h @@ -39,28 +39,29 @@ ** ****************************************************************************/ -#ifndef QKMSUDEVDRMHANDLER_H -#define QKMSUDEVDRMHANDLER_H +#ifndef QANDROIDSYSTEMLOCALE_H +#define QANDROIDSYSTEMLOCALE_H -#include <QObject> - -#include <qkmsudevhandler.h> +#include "private/qlocale_p.h" +#include <QtCore/qreadwritelock.h> QT_BEGIN_NAMESPACE -class QKmsIntegration; - -class QKmsUdevDRMHandler : public QKmsUdevHandler +class QAndroidSystemLocale : public QSystemLocale { public: - QKmsUdevDRMHandler(QKmsIntegration *integration); + QAndroidSystemLocale(); - QObject *create(struct udev_device *device); + virtual QVariant query(QueryType type, QVariant in) const; + virtual QLocale fallbackUiLocale() const; private: - QKmsIntegration *m_integration; + void getLocaleFromJava() const; + + mutable QLocale m_locale; + mutable QReadWriteLock m_lock; }; QT_END_NAMESPACE -#endif // QKMSUDEVDRMHANDLER_H +#endif // QANDROIDSYSTEMLOCALE_H diff --git a/src/plugins/platforms/android/src/src.pri b/src/plugins/platforms/android/src/src.pri index 76539b50ab..0fd9ace1fc 100644 --- a/src/plugins/platforms/android/src/src.pri +++ b/src/plugins/platforms/android/src/src.pri @@ -23,7 +23,8 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformtheme.cpp \ $$PWD/qandroidplatformmenubar.cpp \ $$PWD/qandroidplatformmenu.cpp \ - $$PWD/qandroidplatformmenuitem.cpp + $$PWD/qandroidplatformmenuitem.cpp \ + $$PWD/qandroidsystemlocale.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ @@ -39,7 +40,8 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/qandroidplatformtheme.h \ $$PWD/qandroidplatformmenubar.h \ $$PWD/qandroidplatformmenu.h \ - $$PWD/qandroidplatformmenuitem.h + $$PWD/qandroidplatformmenuitem.h \ + $$PWD/qandroidsystemlocale.h #Non-standard install directory, QTBUG-29859 diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm index 6adcb27817..b730514b12 100644 --- a/src/plugins/platforms/cocoa/main.mm +++ b/src/plugins/platforms/cocoa/main.mm @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QCocoaIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "cocoa.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "cocoa.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h index 2376b35501..ffb12ea846 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.h +++ b/src/plugins/platforms/cocoa/qcocoaapplication.h @@ -89,8 +89,10 @@ Cocoa Application Categories */ #include "qglobal.h" +#include "private/qcore_mac_p.h" #import <AppKit/AppKit.h> + @class QT_MANGLE_NAMESPACE(QCocoaMenuLoader); @interface NSApplication (QT_MANGLE_NAMESPACE(QApplicationIntegration)) @@ -106,6 +108,8 @@ } @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSApplication); + QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent(); diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm index d962ef8f75..c293f4cd52 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm @@ -87,12 +87,12 @@ QT_USE_NAMESPACE - (void)QT_MANGLE_NAMESPACE(qt_setDockMenu):(NSMenu *)newMenu { - [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] setDockMenu:newMenu]; + [[QCocoaApplicationDelegate sharedDelegate] setDockMenu:newMenu]; } - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader) { - return [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] menuLoader]; + return [[QCocoaApplicationDelegate sharedDelegate] menuLoader]; } - (int)QT_MANGLE_NAMESPACE(qt_validModesForFontPanel):(NSFontPanel *)fontPanel @@ -155,7 +155,7 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE @end -@implementation QT_MANGLE_NAMESPACE(QNSApplication) +@implementation QNSApplication - (void)qt_sendEvent_original:(NSEvent *)event { @@ -189,7 +189,7 @@ QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent() { - if ([NSApp isMemberOfClass:[QT_MANGLE_NAMESPACE(QNSApplication) class]]) { + if ([NSApp isMemberOfClass:[QNSApplication class]]) { // No need to change implementation since Qt // already controls a subclass of NSApplication return; @@ -202,7 +202,7 @@ void qt_redirectNSApplicationSendEvent() qt_cocoa_change_implementation( [NSApplication class], @selector(sendEvent:), - [QT_MANGLE_NAMESPACE(QNSApplication) class], + [QNSApplication class], @selector(qt_sendEvent_replacement:), @selector(qt_sendEvent_original:)); } diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h index e44b2d1b6d..7f6c4224df 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h @@ -90,6 +90,7 @@ #import <Cocoa/Cocoa.h> #include <qglobal.h> +#include <private/qcore_mac_p.h> @class QT_MANGLE_NAMESPACE(QCocoaMenuLoader); @@ -108,3 +109,5 @@ - (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; - (void) removeAppleEventHandlers; @end + +QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate); diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 3ec6ad7a20..423d552627 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -88,14 +88,14 @@ QT_USE_NAMESPACE -static QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *sharedCocoaApplicationDelegate = nil; +static QCocoaApplicationDelegate *sharedCocoaApplicationDelegate = nil; static void cleanupCocoaApplicationDelegate() { [sharedCocoaApplicationDelegate release]; } -@implementation QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) +@implementation QCocoaApplicationDelegate - (id)init { @@ -144,7 +144,7 @@ static void cleanupCocoaApplicationDelegate() return nil; } -+ (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate ++ (QCocoaApplicationDelegate *)sharedDelegate { @synchronized(self) { if (sharedCocoaApplicationDelegate == nil) @@ -166,14 +166,14 @@ static void cleanupCocoaApplicationDelegate() return [[dockMenu retain] autorelease]; } -- (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader +- (void)setMenuLoader:(QCocoaMenuLoader *)menuLoader { [menuLoader retain]; [qtMenuLoader release]; qtMenuLoader = menuLoader; } -- (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader +- (QCocoaMenuLoader *)menuLoader { return [[qtMenuLoader retain] autorelease]; } @@ -183,7 +183,7 @@ static void cleanupCocoaApplicationDelegate() [[NSApp mainMenu] cancelTracking]; bool handle_quit = true; - NSMenuItem *quitMenuItem = [[[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] menuLoader] quitMenuItem]; + NSMenuItem *quitMenuItem = [[[QCocoaApplicationDelegate sharedDelegate] menuLoader] quitMenuItem]; if (!QGuiApplicationPrivate::instance()->modalWindowList.isEmpty() && [quitMenuItem isEnabled]) { int visible = 0; diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index 3379a26650..d90d77ec1d 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -87,7 +87,9 @@ static NSButton *macCreateButton(const char *text, NSView *superview) - (void)finishOffWithCode:(NSInteger)code; @end -@implementation QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); + +@implementation QNSColorPanelDelegate - (id)init { @@ -308,12 +310,13 @@ static NSButton *macCreateButton(const char *text, NSView *superview) // close down during the cleanup. qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); [NSApp runModalForWindow:mColorPanel]; + mDialogIsExecuting = false; return (mResultCode == NSOKButton); } -- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode +- (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mResultCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected); + return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (BOOL)windowShouldClose:(id)window diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h index 701e8e2dbf..8a8b1d946c 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h @@ -62,10 +62,10 @@ public: bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); void hide(); - void setDirectory(const QString &directory); - QString directory() const; - void selectFile(const QString &filename); - QStringList selectedFiles() const; + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; void setFilter(); void selectNameFilter(const QString &filter); QString selectedNameFilter() const; diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 76cd235514..b3bc4a8ebf 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -139,7 +139,9 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions; @end -@implementation QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate); + +@implementation QNSOpenSavePanelDelegate - (id)initWithAcceptMode: (const QString &)selectFile @@ -148,7 +150,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions; { self = [super init]; mOptions = options; - if (mOptions->acceptMode() == QT_PREPEND_NAMESPACE(QFileDialogOptions::AcceptOpen)){ + if (mOptions->acceptMode() == QFileDialogOptions::AcceptOpen){ mOpenPanel = [NSOpenPanel openPanel]; mSavePanel = mOpenPanel; } else { @@ -234,7 +236,7 @@ static QString strippedText(QString s) - (void)closePanel { - *mCurrentSelection = QT_PREPEND_NAMESPACE(QCFString::toQString)([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); + *mCurrentSelection = QCFString::toQString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); if ([mSavePanel respondsToSelector:@selector(close)]) [mSavePanel close]; if ([mSavePanel isSheet]) @@ -245,7 +247,7 @@ static QString strippedText(QString s) { if (mOpenPanel){ QFileInfo info(*mCurrentSelection); - NSString *filepath = QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath()); + NSString *filepath = QCFString::toNSString(info.filePath()); bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) || [self panel:nil shouldShowFilename:filepath]; @@ -264,12 +266,12 @@ static QString strippedText(QString s) - (BOOL)runApplicationModalPanel { QFileInfo info(*mCurrentSelection); - NSString *filepath = QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath()); + NSString *filepath = QCFString::toNSString(info.filePath()); bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) || [self panel:nil shouldShowFilename:filepath]; [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; - [mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : @""]; + [mSavePanel setNameFieldStringValue:selectable ? QCFString::toNSString(info.fileName()) : @""]; // Call processEvents in case the event dispatcher has been interrupted, and needs to do // cleanup of modal sessions. Do this before showing the native dialog, otherwise it will @@ -281,22 +283,22 @@ static QString strippedText(QString s) return (mReturnCode == NSOKButton); } -- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode +- (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected); + return (mReturnCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (void)showWindowModalSheet:(QWindow *)parent { QFileInfo info(*mCurrentSelection); - NSString *filepath = QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath()); + NSString *filepath = QCFString::toNSString(info.filePath()); bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) || [self panel:nil shouldShowFilename:filepath]; [self updateProperties]; [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; - [mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : @""]; + [mSavePanel setNameFieldStringValue:selectable ? QCFString::toNSString(info.fileName()) : @""]; NSWindow *nsparent = static_cast<NSWindow *>(qGuiApp->platformNativeInterface()->nativeResourceForWindow("nswindow", parent)); [mSavePanel beginSheetModalForWindow:nsparent completionHandler:^(NSInteger result){ @@ -322,8 +324,8 @@ static QString strippedText(QString s) } } - QString qtFileName = QT_PREPEND_NAMESPACE(QCFString::toQString)(filename); - QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C))); + QString qtFileName = QCFString::toQString(filename); + QFileInfo info(qtFileName.normalized(QString::NormalizationForm_C)); QString path = info.absolutePath(); if (mCachedEntries->directory() != path) { mCachedEntries->updateDirCache(path); @@ -363,7 +365,7 @@ static QString strippedText(QString s) if (filters.size() > 0){ for (int i=0; i<filters.size(); ++i) { QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i); - [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(QCFString::toNSString)(filter)]; + [mPopUpButton addItemWithTitle:QCFString::toNSString(filter)]; } [mPopUpButton selectItemAtIndex:0]; [mSavePanel setAccessoryView:mAccessoryView]; @@ -391,18 +393,20 @@ static QString strippedText(QString s) return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]); } -- (QStringList)selectedFiles +- (QList<QUrl>)selectedFiles { if (mOpenPanel) { - QStringList result; + QList<QUrl> result; NSArray* array = [mOpenPanel URLs]; - for (NSUInteger i=0; i<[array count]; ++i) - result << QCFString::toQString([[array objectAtIndex:i] path]).normalized(QString::NormalizationForm_C); + for (NSUInteger i=0; i<[array count]; ++i) { + QString path = QCFString::toQString([[array objectAtIndex:i] path]).normalized(QString::NormalizationForm_C); + result << QUrl::fromLocalFile(path); + } return result; } else { - QStringList result; - QString filename = QT_PREPEND_NAMESPACE(QCFString::toQString)([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); - result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_")); + QList<QUrl> result; + QString filename = QCFString::toQString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); + result << QUrl::fromLocalFile(filename.remove(QLatin1String("___qt_very_unlikely_prefix_"))); return result; } } @@ -412,18 +416,18 @@ static QString strippedText(QString s) // Call this functions if mFileMode, mFileOptions, // mNameFilterDropDownList or mQDirFilter changes. // The savepanel does not contain the neccessary functions for this. - const QT_PREPEND_NAMESPACE(QFileDialogOptions::FileMode) fileMode = mOptions->fileMode(); - bool chooseFilesOnly = fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFile) - || fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles); - bool chooseDirsOnly = fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::Directory) - || fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::DirectoryOnly) - || mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ShowDirsOnly)); + const QFileDialogOptions::FileMode fileMode = mOptions->fileMode(); + bool chooseFilesOnly = fileMode == QFileDialogOptions::ExistingFile + || fileMode == QFileDialogOptions::ExistingFiles; + bool chooseDirsOnly = fileMode == QFileDialogOptions::Directory + || fileMode == QFileDialogOptions::DirectoryOnly + || mOptions->testOption(QFileDialogOptions::ShowDirsOnly); [mOpenPanel setCanChooseFiles:!chooseDirsOnly]; [mOpenPanel setCanChooseDirectories:!chooseFilesOnly]; - [mSavePanel setCanCreateDirectories:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ReadOnly)))]; - [mOpenPanel setAllowsMultipleSelection:(fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles))]; - [mOpenPanel setResolvesAliases:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::DontResolveSymlinks)))]; + [mSavePanel setCanCreateDirectories:!(mOptions->testOption(QFileDialogOptions::ReadOnly))]; + [mOpenPanel setAllowsMultipleSelection:(fileMode == QFileDialogOptions::ExistingFiles)]; + [mOpenPanel setResolvesAliases:!(mOptions->testOption(QFileDialogOptions::DontResolveSymlinks))]; [mOpenPanel setTitle:QCFString::toNSString(mOptions->windowTitle())]; [mSavePanel setTitle:QCFString::toNSString(mOptions->windowTitle())]; [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead? @@ -432,7 +436,7 @@ static QString strippedText(QString s) const QString defaultSuffix = mOptions->defaultSuffix(); if (!ext.isEmpty() && !defaultSuffix.isEmpty()) ext.prepend(defaultSuffix); - [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))]; + [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)]; if ([mSavePanel respondsToSelector:@selector(isVisible)] && [mSavePanel isVisible]) { if ([mSavePanel respondsToSelector:@selector(validateVisibleColumns)]) @@ -444,7 +448,7 @@ static QString strippedText(QString s) { Q_UNUSED(sender); if (mHelper) { - QString selection = QT_PREPEND_NAMESPACE(QCFString::toQString([[mSavePanel URL] path])); + QString selection = QCFString::toQString([[mSavePanel URL] path]); if (selection != mCurrentSelection) { *mCurrentSelection = selection; mHelper->QNSOpenSavePanelDelegate_selectionChanged(selection); @@ -462,7 +466,7 @@ static QString strippedText(QString s) [mCurrentDir release]; mCurrentDir = [path retain]; - mHelper->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(QCFString::toQString(mCurrentDir))); + mHelper->QNSOpenSavePanelDelegate_directoryEntered(QCFString::toQString(mCurrentDir)); } /* @@ -489,7 +493,7 @@ static QString strippedText(QString s) - (QString)removeExtensions:(const QString &)filter { - QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(QPlatformFileDialogHelper::filterRegExp))); + QRegExp regExp(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp)); if (regExp.indexIn(filter) != -1) return regExp.cap(1).trimmed(); return filter; @@ -525,7 +529,7 @@ static QString strippedText(QString s) (filterToUse == -1 && currentFilter.startsWith(selectedFilter))) filterToUse = i; QString filter = hideDetails ? [self removeExtensions:currentFilter] : currentFilter; - [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(QCFString::toNSString)(filter)]; + [mPopUpButton addItemWithTitle:QCFString::toNSString(filter)]; } if (filterToUse != -1) [mPopUpButton selectItemAtIndex:filterToUse]; @@ -563,13 +567,13 @@ QCocoaFileDialogHelper::~QCocoaFileDialogHelper() if (!mDelegate) return; QCocoaAutoReleasePool pool; - [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate) release]; + [reinterpret_cast<QNSOpenSavePanelDelegate *>(mDelegate) release]; mDelegate = 0; } void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath) { - emit currentChanged(newPath); + emit currentChanged(QUrl::fromLocalFile(newPath)); } void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted) @@ -584,7 +588,7 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted) void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir) { // ### fixme: priv->setLastVisitedDirectory(newDir); - emit directoryEntered(newDir); + emit directoryEntered(QUrl::fromLocalFile(newDir)); } void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuIndex) @@ -596,43 +600,45 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuInd extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp -void QCocoaFileDialogHelper::setDirectory(const QString &directory) +void QCocoaFileDialogHelper::setDirectory(const QUrl &directory) { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (delegate) - [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory)]]; + [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory.toLocalFile())]]; } -QString QCocoaFileDialogHelper::directory() const +QUrl QCocoaFileDialogHelper::directory() const { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); - if (delegate) - return QCFString::toQString([[delegate->mSavePanel directoryURL] path]).normalized(QString::NormalizationForm_C); - return QString(); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); + if (delegate) { + QString path = QCFString::toQString([[delegate->mSavePanel directoryURL] path]).normalized(QString::NormalizationForm_C); + return QUrl::fromLocalFile(path); + } + return QUrl(); } -void QCocoaFileDialogHelper::selectFile(const QString &filename) +void QCocoaFileDialogHelper::selectFile(const QUrl &filename) { - QString filePath = filename; + QString filePath = filename.toLocalFile(); if (QDir::isRelativePath(filePath)) - filePath = QFileInfo(directory(), filePath).filePath(); + filePath = QFileInfo(directory().toLocalFile(), filePath).filePath(); // There seems to no way to select a file once the dialog is running. // So do the next best thing, set the file's directory: setDirectory(QFileInfo(filePath).absolutePath()); } -QStringList QCocoaFileDialogHelper::selectedFiles() const +QList<QUrl> QCocoaFileDialogHelper::selectedFiles() const { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (delegate) return [delegate selectedFiles]; - return QStringList(); + return QList<QUrl>(); } void QCocoaFileDialogHelper::setFilter() { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return; const SharedPointerFileDialogOptions &opts = options(); @@ -651,7 +657,7 @@ void QCocoaFileDialogHelper::selectNameFilter(const QString &filter) return; const int index = options()->nameFilters().indexOf(filter); if (index != -1) { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return; [delegate->mPopUpButton selectItemAtIndex:index]; @@ -661,7 +667,7 @@ void QCocoaFileDialogHelper::selectNameFilter(const QString &filter) QString QCocoaFileDialogHelper::selectedNameFilter() const { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return QString(); int index = [delegate->mPopUpButton indexOfSelectedItem]; @@ -695,11 +701,11 @@ void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate() return; QCocoaAutoReleasePool pool; const SharedPointerFileDialogOptions &opts = options(); - const QStringList selectedFiles = opts->initiallySelectedFiles(); - const QString directory = opts->initialDirectory(); + const QList<QUrl> selectedFiles = opts->initiallySelectedFiles(); + const QUrl directory = opts->initialDirectory(); const bool selectDir = selectedFiles.isEmpty(); - QString selection(selectDir ? directory : selectedFiles.front()); - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) alloc] + QString selection(selectDir ? directory.toLocalFile() : selectedFiles.front().toLocalFile()); + QNSOpenSavePanelDelegate *delegate = [[QNSOpenSavePanelDelegate alloc] initWithAcceptMode: selection options:opts @@ -711,7 +717,7 @@ void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate() bool QCocoaFileDialogHelper::showCocoaFilePanel(Qt::WindowModality windowModality, QWindow *parent) { createNSOpenSavePanelDelegate(); - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return false; if (windowModality == Qt::NonModal) @@ -729,7 +735,7 @@ bool QCocoaFileDialogHelper::hideCocoaFilePanel() // open regarding whether or not to go native: return false; } else { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); [delegate closePanel]; // Even when we hide it, we are still using a // native dialog, so return true: @@ -744,7 +750,7 @@ void QCocoaFileDialogHelper::exec() // yet been reactivated (regardless if [NSApp run] is still on the stack)), // showing a native modal dialog will fail. QCocoaAutoReleasePool pool; - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if ([delegate runApplicationModalPanel]) emit accept(); else diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h index c1fef68f42..83aebba6d3 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h @@ -47,9 +47,6 @@ QT_BEGIN_NAMESPACE -class QFontDialog; -class QFontDialogPrivate; - class QCocoaFontDialogHelper : public QPlatformFontDialogHelper { public: @@ -63,14 +60,6 @@ public: void setCurrentFont(const QFont &); QFont currentFont() const; - -protected: - void createNSFontPanelDelegate(); - bool showCocoaFontPanel(Qt::WindowModality windowModality, QWindow *parent); - bool hideCocoaFontPanel(); - -private: - void *mDelegate; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm index a70ba3749f..91fb52eb6d 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm @@ -128,14 +128,18 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) - (void)finishOffWithCode:(NSInteger)code; @end -@implementation QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); -- (id)initWithDialogHelper: - (QCocoaFontDialogHelper *)helper +@implementation QNSFontPanelDelegate + +- (id)init { self = [super init]; mFontPanel = [NSFontPanel sharedFontPanel]; - mHelper = helper; + mHelper = 0; + mStolenContentView = 0; + mOkButton = 0; + mCancelButton = 0; mResultCode = NSCancelButton; mDialogIsExecuting = false; mResultSet = false; @@ -145,13 +149,32 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [mFontPanel setRestorable:NO]; #endif + [mFontPanel setDelegate:self]; + [[NSFontManager sharedFontManager] setDelegate:self]; + + [mFontPanel retain]; + return self; +} + +- (void)dealloc +{ + [self restoreOriginalContentView]; + [mFontPanel setDelegate:nil]; + [[NSFontManager sharedFontManager] setDelegate:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; +} + +- (void)setDialogHelper:(QCocoaFontDialogHelper *)helper +{ + mHelper = helper; + [mFontPanel setTitle:QCFString::toNSString(helper->options()->windowTitle())]; if (mHelper->options()->testOption(QFontDialogOptions::NoButtons)) { - mStolenContentView = 0; - mOkButton = 0; - mCancelButton = 0; - } else { + [self restoreOriginalContentView]; + } else if (!mStolenContentView) { // steal the font panel's contents view mStolenContentView = [mFontPanel contentView]; [mStolenContentView retain]; @@ -176,14 +199,22 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [mCancelButton setAction:@selector(onCancelClicked)]; [mCancelButton setTarget:self]; } +} - [mFontPanel retain]; - return self; +- (void)closePanel +{ + [mFontPanel close]; } -- (void)dealloc +- (void)windowDidResize:(NSNotification *)notification { - if (mOkButton) { + Q_UNUSED(notification); + [self relayout]; +} + +- (void)restoreOriginalContentView +{ + if (mStolenContentView) { NSView *ourContentView = [mFontPanel contentView]; // return stolen stuff to its rightful owner @@ -192,28 +223,17 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [mOkButton release]; [mCancelButton release]; [ourContentView release]; + mOkButton = 0; + mCancelButton = 0; + mStolenContentView = 0; } - - [mFontPanel setDelegate:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [super dealloc]; -} - -- (void)closePanel -{ - [mFontPanel close]; -} - -- (void)windowDidResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (mOkButton) - [self relayout]; } - (void)relayout { + if (!mOkButton) + return; + [self relayoutToContentSize:[[mStolenContentView superview] frame].size]; } @@ -289,30 +309,32 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) NSFont *panelFont = [fontManager convertFont:selectedFont]; mQtFont = qfontForCocoaFont(panelFont, mQtFont); - emit mHelper->currentFontChanged(mQtFont); + if (mHelper) + emit mHelper->currentFontChanged(mQtFont); } - (void)showModelessPanel { mDialogIsExecuting = false; + mResultSet = false; [mFontPanel makeKeyAndOrderFront:mFontPanel]; } - (BOOL)runApplicationModalPanel { mDialogIsExecuting = true; - [mFontPanel setDelegate:self]; // Call processEvents in case the event dispatcher has been interrupted, and needs to do // cleanup of modal sessions. Do this before showing the native dialog, otherwise it will // close down during the cleanup. qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); [NSApp runModalForWindow:mFontPanel]; + mDialogIsExecuting = false; return (mResultCode == NSOKButton); } -- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode +- (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mResultCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected); + return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (BOOL)windowShouldClose:(id)window @@ -324,7 +346,8 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [self finishOffWithCode:NSCancelButton]; } else { mResultSet = true; - emit mHelper->reject(); + if (mHelper) + emit mHelper->reject(); } return true; } @@ -359,27 +382,101 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) QT_BEGIN_NAMESPACE -QCocoaFontDialogHelper::QCocoaFontDialogHelper() : - mDelegate(0) +class QCocoaFontPanel +{ +public: + QCocoaFontPanel() + { + mDelegate = [[QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) alloc] init]; + } + + ~QCocoaFontPanel() + { + [mDelegate release]; + } + + void init(QCocoaFontDialogHelper *helper) + { + [mDelegate setDialogHelper:helper]; + } + + void cleanup(QCocoaFontDialogHelper *helper) + { + if (mDelegate->mHelper == helper) + mDelegate->mHelper = 0; + } + + bool exec() + { + // Note: If NSApp is not running (which is the case if e.g a top-most + // QEventLoop has been interrupted, and the second-most event loop has not + // yet been reactivated (regardless if [NSApp run] is still on the stack)), + // showing a native modal dialog will fail. + return [mDelegate runApplicationModalPanel]; + } + + bool show(Qt::WindowModality windowModality, QWindow *parent) + { + Q_UNUSED(parent); + if (windowModality != Qt::WindowModal) + [mDelegate showModelessPanel]; + // no need to show a Qt::WindowModal dialog here, because it's necessary to call exec() in that case + return true; + } + + void hide() + { + [mDelegate closePanel]; + } + + QFont currentFont() const + { + return mDelegate->mQtFont; + } + + void setCurrentFont(const QFont &font) + { + NSFontManager *mgr = [NSFontManager sharedFontManager]; + const NSFont *nsFont = 0; + + int weight = 5; + NSFontTraitMask mask = 0; + if (font.style() == QFont::StyleItalic) { + mask |= NSItalicFontMask; + } + if (font.weight() == QFont::Bold) { + weight = 9; + mask |= NSBoldFontMask; + } + + QFontInfo fontInfo(font); + nsFont = [mgr fontWithFamily:QCFString::toNSString(fontInfo.family()) + traits:mask + weight:weight + size:fontInfo.pointSize()]; + + [mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO]; + mDelegate->mQtFont = font; + } + +private: + QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *mDelegate; +}; + +Q_GLOBAL_STATIC(QCocoaFontPanel, sharedFontPanel) + +QCocoaFontDialogHelper::QCocoaFontDialogHelper() { } QCocoaFontDialogHelper::~QCocoaFontDialogHelper() { - if (!mDelegate) - return; - [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate) release]; - mDelegate = 0; + sharedFontPanel()->cleanup(this); } void QCocoaFontDialogHelper::exec() { - // Note: If NSApp is not running (which is the case if e.g a top-most - // QEventLoop has been interrupted, and the second-most event loop has not - // yet been reactivated (regardless if [NSApp run] is still on the stack)), - // showing a native modal dialog will fail. - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate); - if ([delegate runApplicationModalPanel]) + if (sharedFontPanel()->exec()) emit accept(); else emit reject(); @@ -387,86 +484,26 @@ void QCocoaFontDialogHelper::exec() bool QCocoaFontDialogHelper::show(Qt::WindowFlags, Qt::WindowModality windowModality, QWindow *parent) { - if (windowModality == Qt::WindowModal) { - // Cocoa's shared font panel cannot be shown as a sheet - return false; - } - return showCocoaFontPanel(windowModality, parent); + if (windowModality == Qt::WindowModal) + windowModality = Qt::ApplicationModal; + sharedFontPanel()->init(this); + return sharedFontPanel()->show(windowModality, parent); } void QCocoaFontDialogHelper::hide() { - if (!mDelegate) - return; - [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mFontPanel close]; + sharedFontPanel()->hide(); } void QCocoaFontDialogHelper::setCurrentFont(const QFont &font) { - NSFontManager *mgr = [NSFontManager sharedFontManager]; - const NSFont *nsFont = 0; - - int weight = 5; - NSFontTraitMask mask = 0; - if (font.style() == QFont::StyleItalic) { - mask |= NSItalicFontMask; - } - if (font.weight() == QFont::Bold) { - weight = 9; - mask |= NSBoldFontMask; - } - - QFontInfo fontInfo(font); - nsFont = [mgr fontWithFamily:QCFString::toNSString(fontInfo.family()) - traits:mask - weight:weight - size:fontInfo.pointSize()]; - - if (!mDelegate) - createNSFontPanelDelegate(); - - [mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO]; - static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mQtFont = font; + sharedFontPanel()->init(this); + sharedFontPanel()->setCurrentFont(font); } QFont QCocoaFontDialogHelper::currentFont() const { - if (!mDelegate) - return QFont(); - return reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mQtFont; -} - -void QCocoaFontDialogHelper::createNSFontPanelDelegate() -{ - if (mDelegate) - return; - - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) alloc] - initWithDialogHelper:this]; - - mDelegate = delegate; -} - -bool QCocoaFontDialogHelper::showCocoaFontPanel(Qt::WindowModality windowModality, QWindow *parent) -{ - Q_UNUSED(parent); - createNSFontPanelDelegate(); - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate); - if (windowModality == Qt::NonModal) - [delegate showModelessPanel]; - // no need to show a Qt::ApplicationModal dialog here, since it will be done in _q_platformRunNativeAppModalPanel() - return true; -} - -bool QCocoaFontDialogHelper::hideCocoaFontPanel() -{ - if (!mDelegate){ - return false; - } else { - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate); - [delegate closePanel]; - return true; - } + return sharedFontPanel()->currentFont(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 3ade0a2a45..3be294de7e 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -508,7 +508,6 @@ CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) CGColorSpaceRef colorSpace; CGDirectDisplayID displayID; - CMProfileRef displayProfile = 0; if (widget == 0) { displayID = CGMainDisplayID(); } else { @@ -526,18 +525,11 @@ CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) if ((colorSpace = m_displayColorSpaceHash.value(displayID))) return colorSpace; - CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile); - if (err == noErr) { - colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile); - } else if (widget) { - return qt_mac_displayColorSpace(0); // fall back on main display - } - + colorSpace = CGDisplayCopyColorSpace(displayID); if (colorSpace == 0) colorSpace = CGColorSpaceCreateDeviceRGB(); m_displayColorSpaceHash.insert(displayID, colorSpace); - CMCloseProfile(displayProfile); if (!m_postRoutineRegistered) { m_postRoutineRegistered = true; void qt_mac_cleanUpMacColorSpaces(); @@ -810,20 +802,7 @@ CGImageRef qt_mac_toCGImage(const QImage &qImage, bool isMask, uchar **dataCopy) NULL, false); } else { - // Try get a device color space. Using the device color space means - // that the CGImage can be drawn to screen without per-pixel color - // space conversion, at the cost of less color accuracy. - CGColorSpaceRef cgColourSpaceRef = 0; - CMProfileRef sysProfile; - if (CMGetSystemProfile(&sysProfile) == noErr) - { - cgColourSpaceRef = CGColorSpaceCreateWithPlatformColorSpace(sysProfile); - CMCloseProfile(sysProfile); - } - - // Fall back to Generic RGB if a profile was not found. - if (!cgColourSpaceRef) - cgColourSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGColorSpaceRef cgColourSpaceRef = qt_mac_displayColorSpace(0); // Create a CGBitmapInfo contiaining the image format. // Support the 8-bit per component (A)RGB formats. @@ -857,7 +836,6 @@ CGImageRef qt_mac_toCGImage(const QImage &qImage, bool isMask, uchar **dataCopy) NULL, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(cgColourSpaceRef); } CGDataProviderRelease(cgDataProviderRef); return cgImage; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index fad743439e..6d1882f622 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -232,7 +232,7 @@ QCocoaIntegration::QCocoaIntegration() qApp->setAttribute(Qt::AA_DontUseNativeMenuBar, false); - NSApplication *cocoaApplication = [QT_MANGLE_NAMESPACE(QNSApplication) sharedApplication]; + NSApplication *cocoaApplication = [QNSApplication sharedApplication]; qt_redirectNSApplicationSendEvent(); if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { @@ -256,12 +256,12 @@ QCocoaIntegration::QCocoaIntegration() if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) { // Set app delegate, link to the current delegate (if any) - QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; + QCocoaApplicationDelegate *newDelegate = [QCocoaApplicationDelegate sharedDelegate]; [newDelegate setReflectionDelegate:[cocoaApplication delegate]]; [cocoaApplication setDelegate:newDelegate]; // Load the application menu. This menu contains Preferences, Hide, Quit. - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader = [[QT_MANGLE_NAMESPACE(QCocoaMenuLoader) alloc] init]; + QCocoaMenuLoader *qtMenuLoader = [[QCocoaMenuLoader alloc] init]; qt_mac_loadMenuNib(qtMenuLoader); [cocoaApplication setMenu:[qtMenuLoader menu]]; [newDelegate setMenuLoader:qtMenuLoader]; @@ -279,7 +279,7 @@ QCocoaIntegration::~QCocoaIntegration() QCocoaAutoReleasePool pool; if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) { // remove the apple event handlers installed by QCocoaApplicationDelegate - QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *delegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; + QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate]; [delegate removeAppleEventHandlers]; // reset the application delegate [[NSApplication sharedApplication] setDelegate: 0]; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index f9e033d21b..3ac48df09e 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -74,7 +74,7 @@ NSString *qt_mac_removePrivateUnicode(NSString* string) return string; } -static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +static inline QCocoaMenuLoader *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; } @@ -87,7 +87,9 @@ static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() @end -@implementation QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); + +@implementation QCocoaMenuDelegate - (id) initWithMenu:(QCocoaMenu*) m { @@ -220,11 +222,11 @@ QCocoaMenu::QCocoaMenu() : m_tag(0), m_menuBar(0) { - m_delegate = [[QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) alloc] initWithMenu:this]; + m_delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this]; m_nativeItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; m_nativeMenu = [[NSMenu alloc] initWithTitle:@"Untitled"]; [m_nativeMenu setAutoenablesItems:YES]; - m_nativeMenu.delegate = (QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) *) m_delegate; + m_nativeMenu.delegate = (QCocoaMenuDelegate *) m_delegate; [m_nativeItem setSubmenu:m_nativeMenu]; } diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index ddfa9fff96..0fea55ac68 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -52,7 +52,7 @@ static QList<QCocoaMenuBar*> static_menubars; -static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +static inline QCocoaMenuLoader *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; } @@ -240,7 +240,7 @@ void QCocoaMenuBar::updateMenuBarImmediately() } } - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); [loader ensureAppMenuInMenu:mb->nsMenu()]; NSMutableSet *mergedItems = [[NSMutableSet setWithCapacity:0] retain]; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 6d8174c667..013f9931ff 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -52,7 +52,7 @@ #include <QtCore/QDebug> -static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +static inline QCocoaMenuLoader *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; } @@ -199,7 +199,7 @@ NSMenuItem *QCocoaMenuItem::sync() if ((m_role != NoRole && !m_textSynced) || m_merged) { NSMenuItem *mergeItem = nil; - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); switch (m_role) { case ApplicationSpecificRole: mergeItem = [loader appSpecificMenuItem:reinterpret_cast<NSInteger>(this)]; @@ -326,7 +326,7 @@ QT_END_NAMESPACE QString QCocoaMenuItem::mergeText() { - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); if (m_native == [loader aboutMenuItem]) { return qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName()); } else if (m_native== [loader aboutQtMenuItem]) { @@ -344,7 +344,7 @@ QString QCocoaMenuItem::mergeText() QKeySequence QCocoaMenuItem::mergeAccel() { - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); if (m_native == [loader preferencesMenuItem]) return QKeySequence(QKeySequence::Preferences); else if (m_native == [loader quitMenuItem]) diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h index a45ec0fa89..e07da39995 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.h +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h @@ -92,9 +92,11 @@ - (NSArray *)mergeable; @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuLoader); + QT_BEGIN_NAMESPACE -void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader); +void qt_mac_loadMenuNib(QCocoaMenuLoader *qtMenuLoader); QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index 62b722d2d2..29fc0fb674 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE and written to QDir::temp() before loading. (Earlier Qt versions used to require having the nib file in the Qt GUI framework.) */ -void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader) +void qt_mac_loadMenuNib(QCocoaMenuLoader *qtMenuLoader) { // Create qt_menu.nib dir in temp. QDir temp = QDir::temp(); @@ -106,7 +106,7 @@ void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader) QT_END_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(QCocoaMenuLoader) +@implementation QCocoaMenuLoader - (void)awakeFromNib { diff --git a/src/plugins/platforms/cocoa/qcocoaservices.mm b/src/plugins/platforms/cocoa/qcocoaservices.mm index e4cec8c5f8..de4c688b71 100644 --- a/src/plugins/platforms/cocoa/qcocoaservices.mm +++ b/src/plugins/platforms/cocoa/qcocoaservices.mm @@ -55,7 +55,7 @@ bool QCocoaServices::openUrl(const QUrl &url) const QString scheme = url.scheme(); if (scheme.isEmpty()) return openDocument(url); - return [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:QT_PREPEND_NAMESPACE(QCFString::toNSString)(url.toString(QUrl::FullyEncoded))]]; + return [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:QCFString::toNSString(url.toString(QUrl::FullyEncoded))]]; } bool QCocoaServices::openDocument(const QUrl &url) @@ -63,7 +63,7 @@ bool QCocoaServices::openDocument(const QUrl &url) if (!url.isValid()) return false; - return [[NSWorkspace sharedWorkspace] openFile:QT_PREPEND_NAMESPACE(QCFString::toNSString)(url.toLocalFile())]; + return [[NSWorkspace sharedWorkspace] openFile:QCFString::toNSString(url.toLocalFile())]; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index af817bd4c5..194394d11a 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -264,6 +264,10 @@ QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts() fonts.insert(QPlatformTheme::SmallFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); fonts.insert(QPlatformTheme::MiniFont, qt_mac_qfontForThemeFont(kThemeMiniSystemFont)); + QFont* fixedFont = new QFont(QStringLiteral("Monaco"), fonts[QPlatformTheme::SystemFont]->pointSize()); + fixedFont->setStyleHint(QFont::TypeWriter); + fonts.insert(QPlatformTheme::FixedFont, fixedFont); + return fonts; } diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 99f533b33a..83c960d931 100755 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -135,12 +135,16 @@ QT_USE_NAMESPACE -(id)initWithQMenu:(QPlatformMenu*)qmenu; @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem); +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSImageView); +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSMenu); + QT_BEGIN_NAMESPACE class QSystemTrayIconSys { public: QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) { - item = [[QT_MANGLE_NAMESPACE(QNSStatusItem) alloc] initWithSysTray:sys]; + item = [[QNSStatusItem alloc] initWithSysTray:sys]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item]; @@ -156,7 +160,7 @@ public: #endif [item release]; } - QT_MANGLE_NAMESPACE(QNSStatusItem) *item; + QNSStatusItem *item; }; void QCocoaSystemTrayIcon::init() @@ -310,8 +314,8 @@ QT_END_NAMESPACE @implementation NSStatusItem (Qt) @end -@implementation QT_MANGLE_NAMESPACE(QNSImageView) --(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent { +@implementation QNSImageView +-(id)initWithParent:(QNSStatusItem*)myParent { self = [super init]; parent = myParent; down = NO; @@ -406,7 +410,7 @@ QT_END_NAMESPACE } @end -@implementation QT_MANGLE_NAMESPACE(QNSStatusItem) +@implementation QNSStatusItem -(id)initWithSysTray:(QCocoaSystemTrayIcon *)sys { @@ -416,7 +420,7 @@ QT_END_NAMESPACE menu = 0; menuVisible = false; systray = sys; - imageCell = [[QT_MANGLE_NAMESPACE(QNSImageView) alloc] initWithParent:self]; + imageCell = [[QNSImageView alloc] initWithParent:self]; [item setView: imageCell]; } return self; @@ -494,7 +498,7 @@ private: QSystemTrayIconQMenu(); }; -@implementation QT_MANGLE_NAMESPACE(QNSMenu) +@implementation QNSMenu -(id)initWithQMenu:(QPlatformMenu*)qm { self = [super init]; if (self) { diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index cac059763d..e4237c9b3e 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -68,7 +68,9 @@ public: const QPalette *palette(Palette type = SystemPalette) const; const QFont *font(Font type = SystemFont) const; QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + QPixmap fileIconPixmap(const QFileInfo &fileInfo, + const QSizeF &size, + QPlatformTheme::IconOptions options = 0) const; QVariant themeHint(ThemeHint hint) const; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 13a387a0a3..1484ae2ba3 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -249,8 +249,10 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const return QPlatformTheme::standardPixmap(sp, size); } -QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { + Q_UNUSED(iconOptions); QCocoaAutoReleasePool pool; NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:QCFString::toNSString(fileInfo.canonicalFilePath())]; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index b82d096bb5..8967445f59 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -61,7 +61,7 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow) @end @interface QNSPanel : NSPanel { - @public QT_PREPEND_NAMESPACE(QCocoaWindow) *m_cocoaPlatformWindow; + @public QCocoaWindow *m_cocoaPlatformWindow; } - (void)clearPlatformWindow; - (BOOL)canBecomeKeyWindow; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 1126315126..fcebb7e0dc 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -155,6 +155,9 @@ static bool isMouseEvent(NSEvent *ev) - (BOOL)canBecomeKeyWindow { + if (!m_cocoaPlatformWindow) + return NO; + // Only tool or dialog windows should become key: if (m_cocoaPlatformWindow && (m_cocoaPlatformWindow->window()->type() == Qt::Tool || m_cocoaPlatformWindow->window()->type() == Qt::Dialog)) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index aff93dd133..b8f0fc3cce 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -876,7 +876,23 @@ static QTouchDevice *touchDevice = 0; currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; } - QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers); + QWheelEvent::Phase ph = QWheelEvent::Changed; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { + // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. + if (phase == NSEventPhaseMayBegin) + ph = QWheelEvent::Started; + } else +#endif + if (phase == NSEventPhaseBegan) { + // On 10.7, MayBegin will not happen, so Began is the actual beginning. + ph = QWheelEvent::Started; + } + if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) { + ph = QWheelEvent::Ended; + } + + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph); if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) { currentWheelModifiers = Qt::NoModifier; @@ -919,14 +935,11 @@ static QTouchDevice *touchDevice = 0; NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers]; NSString *characters = [nsevent characters]; - // [from Qt 4 impl] There is no way to get the scan code from carbon. But we cannot + // There is no way to get the scan code from carbon/cocoa. But we cannot // use the value 0, since it indicates that the event originates from somewhere // else than the keyboard. quint32 nativeScanCode = 1; - - UInt32 nativeVirtualKey = 0; - EventRef eventRef = EventRef([nsevent eventRef]); - GetEventParameter(eventRef, kEventParamKeyCode, typeUInt32, 0, sizeof(nativeVirtualKey), 0, &nativeVirtualKey); + quint32 nativeVirtualKey = [nsevent keyCode]; QChar ch = QChar::ReplacementCharacter; int keyCode = Qt::Key_unknown; diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 301beb11c1..dc3757ce3c 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -362,7 +362,6 @@ CGColorSpaceRef QCoreGraphicsPaintEngine::macDisplayColorSpace(const QWidget *wi CGColorSpaceRef colorSpace; CGDirectDisplayID displayID; - CMProfileRef displayProfile = 0; if (widget == 0) { displayID = CGMainDisplayID(); } else { @@ -376,18 +375,11 @@ CGColorSpaceRef QCoreGraphicsPaintEngine::macDisplayColorSpace(const QWidget *wi if ((colorSpace = m_displayColorSpaceHash.value(displayID))) return colorSpace; - CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile); - if (err == noErr) { - colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile); - } else if (widget) { - return macDisplayColorSpace(0); // fall back on main display - } - + colorSpace = CGDisplayCopyColorSpace(displayID); if (colorSpace == 0) colorSpace = CGColorSpaceCreateDeviceRGB(); m_displayColorSpaceHash.insert(displayID, colorSpace); - CMCloseProfile(displayProfile); if (!m_postRoutineRegistered) { m_postRoutineRegistered = true; qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); diff --git a/src/plugins/platforms/directfb/main.cpp b/src/plugins/platforms/directfb/main.cpp index 3d5d60abaa..5ba1b0996b 100644 --- a/src/plugins/platforms/directfb/main.cpp +++ b/src/plugins/platforms/directfb/main.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE class QDirectFbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "directfb.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "directfb.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp index 939d8c0686..5b4c958616 100644 --- a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp +++ b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp @@ -286,6 +286,14 @@ QDirectFbKeyMap::QDirectFbKeyMap() insert(DIKS_MAIL , Qt::Key_LaunchMail); insert(DIKS_FAVORITES , Qt::Key_Favorites); + insert(DIKS_RED , Qt::Key_Red); + insert(DIKS_GREEN , Qt::Key_Green); + insert(DIKS_YELLOW , Qt::Key_Yellow); + insert(DIKS_BLUE , Qt::Key_Blue); + + insert(DIKS_CHANNEL_UP , Qt::Key_ChannelUp); + insert(DIKS_CHANNEL_DOWN , Qt::Key_ChannelDown); + insert(DIKS_BACK , Qt::Key_Back); insert(DIKS_FORWARD , Qt::Key_Forward); insert(DIKS_VOLUME_UP , Qt::Key_VolumeUp); diff --git a/src/plugins/platforms/eglfs/main.cpp b/src/plugins/platforms/eglfs/main.cpp index df77127b4a..d8e7a3792e 100644 --- a/src/plugins/platforms/eglfs/main.cpp +++ b/src/plugins/platforms/eglfs/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QEglFSIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "eglfs.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "eglfs.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index cf1503b7f9..08f68a20f4 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -74,6 +74,8 @@ QT_BEGIN_NAMESPACE +static void *eglContextForContext(QOpenGLContext *context); + QEglFSIntegration::QEglFSIntegration() : mEventDispatcher(createUnixEventDispatcher()), mFontDb(new QGenericUnixFontDatabase()) { @@ -200,6 +202,20 @@ void *QEglFSIntegration::nativeResourceForIntegration(const QByteArray &resource return 0; } +void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ + QByteArray lowerCaseResource = resource.toLower(); + + if (lowerCaseResource == "egldisplay") { + if (window) + return static_cast<QEglFSScreen *>(window->handle()->screen())->display(); + else + return static_cast<QEglFSScreen *>(mScreen)->display(); + } + + return 0; +} + void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { QByteArray lowerCaseResource = resource.toLower(); @@ -215,6 +231,26 @@ void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QO return 0; } +QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource) +{ + QByteArray lowerCaseResource = resource.toLower(); + if (lowerCaseResource == "get_egl_context") + return NativeResourceForContextFunction(eglContextForContext); + + return 0; +} + +static void *eglContextForContext(QOpenGLContext *context) +{ + Q_ASSERT(context); + + QEGLPlatformContext *handle = static_cast<QEGLPlatformContext *>(context->handle()); + if (!handle) + return 0; + + return handle->eglContext(); +} + EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format) { class Chooser : public QEglConfigChooser { diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index bf044d6919..dd85788bd8 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -72,8 +72,11 @@ public: // QPlatformNativeInterface void *nativeResourceForIntegration(const QByteArray &resource); + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); + NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; + QPlatformScreen *screen() const { return mScreen; } static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format); diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index 6cb1f88c66..1fe8bcc11b 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE QEglFSScreen::QEglFSScreen(EGLDisplay dpy) : m_dpy(dpy) + , m_surface(0) , m_cursor(0) { #ifdef QEGL_EXTRA_DEBUG @@ -95,4 +96,9 @@ QPlatformCursor *QEglFSScreen::cursor() const return m_cursor; } +void QEglFSScreen::setPrimarySurface(EGLSurface surface) +{ + m_surface = surface; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 298a67cd3a..b04c85797f 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -69,9 +69,16 @@ public: QPlatformCursor *cursor() const; EGLDisplay display() const { return m_dpy; } + EGLSurface primarySurface() const { return m_surface; } + +protected: + void setPrimarySurface(EGLSurface surface); private: + friend class QEglFSWindow; + EGLDisplay m_dpy; + EGLSurface m_surface; QEglFSCursor *m_cursor; }; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 28ce8c8a33..bf6e375ac0 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -42,6 +42,8 @@ #include "qeglfswindow.h" #include "qeglfshooks.h" #include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformintegration.h> +#include <private/qguiapplication_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> @@ -66,6 +68,11 @@ QEglFSWindow::~QEglFSWindow() destroy(); } +static inline bool supportsMultipleWindows() +{ + return QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows); +} + void QEglFSWindow::create() { if (has_window) @@ -80,6 +87,9 @@ void QEglFSWindow::create() return; } + if (!supportsMultipleWindows() && screen()->primarySurface()) + return; + EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display(); QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat()); m_config = QEglFSIntegration::chooseConfig(display, platformFormat); @@ -105,11 +115,14 @@ void QEglFSWindow::resetSurface() m_window = QEglFSHooks::hooks()->createNativeWindow(QEglFSHooks::hooks()->screenSize(), m_format); has_window = true; m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL); + if (m_surface == EGL_NO_SURFACE) { EGLint error = eglGetError(); eglTerminate(display); qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error); } + + screen()->setPrimarySurface(m_surface); } void QEglFSWindow::destroy() @@ -117,6 +130,12 @@ void QEglFSWindow::destroy() if (m_surface) { EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); eglDestroySurface(display, m_surface); + + if (!supportsMultipleWindows()) { + // ours must be the primary surface + screen()->setPrimarySurface(0); + } + m_surface = 0; } @@ -145,9 +164,21 @@ WId QEglFSWindow::winId() const return WId(m_window); } +EGLSurface QEglFSWindow::surface() const +{ + if (!supportsMultipleWindows()) + return screen()->primarySurface(); + return m_surface; +} + QSurfaceFormat QEglFSWindow::format() const { return m_format; } +QEglFSScreen *QEglFSWindow::screen() const +{ + return static_cast<QEglFSScreen *>(QPlatformWindow::screen()); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index 0997f80e74..936537807a 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -59,9 +59,11 @@ public: void setWindowState(Qt::WindowState state); WId winId() const; - EGLSurface surface() const { return m_surface; } + EGLSurface surface() const; QSurfaceFormat format() const; + QEglFSScreen *screen() const; + void create(); void destroy(); diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index 842ff17f1c..5a2129eb08 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -1,3 +1,39 @@ -TEMPLATE = subdirs +TARGET = qios -SUBDIRS += plugin.pro qtmain.pro +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QIOSIntegrationPlugin +load(qt_plugin) + +QT += core-private gui-private platformsupport-private +LIBS += -framework Foundation -framework UIKit -framework QuartzCore + +OBJECTIVE_SOURCES = \ + plugin.mm \ + qiosmain_wrapper.mm \ + qiosmain_dummy.mm \ + qiosintegration.mm \ + qioswindow.mm \ + qiosscreen.mm \ + qiosbackingstore.mm \ + qiosapplicationdelegate.mm \ + qiosapplicationstate.mm \ + qiosviewcontroller.mm \ + qioscontext.mm \ + qiosinputcontext.mm \ + qiostheme.mm \ + qiosglobal.mm + +HEADERS = \ + qiosintegration.h \ + qioswindow.h \ + qiosscreen.h \ + qiosbackingstore.h \ + qiosapplicationdelegate.h \ + qiosapplicationstate.h \ + qiosviewcontroller.h \ + qioscontext.h \ + qiosinputcontext.h \ + qiostheme.h \ + qiosglobal.h + +#HEADERS = qiossoftwareinputhandler.h diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm index a93b6037ad..efb1ad8d74 100644 --- a/src/plugins/platforms/ios/plugin.mm +++ b/src/plugins/platforms/ios/plugin.mm @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "ios.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "ios.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; @@ -66,4 +66,8 @@ QT_END_NAMESPACE #include "plugin.moc" +// Dummy function that we explicitly tell the linker to look for, +// so that the plugin's static initializer is included and run. +extern "C" void qt_registerPlatformPlugin() {} + Q_IMPORT_PLUGIN(QIOSIntegrationPlugin) diff --git a/src/plugins/platforms/ios/plugin.pro b/src/plugins/platforms/ios/plugin.pro deleted file mode 100644 index 591a0a67ed..0000000000 --- a/src/plugins/platforms/ios/plugin.pro +++ /dev/null @@ -1,36 +0,0 @@ -TARGET = qios - -PLUGIN_TYPE = platforms -load(qt_plugin) - -QT += core-private gui-private platformsupport-private -LIBS += -framework UIKit -framework QuartzCore - -OBJECTIVE_SOURCES = \ - plugin.mm \ - qiosintegration.mm \ - qioswindow.mm \ - qiosscreen.mm \ - qioseventdispatcher.mm \ - qiosbackingstore.mm \ - qiosapplicationdelegate.mm \ - qiosviewcontroller.mm \ - qioscontext.mm \ - qiosinputcontext.mm \ - qiostheme.mm \ - qiosglobal.mm - -HEADERS = \ - qiosintegration.h \ - qioswindow.h \ - qiosscreen.h \ - qioseventdispatcher.h \ - qiosbackingstore.h \ - qiosapplicationdelegate.h \ - qiosviewcontroller.h \ - qioscontext.h \ - qiosinputcontext.h \ - qiostheme.h \ - qiosglobal.h - -#HEADERS = qiossoftwareinputhandler.h diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h index 3d3ba58049..bfe31af198 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.h +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h @@ -50,7 +50,3 @@ @property (strong, nonatomic) QIOSViewController *qiosViewController; @end - -@interface QIOSMainWrapperApplicationDelegate : QIOSApplicationDelegate -@end - diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm index 10cbe529c4..52d94f38fb 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm @@ -39,10 +39,15 @@ ** ****************************************************************************/ -#import "qiosapplicationdelegate.h" +#include "qiosapplicationdelegate.h" + +#include "qiosviewcontroller.h" #include "qioswindow.h" + #include <QtCore/QtCore> +extern int qt_user_main(int argc, char *argv[]); + @implementation QIOSApplicationDelegate @synthesize window; @@ -50,40 +55,43 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - Q_UNUSED(application) - Q_UNUSED(launchOptions) + Q_UNUSED(application); + Q_UNUSED(launchOptions); - return YES; -} + self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + self.qiosViewController = [[[QIOSViewController alloc] init] autorelease]; + self.window.rootViewController = self.qiosViewController; -- (void)applicationWillResignActive:(UIApplication *)application -{ - Q_UNUSED(application) -} +#ifdef QT_DEBUG + self.window.backgroundColor = [UIColor cyanColor]; +#endif -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - Q_UNUSED(application) -} + [self.window makeKeyAndVisible]; -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - Q_UNUSED(application) - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. -} + // We schedule the main-redirection for the next eventloop pass so that we + // can return from this function and let UIApplicationMain finish its job. + [NSTimer scheduledTimerWithTimeInterval:.01f target:self + selector:@selector(runUserMain) userInfo:nil repeats:NO]; -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - Q_UNUSED(application) - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + return YES; } -- (void)applicationWillTerminate:(UIApplication *)application +- (void)runUserMain { - Q_UNUSED(application) - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + NSArray *arguments = [[NSProcessInfo processInfo] arguments]; + int argc = arguments.count; + char **argv = new char*[argc]; + for (int i = 0; i < argc; ++i) { + NSString *arg = [arguments objectAtIndex:i]; + argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]])); + strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]); + } + + qt_user_main(argc, argv); + delete[] argv; } + - (void)dealloc { [qiosViewController release]; @@ -93,4 +101,3 @@ @end - diff --git a/src/plugins/platforms/kms/qkmsudevhandler.cpp b/src/plugins/platforms/ios/qiosapplicationstate.h index e32723e78f..e726ad895e 100644 --- a/src/plugins/platforms/kms/qkmsudevhandler.cpp +++ b/src/plugins/platforms/ios/qiosapplicationstate.h @@ -39,17 +39,22 @@ ** ****************************************************************************/ -#include <qkmsudevhandler.h> +#ifndef QIOSAPPLICATIONSTATE_H +#define QIOSAPPLICATIONSTATE_H QT_BEGIN_NAMESPACE -QKmsUdevHandler::QKmsUdevHandler(QObject *parent) - : QObject(parent) -{ -} +@class QIOSApplicationStateListener; -QKmsUdevHandler::~QKmsUdevHandler() +class QIOSApplicationState { -} +public: + QIOSApplicationState(); + ~QIOSApplicationState(); +private: + QIOSApplicationStateListener *m_listener; +}; QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm new file mode 100644 index 0000000000..df64edf465 --- /dev/null +++ b/src/plugins/platforms/ios/qiosapplicationstate.mm @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <UIKit/UIKit.h> + +#include <qpa/qwindowsysteminterface.h> +#include "qiosapplicationstate.h" + +@interface QIOSApplicationStateListener : NSObject +@end + +@implementation QIOSApplicationStateListener + +- (id) init +{ + self = [super init]; + if (self) { + // Listen for application state changes. + // Note: We use notifications rather than application delegate callbacks to + // also support hybrid applications were QIOSApplicationDelegate is not in use. + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationDidBecomeActive) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationWillResignActive) + name:UIApplicationWillResignActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationDidEnterBackground) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + } + return self; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIApplicationDidBecomeActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIApplicationWillResignActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + [super dealloc]; +} + +- (void) applicationDidBecomeActive +{ + [self handleApplicationStateChanged:UIApplicationStateActive]; +} + +- (void) applicationWillResignActive +{ + // Note that UIApplication is still UIApplicationStateActive at this + // point, but since there is no separate notification for the inactive + // state, we report UIApplicationStateInactive now: + [self handleApplicationStateChanged:UIApplicationStateInactive]; +} + +- (void) applicationDidEnterBackground +{ + [self handleApplicationStateChanged:UIApplicationStateBackground]; +} + +- (void) handleApplicationStateChanged:(UIApplicationState) uiApplicationState +{ + Qt::ApplicationState state; + switch (uiApplicationState) { + case UIApplicationStateActive: + // The application is visible in front, and receiving events: + state = Qt::ApplicationActive; + break; + case UIApplicationStateInactive: + // The app is running in the foreground but is not receiving events. This + // typically happens while transitioning to/from active/background, like + // upon app launch or when receiving incoming calls: + state = Qt::ApplicationInactive; + break; + case UIApplicationStateBackground: + // Normally the app would enter this state briefly before it gets + // suspeded (you have five seconds, according to Apple). + // You can request more time and start a background task, which would + // normally map closer to Qt::ApplicationHidden. But since we have no + // API for doing that yet, we handle this state as "about to be suspended". + // Note: A screen-shot for the SpringBoard will also be taken after this + // call returns. + state = Qt::ApplicationSuspended; + break; + } + QWindowSystemInterface::handleApplicationStateChanged(state); +} + +@end + +QT_BEGIN_NAMESPACE + +QIOSApplicationState::QIOSApplicationState() + : m_listener([[QIOSApplicationStateListener alloc] init]) +{ + // Update the current state now, since we have missed all the updates + // posted from AppKit so far. But let QPA finish initialization first: + dispatch_async(dispatch_get_main_queue(), ^{ + UIApplicationState state = [UIApplication sharedApplication].applicationState; + [m_listener handleApplicationStateChanged:state]; + }); +} + +QIOSApplicationState::~QIOSApplicationState() +{ + [m_listener release]; +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index 87bcc01d04..85f560a722 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -200,7 +200,7 @@ void QIOSContext::windowDestroyed(QObject *object) QFunctionPointer QIOSContext::getProcAddress(const QByteArray& functionName) { - return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_NEXT, functionName.constData())); + return QFunctionPointer(dlsym(RTLD_DEFAULT, functionName.constData())); } #include "moc_qioscontext.cpp" diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 176ad05733..78c1b260e6 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -66,6 +66,7 @@ public: private: QIOSKeyboardListener *m_keyboardListener; UIView *m_focusView; + bool m_hasPendingHideRequest; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 1d3ab12de9..d430589037 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -99,6 +99,7 @@ QIOSInputContext::QIOSInputContext() : QPlatformInputContext() , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_focusView(0) + , m_hasPendingHideRequest(false) { } @@ -120,12 +121,20 @@ void QIOSInputContext::showInputPanel() // responder. Rather than searching for it from the top, we let the active QIOSWindow tell us which view to use. // Note that Qt will forward keyevents to whichever QObject that needs it, regardless of which UIView the input // actually came from. So in this respect, we're undermining iOS' responder chain. + m_hasPendingHideRequest = false; [m_focusView becomeFirstResponder]; } void QIOSInputContext::hideInputPanel() { - [m_focusView resignFirstResponder]; + // Delay hiding the keyboard for cases where the user is transferring focus between + // 'line edits'. In that case the 'line edit' that lost focus will close the input + // panel, just to see that the new 'line edit' will open it again: + m_hasPendingHideRequest = true; + dispatch_async(dispatch_get_main_queue(), ^{ + if (m_hasPendingHideRequest) + [m_focusView resignFirstResponder]; + }); } bool QIOSInputContext::isInputPanelVisible() const diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index c352e0f2d2..4aaf98f839 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -46,6 +46,8 @@ #include <qpa/qplatformnativeinterface.h> #include <qpa/qwindowsysteminterface.h> +#include "qiosapplicationstate.h" + QT_BEGIN_NAMESPACE class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInterface @@ -79,6 +81,7 @@ private: QPlatformInputContext *m_inputContext; QPlatformScreen *m_screen; QTouchDevice *m_touchDevice; + QIOSApplicationState m_applicationState; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 61fd1c3d60..e31804f428 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -43,12 +43,13 @@ #include "qioswindow.h" #include "qiosbackingstore.h" #include "qiosscreen.h" -#include "qioseventdispatcher.h" #include "qioscontext.h" #include "qiosinputcontext.h" #include "qiostheme.h" +#include <QtPlatformSupport/private/qioseventdispatcher_p.h> #include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> +#include <QDir> #include <QtDebug> @@ -71,6 +72,9 @@ QIOSIntegration::QIOSIntegration() exit(-1); } + // Set current directory to app bundle folder + QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String])); + screenAdded(m_screen); m_touchDevice = new QTouchDevice; @@ -86,6 +90,8 @@ bool QIOSIntegration::hasCapability(Capability cap) const return true; case MultipleWindows: return true; + case ApplicationState: + return true; default: return QPlatformIntegration::hasCapability(cap); } @@ -129,6 +135,8 @@ QVariant QIOSIntegration::styleHint(StyleHint hint) const switch (hint) { case ShowIsFullScreen: return true; + case SetFocusOnTouchRelease: + return true; default: return QPlatformIntegration::styleHint(hint); } diff --git a/src/plugins/platforms/kms/qkmsudevhandler.h b/src/plugins/platforms/ios/qiosmain_dummy.mm index e95960628a..28d7e59381 100644 --- a/src/plugins/platforms/kms/qkmsudevhandler.h +++ b/src/plugins/platforms/ios/qiosmain_dummy.mm @@ -39,26 +39,18 @@ ** ****************************************************************************/ -#ifndef QKMSUDEVHANDLER_H -#define QKMSUDEVHANDLER_H +#include <QtCore/qglobal.h> -#include <QObject> +/* + This file provides a dummy implementation of qt_user_main, so that + we don't get an undefined symbol in the hybrid use-case, where we + don't rename main() to qt_user_main(). As long as the linker is not + passed -all_load, this translation unit is only picked up and used + if qt_user_main is not defined by the user's code. +*/ -#include <libudev.h> - -QT_BEGIN_NAMESPACE - -class QKmsUdevHandler : public QObject +int qt_user_main(int, char **) { - Q_OBJECT - -public: - QKmsUdevHandler(QObject *parent = 0); - virtual ~QKmsUdevHandler(); - - virtual QObject *create(struct udev_device *) = 0; -}; - -QT_END_NAMESPACE - -#endif // QKMSUDEVHANDLER_H + qFatal("Hit dummy qt_user_main, this should never happen!"); + return 0; +} diff --git a/src/plugins/platforms/kms/qkmsudevdrmhandler.cpp b/src/plugins/platforms/ios/qiosmain_wrapper.mm index 68a4aaacdb..d9b8c7311e 100644 --- a/src/plugins/platforms/kms/qkmsudevdrmhandler.cpp +++ b/src/plugins/platforms/ios/qiosmain_wrapper.mm @@ -39,28 +39,22 @@ ** ****************************************************************************/ -#include <QtCore/QRegExp> +#include "qiosapplicationdelegate.h" -#include <qkmsintegration.h> -#include <qkmsudevdrmhandler.h> +/* + This file provides a wrapper implementation of main() for the non- + hybrid use-case. The user's main is renamed to qt_user_main by the + build rules, and we'll call out to that main at the appropriate time. -QT_BEGIN_NAMESPACE + This file purposly only exports a single symbol, _main, so that + when the linker considers the translation unit for inclusion it + will discard it when main has already been defined in the user's + application for the hybrid use-case. +*/ -QKmsUdevDRMHandler::QKmsUdevDRMHandler(QKmsIntegration *integration) - : m_integration(integration) +int main(int argc, char *argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate class])); + } } - -QObject *QKmsUdevDRMHandler::create(struct udev_device *device) -{ - if (strcmp(udev_device_get_subsystem(device), "drm")) - return 0; - - QRegExp regexp("^card\\d+$"); - if (!regexp.exactMatch(udev_device_get_sysname(device))) - return 0; - - return m_integration->createDevice(udev_device_get_devnode(device)); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 0c3ae8e834..4c8a16b0bc 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -247,6 +247,23 @@ return YES; } +- (BOOL)becomeFirstResponder +{ + // On iOS, a QWindow should only have input focus when the input panel is + // open. This is to stop cursors and focus rects from being drawn when the + // user cannot type. And since the keyboard will open when a view becomes + // the first responder, it's now a good time to inform QPA that the QWindow + // this view backs became active: + QWindowSystemInterface::handleWindowActivated(m_qioswindow->window()); + return [super becomeFirstResponder]; +} + +- (BOOL)resignFirstResponder +{ + QWindowSystemInterface::handleWindowActivated(0); + return [super resignFirstResponder]; +} + - (BOOL)hasText { return YES; @@ -416,7 +433,6 @@ void QIOSWindow::requestActivateWindow() raise(); QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view); - QPlatformWindow::requestActivateWindow(); } void QIOSWindow::raiseOrLower(bool raise) diff --git a/src/plugins/platforms/ios/qtmain.mm b/src/plugins/platforms/ios/qtmain.mm deleted file mode 100644 index 19c98f2c59..0000000000 --- a/src/plugins/platforms/ios/qtmain.mm +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qiosapplicationdelegate.h" -#include "qiosviewcontroller.h" - -int main(int argc, char *argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSMainWrapperApplicationDelegate class])); - } -} - -extern int qt_main(int argc, char *argv[]); - -@implementation QIOSMainWrapperApplicationDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; - self.qiosViewController = [[[QIOSViewController alloc] init] autorelease]; - self.window.rootViewController = self.qiosViewController; - -#ifdef QT_DEBUG - self.window.backgroundColor = [UIColor cyanColor]; -#endif - - [self.window makeKeyAndVisible]; - - // We schedule the main-redirection for the next eventloop pass so that we - // can return from this function and let UIApplicationMain finish its job. - [NSTimer scheduledTimerWithTimeInterval:.01f target:self - selector:@selector(runUserMain) userInfo:nil repeats:NO]; - - if ([QIOSApplicationDelegate instancesRespondToSelector:_cmd]) - return [super application:application didFinishLaunchingWithOptions:launchOptions]; - else - return YES; -} - -- (void)runUserMain -{ - NSArray *arguments = [[NSProcessInfo processInfo] arguments]; - int argc = arguments.count; - char **argv = new char*[argc]; - for (int i = 0; i < argc; ++i) { - NSString *arg = [arguments objectAtIndex:i]; - argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]])); - strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]); - } - - qt_main(argc, argv); - delete[] argv; -} - -@end diff --git a/src/plugins/platforms/ios/qtmain.pro b/src/plugins/platforms/ios/qtmain.pro deleted file mode 100644 index cbcb272217..0000000000 --- a/src/plugins/platforms/ios/qtmain.pro +++ /dev/null @@ -1,8 +0,0 @@ -TARGET = qiosmain - -PLUGIN_TYPE = platforms -load(qt_plugin) - -QT += gui-private - -OBJECTIVE_SOURCES = qtmain.mm diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro index 711cf9e5c7..612a878736 100644 --- a/src/plugins/platforms/kms/kms.pro +++ b/src/plugins/platforms/kms/kms.pro @@ -22,9 +22,6 @@ SOURCES = main.cpp \ qkmsdevice.cpp \ qkmsbackingstore.cpp \ qkmsnativeinterface.cpp \ - qkmsudevlistener.cpp \ - qkmsudevhandler.cpp \ - qkmsudevdrmhandler.cpp \ qkmsvthandler.cpp HEADERS = qkmsintegration.h \ qkmsscreen.h \ @@ -34,9 +31,6 @@ HEADERS = qkmsintegration.h \ qkmsdevice.h \ qkmsbackingstore.h \ qkmsnativeinterface.h \ - qkmsudevlistener.h \ - qkmsudevhandler.h \ - qkmsudevdrmhandler.h \ qkmsvthandler.h OTHER_FILES += \ diff --git a/src/plugins/platforms/kms/main.cpp b/src/plugins/platforms/kms/main.cpp index 75f7ef5278..db0582e694 100644 --- a/src/plugins/platforms/kms/main.cpp +++ b/src/plugins/platforms/kms/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QKmsIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "kms.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "kms.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp index 8210b54535..539363722d 100644 --- a/src/plugins/platforms/kms/qkmsintegration.cpp +++ b/src/plugins/platforms/kms/qkmsintegration.cpp @@ -46,10 +46,14 @@ #include "qkmsbackingstore.h" #include "qkmscontext.h" #include "qkmsnativeinterface.h" -#include "qkmsudevlistener.h" -#include "qkmsudevdrmhandler.h" #include "qkmsvthandler.h" +#if !defined(QT_NO_EVDEV) +#include <QtPlatformSupport/private/qevdevmousemanager_p.h> +#include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h> +#include <QtPlatformSupport/private/qevdevtouch_p.h> +#endif + #include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> #include <QtGui/private/qguiapplication_p.h> @@ -62,18 +66,32 @@ QKmsIntegration::QKmsIntegration() : QPlatformIntegration(), m_fontDatabase(new QGenericUnixFontDatabase()), m_eventDispatcher(createUnixEventDispatcher()), - m_nativeInterface(new QKmsNativeInterface), - m_udevListener(new QKmsUdevListener) + m_nativeInterface(new QKmsNativeInterface) { QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); setenv("EGL_PLATFORM", "drm",1); m_vtHandler = new QKmsVTHandler; - m_drmHandler = new QKmsUdevDRMHandler(this); - m_udevListener->addHandler(m_drmHandler); + + m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_DRM | QDeviceDiscovery::Device_DRM_PrimaryGPU, 0); + if (m_deviceDiscovery) { + QStringList devices = m_deviceDiscovery->scanConnectedDevices(); + foreach (QString device, devices) + addDevice(device); + + connect(m_deviceDiscovery, SIGNAL(deviceDetected(QString)), this, SLOT(addDevice(QString))); + connect(m_deviceDiscovery, SIGNAL(deviceRemoved(QString)), this, SLOT(removeDevice(QString))); + } + +#if !defined(QT_NO_EVDEV) + new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); + new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this); + new QEvdevTouchScreenHandlerThread(QString() /* spec */, this); +#endif } QKmsIntegration::~QKmsIntegration() { + delete m_deviceDiscovery; foreach (QKmsDevice *device, m_devices) { delete device; } @@ -81,15 +99,18 @@ QKmsIntegration::~QKmsIntegration() delete screen; } delete m_fontDatabase; - delete m_udevListener; delete m_vtHandler; } -QObject *QKmsIntegration::createDevice(const char *path) +void QKmsIntegration::addDevice(const QString &deviceNode) +{ + m_devices.append(new QKmsDevice(deviceNode, this)); +} + +void QKmsIntegration::removeDevice(const QString &deviceNode) { - QKmsDevice *device = new QKmsDevice(path, this); - m_devices.append(device); - return device; + // TODO: support hot-plugging some day? + Q_UNUSED(deviceNode); } bool QKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const diff --git a/src/plugins/platforms/kms/qkmsintegration.h b/src/plugins/platforms/kms/qkmsintegration.h index c08396ba3f..5069753aa5 100644 --- a/src/plugins/platforms/kms/qkmsintegration.h +++ b/src/plugins/platforms/kms/qkmsintegration.h @@ -44,17 +44,18 @@ #include <qpa/qplatformintegration.h> #include <qpa/qplatformnativeinterface.h> +#include <QtPlatformSupport/private/qdevicediscovery_p.h> QT_BEGIN_NAMESPACE class QKmsScreen; class QKmsDevice; -class QKmsUdevListener; -class QKmsUdevDRMHandler; class QKmsVTHandler; -class QKmsIntegration : public QPlatformIntegration +class QKmsIntegration : public QObject, public QPlatformIntegration { + Q_OBJECT + public: QKmsIntegration(); ~QKmsIntegration(); @@ -73,6 +74,10 @@ public: void addScreen(QKmsScreen *screen); QObject *createDevice(const char *); +private slots: + void addDevice(const QString &deviceNode); + void removeDevice(const QString &deviceNode); + private: QStringList findDrmDevices(); @@ -81,9 +86,8 @@ private: QPlatformFontDatabase *m_fontDatabase; QAbstractEventDispatcher *m_eventDispatcher; QPlatformNativeInterface *m_nativeInterface; - QKmsUdevListener *m_udevListener; - QKmsUdevDRMHandler *m_drmHandler; QKmsVTHandler *m_vtHandler; + QDeviceDiscovery *m_deviceDiscovery; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp index a1037c4feb..579984d2fc 100644 --- a/src/plugins/platforms/linuxfb/main.cpp +++ b/src/plugins/platforms/linuxfb/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QLinuxFbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "linuxfb.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "linuxfb.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/minimal/main.cpp b/src/plugins/platforms/minimal/main.cpp index 811f1fe5ee..7846b5b387 100644 --- a/src/plugins/platforms/minimal/main.cpp +++ b/src/plugins/platforms/minimal/main.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class QMinimalIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "minimal.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "minimal.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/minimalegl/main.cpp b/src/plugins/platforms/minimalegl/main.cpp index 414f45c745..c951bfb0dc 100644 --- a/src/plugins/platforms/minimalegl/main.cpp +++ b/src/plugins/platforms/minimalegl/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QMinimalEglIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "minimalegl.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "minimalegl.json") public: QStringList keys() const; QPlatformIntegration *create(const QString&, const QStringList&); diff --git a/src/plugins/platforms/offscreen/main.cpp b/src/plugins/platforms/offscreen/main.cpp index ca7dc1d18b..f48451d00d 100644 --- a/src/plugins/platforms/offscreen/main.cpp +++ b/src/plugins/platforms/offscreen/main.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class QOffscreenIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "offscreen.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "offscreen.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/openwfd/main.cpp b/src/plugins/platforms/openwfd/main.cpp index 724c5cfa4b..cea3c50e56 100644 --- a/src/plugins/platforms/openwfd/main.cpp +++ b/src/plugins/platforms/openwfd/main.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE class QOpenWFDIntegrationPlugin : public QPlatformIntegrationPlugin { - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/qnx/main.cpp b/src/plugins/platforms/qnx/main.cpp index ea50b12cb3..fb81928625 100644 --- a/src/plugins/platforms/qnx/main.cpp +++ b/src/plugins/platforms/qnx/main.cpp @@ -46,9 +46,8 @@ QT_BEGIN_NAMESPACE QPlatformIntegration *QQnxIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - Q_UNUSED(paramList); if (system.toLower() == QLatin1String("qnx")) - return new QQnxIntegration; + return new QQnxIntegration(paramList); return 0; } diff --git a/src/plugins/platforms/qnx/main.h b/src/plugins/platforms/qnx/main.h index 0b5f6323c4..683b20efd2 100644 --- a/src/plugins/platforms/qnx/main.h +++ b/src/plugins/platforms/qnx/main.h @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE class QQnxIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "qnx.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "qnx.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 398b64640e..7c497b4434 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -11,11 +11,11 @@ QT += platformsupport-private core-private gui-private CONFIG(blackberry) { CONFIG += qqnx_pps - # Unomment this to enable screen event handling - # through a dedicated thread. - # DEFINES += QQNX_SCREENEVENTTHREAD + # Uncomment following line to enable screen event + # handling through a dedicated thread. + # CONFIG += qqnx_screeneventthread } else { - DEFINES += QQNX_SCREENEVENTTHREAD + CONFIG += qqnx_screeneventthread } # Uncomment these to enable debugging output for various aspects of the plugin @@ -40,11 +40,11 @@ CONFIG(blackberry) { #DEFINES += QQNXVIRTUALKEYBOARD_DEBUG #DEFINES += QQNXWINDOW_DEBUG #DEFINES += QQNXCURSOR_DEBUG +#DEFINES += QQNXFILEPICKER_DEBUG SOURCES = main.cpp \ qqnxbuffer.cpp \ - qqnxscreeneventthread.cpp \ qqnxintegration.cpp \ qqnxscreen.cpp \ qqnxwindow.cpp \ @@ -60,7 +60,6 @@ SOURCES = main.cpp \ HEADERS = main.h \ qqnxbuffer.h \ - qqnxscreeneventthread.h \ qqnxkeytranslator.h \ qqnxintegration.h \ qqnxscreen.h \ @@ -75,6 +74,12 @@ HEADERS = main.h \ qqnxservices.h \ qqnxcursor.h +CONFIG(qqnx_screeneventthread) { + DEFINES += QQNX_SCREENEVENTTHREAD + SOURCES += qqnxscreeneventthread.cpp + HEADERS += qqnxscreeneventthread.h +} + LIBS += -lscreen contains(QT_CONFIG, opengles2) { @@ -91,8 +96,7 @@ CONFIG(blackberry) { qqnxbpseventfilter.cpp \ qqnxvirtualkeyboardbps.cpp \ qqnxtheme.cpp \ - qqnxsystemsettings.cpp \ - qqnxfiledialoghelper.cpp + qqnxsystemsettings.cpp HEADERS += qqnxnavigatorbps.h \ qqnxeventdispatcher_blackberry.h \ @@ -105,6 +109,17 @@ CONFIG(blackberry) { LIBS += -lbps } +CONFIG(blackberry-playbook) { + SOURCES += qqnxfiledialoghelper_playbook.cpp +} else { + CONFIG(blackberry) { + SOURCES += qqnxfiledialoghelper_bb10.cpp \ + qqnxfilepicker.cpp + + HEADERS += qqnxfilepicker.h + } +} + CONFIG(qqnx_pps) { DEFINES += QQNX_PPS diff --git a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp index d94d3c092a..133bf02fee 100644 --- a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp +++ b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp @@ -41,11 +41,12 @@ #include "qqnxbpseventfilter.h" #include "qqnxnavigatoreventhandler.h" -#include "qqnxfiledialoghelper.h" #include "qqnxscreen.h" #include "qqnxscreeneventhandler.h" #include "qqnxvirtualkeyboardbps.h" +#include "qqnxfiledialoghelper.h" +#include <QCoreApplication> #include <QAbstractEventDispatcher> #include <QDebug> @@ -126,6 +127,7 @@ void QQnxBpsEventFilter::unregisterForScreenEvents(QQnxScreen *screen) qWarning("QQNX: failed to unregister for screen events on screen %p", screen->nativeContext()); } +#if defined(Q_OS_BLACKBERRY_TABLET) void QQnxBpsEventFilter::registerForDialogEvents(QQnxFileDialogHelper *dialog) { if (dialog_request_events(0) != BPS_SUCCESS) @@ -141,6 +143,7 @@ void QQnxBpsEventFilter::unregisterForDialogEvents(QQnxFileDialogHelper *dialog) if (count == 0) qWarning("QQNX: attempting to unregister dialog that was not registered"); } +#endif // Q_OS_BLACKBERRY_TABLET bool QQnxBpsEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { @@ -160,12 +163,14 @@ bool QQnxBpsEventFilter::nativeEventFilter(const QByteArray &eventType, void *me return m_screenEventHandler->handleEvent(screenEvent); } +#if defined(Q_OS_BLACKBERRY_TABLET) if (eventDomain == dialog_get_domain()) { dialog_instance_t nativeDialog = dialog_event_get_dialog_instance(event); QQnxFileDialogHelper *dialog = m_dialogMapper.value(nativeDialog, 0); if (dialog) return dialog->handleEvent(event); } +#endif if (eventDomain == navigator_get_domain()) return handleNavigatorEvent(event); @@ -244,6 +249,11 @@ bool QQnxBpsEventFilter::handleNavigatorEvent(bps_event_t *event) break; } + case NAVIGATOR_LOW_MEMORY: + qWarning() << "QGuiApplication based process" << QCoreApplication::applicationPid() + << "received \"NAVIGATOR_LOW_MEMORY\" event"; + return false; + default: qBpsEventFilterDebug() << Q_FUNC_INFO << "Unhandled navigator event. code=" << bps_event_get_code(event); return false; diff --git a/src/plugins/platforms/qnx/qqnxbpseventfilter.h b/src/plugins/platforms/qnx/qqnxbpseventfilter.h index e897863efb..f8e36823d5 100644 --- a/src/plugins/platforms/qnx/qqnxbpseventfilter.h +++ b/src/plugins/platforms/qnx/qqnxbpseventfilter.h @@ -73,8 +73,10 @@ public: void registerForScreenEvents(QQnxScreen *screen); void unregisterForScreenEvents(QQnxScreen *screen); +#ifdef Q_OS_BLACKBERRY_TABLET void registerForDialogEvents(QQnxFileDialogHelper *dialog); void unregisterForDialogEvents(QQnxFileDialogHelper *dialog); +#endif private: bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h index e17ea80501..e7c68f6ff5 100644 --- a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h @@ -44,12 +44,19 @@ #include <qpa/qplatformdialoghelper.h> -#include <bps/dialog.h> QT_BEGIN_NAMESPACE class QQnxIntegration; +#if defined(Q_OS_BLACKBERRY_TABLET) +#include <bps/dialog.h> +#define NativeDialogPtr dialog_instance_t +#else +class QQnxFilePicker; +#define NativeDialogPtr QQnxFilePicker * +#endif + class QQnxFileDialogHelper : public QPlatformFileDialogHelper { Q_OBJECT @@ -57,7 +64,9 @@ public: explicit QQnxFileDialogHelper(const QQnxIntegration *); ~QQnxFileDialogHelper(); +#if defined(Q_OS_BLACKBERRY_TABLET) bool handleEvent(bps_event_t *event); +#endif void exec(); @@ -65,29 +74,32 @@ public: void hide(); bool defaultNameFilterDisables() const; - void setDirectory(const QString &directory); - QString directory() const; - void selectFile(const QString &fileName); - QStringList selectedFiles() const; + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &fileName) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; void setFilter(); void selectNameFilter(const QString &filter); QString selectedNameFilter() const; - dialog_instance_t nativeDialog() const { return m_dialog; } + NativeDialogPtr nativeDialog() const { return m_dialog; } Q_SIGNALS: void dialogClosed(); private: void setNameFilter(const QString &filter); + void setNameFilters(const QStringList &filters); const QQnxIntegration *m_integration; - dialog_instance_t m_dialog; + NativeDialogPtr m_dialog; QFileDialogOptions::AcceptMode m_acceptMode; QString m_selectedFilter; QPlatformDialogHelper::DialogCode m_result; - QStringList m_paths; +#if defined(Q_OS_BLACKBERRY_TABLET) + QList<QUrl> m_paths; +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper_bb10.cpp b/src/plugins/platforms/qnx/qqnxfiledialoghelper_bb10.cpp new file mode 100644 index 0000000000..dc841eb1a9 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper_bb10.cpp @@ -0,0 +1,217 @@ +/*************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqnxfiledialoghelper.h" + +#include "qqnxfilepicker.h" +#include "qqnxbpseventfilter.h" +#include "qqnxscreen.h" +#include "qqnxintegration.h" + +#include <QDebug> +#include <QEventLoop> +#include <QScreen> +#include <QTimer> +#include <QWindow> + +#ifdef QQNXFILEDIALOGHELPER_DEBUG +#define qFileDialogHelperDebug qDebug +#else +#define qFileDialogHelperDebug QT_NO_QDEBUG_MACRO +#endif + +QT_BEGIN_NAMESPACE + +QQnxFileDialogHelper::QQnxFileDialogHelper(const QQnxIntegration *integration) + : QPlatformFileDialogHelper(), + m_integration(integration), + m_dialog(new QQnxFilePicker), + m_acceptMode(QFileDialogOptions::AcceptOpen), + m_selectedFilter(), + m_result(QPlatformDialogHelper::Rejected) +{ +} + +QQnxFileDialogHelper::~QQnxFileDialogHelper() +{ + delete m_dialog; +} + +void QQnxFileDialogHelper::exec() +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + + // Clear any previous results + m_dialog->setDirectories(QStringList()); + + QEventLoop loop; + connect(m_dialog, SIGNAL(closed()), &loop, SLOT(quit())); + loop.exec(); + + if (m_dialog->selectedFiles().isEmpty()) + Q_EMIT reject(); + else + Q_EMIT accept(); +} + +bool QQnxFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) +{ + Q_UNUSED(flags); + Q_UNUSED(parent); + Q_UNUSED(modality); + + qFileDialogHelperDebug() << Q_FUNC_INFO; + + // Create dialog + const QSharedPointer<QFileDialogOptions> &opts = options(); + if (opts->acceptMode() == QFileDialogOptions::AcceptOpen) { + // Select one or many files? + const QQnxFilePicker::Mode mode = (opts->fileMode() == QFileDialogOptions::ExistingFiles) + ? QQnxFilePicker::PickerMultiple : QQnxFilePicker::Picker; + + m_dialog->setMode(mode); + + // Set the actual list of extensions + if (!opts->nameFilters().isEmpty()) + setNameFilters(opts->nameFilters()); + else + setNameFilter(tr("All files (*.*)")); + } else { + const QQnxFilePicker::Mode mode = (opts->initiallySelectedFiles().count() >= 2) + ? QQnxFilePicker::SaverMultiple : QQnxFilePicker::Saver; + + m_dialog->setMode(mode); + + if (!opts->initiallySelectedFiles().isEmpty()) { + QStringList files; + Q_FOREACH ( const QUrl &url, opts->initiallySelectedFiles() ) + files.append(url.toLocalFile()); + m_dialog->setDefaultSaveFileNames(files); + } + } + + // Cache the accept mode so we know which functions to use to get the results back + m_acceptMode = opts->acceptMode(); + m_dialog->setTitle(opts->windowTitle()); + m_dialog->open(); + + return true; +} + +void QQnxFileDialogHelper::hide() +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + m_dialog->close(); +} + +bool QQnxFileDialogHelper::defaultNameFilterDisables() const +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + return false; +} + +void QQnxFileDialogHelper::setDirectory(const QUrl &directory) +{ + m_dialog->addDirectory(directory.toLocalFile()); +} + +QUrl QQnxFileDialogHelper::directory() const +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + if (!m_dialog->directories().isEmpty()) + return QUrl::fromLocalFile(m_dialog->directories().first()); + + return QUrl(); +} + +void QQnxFileDialogHelper::selectFile(const QUrl &fileName) +{ + m_dialog->addDefaultSaveFileName(fileName.toLocalFile()); +} + +QList<QUrl> QQnxFileDialogHelper::selectedFiles() const +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + QList<QUrl> urls; + QStringList files = m_dialog->selectedFiles(); + Q_FOREACH (const QString &file, files) + urls.append(QUrl::fromLocalFile(file)); + return urls; +} + +void QQnxFileDialogHelper::setFilter() +{ + // No native api to support setting a filter from QDir::Filters + qFileDialogHelperDebug() << Q_FUNC_INFO; +} + +void QQnxFileDialogHelper::selectNameFilter(const QString &filter) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter; + setNameFilter(filter); +} + +QString QQnxFileDialogHelper::selectedNameFilter() const +{ + // For now there is no way for the user to change the selected filter + // so this just reflects what the developer has set programmatically. + qFileDialogHelperDebug() << Q_FUNC_INFO; + return m_selectedFilter; +} + +void QQnxFileDialogHelper::setNameFilter(const QString &filter) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter; + + setNameFilters(QPlatformFileDialogHelper::cleanFilterList(filter)); +} + +void QQnxFileDialogHelper::setNameFilters(const QStringList &filters) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filters =" << filters; + + Q_ASSERT(!filters.isEmpty()); + + m_dialog->setFilters(filters); + m_selectedFilter = filters.first(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp b/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp index 0325a33268..2a743d03f7 100644 --- a/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp @@ -102,7 +102,7 @@ bool QQnxFileDialogHelper::handleEvent(bps_event_t *event) for (int i = 0; i < pathCount; ++i) { QString path = QFile::decodeName(filePaths[i]); - m_paths.append(path); + m_paths.append(QUrl::fromLocalFile(path)); qFileDialogHelperDebug() << "path =" << path; } @@ -112,13 +112,13 @@ bool QQnxFileDialogHelper::handleEvent(bps_event_t *event) const char *filePath = dialog_event_get_filesave_filepath(event); QString path = QFile::decodeName(filePath); qFileDialogHelperDebug() << "path =" << path; - m_paths.append(path); + m_paths.append(QUrl::fromLocalFile(path)); } } else { // Cancel m_result = QPlatformDialogHelper::Rejected; } - emit dialogClosed(); + Q_EMIT dialogClosed(); return true; } @@ -135,9 +135,9 @@ void QQnxFileDialogHelper::exec() loop.exec(); if (m_result == QPlatformDialogHelper::Accepted) - emit accept(); + Q_EMIT accept(); else - emit reject(); + Q_EMIT reject(); } bool QQnxFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) @@ -188,7 +188,7 @@ bool QQnxFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modali // Maybe pre-select a filename if (!opts->initiallySelectedFiles().isEmpty()) { - QString fileName = opts->initiallySelectedFiles().first(); + QString fileName = opts->initiallySelectedFiles().first().toLocalFile(); dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName).constData()); } @@ -240,29 +240,29 @@ bool QQnxFileDialogHelper::defaultNameFilterDisables() const return false; } -void QQnxFileDialogHelper::setDirectory(const QString &directory) +void QQnxFileDialogHelper::setDirectory(const QUrl &directory) { qFileDialogHelperDebug() << Q_FUNC_INFO << "directory =" << directory; // No native API for setting the directory(!). The best we can do is to // set it as the file name but even then only with a file save dialog. if (m_dialog && m_acceptMode == QFileDialogOptions::AcceptSave) - dialog_set_filesave_filename(m_dialog, QFile::encodeName(directory).constData()); + dialog_set_filesave_filename(m_dialog, QFile::encodeName(directory.toLocalFile()).constData()); } -QString QQnxFileDialogHelper::directory() const +QUrl QQnxFileDialogHelper::directory() const { qFileDialogHelperDebug() << Q_FUNC_INFO; return m_paths.first(); } -void QQnxFileDialogHelper::selectFile(const QString &fileName) +void QQnxFileDialogHelper::selectFile(const QUrl &fileName) { qFileDialogHelperDebug() << Q_FUNC_INFO << "filename =" << fileName; if (m_dialog && m_acceptMode == QFileDialogOptions::AcceptSave) - dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName).constData()); + dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName.toLocalFile()).constData()); } -QStringList QQnxFileDialogHelper::selectedFiles() const +QList<QUrl> QQnxFileDialogHelper::selectedFiles() const { qFileDialogHelperDebug() << Q_FUNC_INFO; return m_paths; @@ -291,9 +291,15 @@ QString QQnxFileDialogHelper::selectedNameFilter() const void QQnxFileDialogHelper::setNameFilter(const QString &filter) { qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter; + setNameFilters(QPlatformFileDialogHelper::cleanFilterList(filter)); +} + +void QQnxFileDialogHelper::setNameFilters(const QStringList &filters) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filters =" << filters; + + Q_ASSERT(!filters.isEmpty()); - // Extract the globbing expressions - QStringList filters = QPlatformFileDialogHelper::cleanFilterList(filter); char **globs = new char*[filters.size()]; for (int i = 0; i < filters.size(); ++i) { QByteArray glob = filters.at(i).toLocal8Bit(); @@ -303,7 +309,7 @@ void QQnxFileDialogHelper::setNameFilter(const QString &filter) // Set the filters dialog_set_filebrowse_filter(m_dialog, const_cast<const char**>(globs), filters.size()); - m_selectedFilter = filter; + m_selectedFilter = filters.first(); // Cleanup for (int i = 0; i < filters.size(); ++i) diff --git a/src/plugins/platforms/qnx/qqnxfilepicker.cpp b/src/plugins/platforms/qnx/qqnxfilepicker.cpp new file mode 100644 index 0000000000..5229d1f1f5 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxfilepicker.cpp @@ -0,0 +1,289 @@ +/*************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqnxfilepicker.h" + +#include <QAbstractEventDispatcher> +#include <QCoreApplication> +#include <QDebug> +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonArray> +#include <QJsonParseError> +#include <QUrl> + +#include <bps/navigator.h> +#include <bps/navigator_invoke.h> + +#include <errno.h> + +#ifdef QQNXFILEPICKER_DEBUG +#define qFilePickerDebug qDebug +#else +#define qFilePickerDebug QT_NO_QDEBUG_MACRO +#endif + +static const char s_filePickerTarget[] = "sys.filepicker.target"; + +QQnxFilePicker::QQnxFilePicker(QObject *parent) + : QObject(parent) + , m_invocationHandle(0) + , m_mode(QQnxFilePicker::Picker) + , m_title(tr("Pick a file")) +{ + QCoreApplication::eventDispatcher()->installNativeEventFilter(this); +} + +QQnxFilePicker::~QQnxFilePicker() +{ + cleanup(); + + QCoreApplication::eventDispatcher()->removeNativeEventFilter(this); +} + +void QQnxFilePicker::open() +{ + if (m_invocationHandle) + return; + + int errorCode = BPS_SUCCESS; + + errorCode = navigator_invoke_invocation_create(&m_invocationHandle); + if (errorCode != BPS_SUCCESS) { + qWarning() << "QQnxFilePicker: unable to create invocation:" << strerror(errno); + return; + } + + errorCode = navigator_invoke_invocation_set_target(m_invocationHandle, s_filePickerTarget); + + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set target:" << strerror(errno); + return; + } + + errorCode = navigator_invoke_invocation_set_action(m_invocationHandle, "bb.action.OPEN"); + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set action:" << strerror(errno); + return; + } + + errorCode = navigator_invoke_invocation_set_type(m_invocationHandle, "application/vnd.blackberry.file_picker"); + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set mime type:" << strerror(errno); + return; + } + + QVariantMap map; + map[QStringLiteral("Type")] = QStringLiteral("Other"); + map[QStringLiteral("Mode")] = modeToString(m_mode); + map[QStringLiteral("Title")] = m_title; + map[QStringLiteral("ViewMode")] = QStringLiteral("Default"); + map[QStringLiteral("SortBy")] = QStringLiteral("Default"); + map[QStringLiteral("SortOrder")] = QStringLiteral("Default"); + map[QStringLiteral("ImageCrop")] = false; + map[QStringLiteral("AllowOverwrite")] = false; + + if (!m_defaultSaveFileNames.isEmpty()) + map[QStringLiteral("DefaultFileNames")] = m_defaultSaveFileNames.join(","); + if (!m_filters.isEmpty()) + map[QStringLiteral("Filter")] = m_filters.join(";"); + + QJsonDocument document; + document.setObject(QJsonObject::fromVariantMap(map)); + const QByteArray jsonData = document.toJson(QJsonDocument::Compact); + + errorCode = navigator_invoke_invocation_set_data(m_invocationHandle, jsonData.constData(), jsonData.size()); + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set data:" << strerror(errno); + return; + } + + navigator_invoke_invocation_send(m_invocationHandle); +} + +void QQnxFilePicker::close() +{ + navigator_card_close_child(); + cleanup(); +} + +bool QQnxFilePicker::nativeEventFilter(const QByteArray&, void *message, long*) +{ + bps_event_t * const event = static_cast<bps_event_t*>(message); + if (!event) + return false; + + if (bps_event_get_code(event) == NAVIGATOR_INVOKE_TARGET_RESULT) { + const char *id = navigator_event_get_id(event); + const char *err = navigator_event_get_err(event); + qFilePickerDebug("received invocation response: id=%s err=%s", id, err); + } else if (bps_event_get_code(event) == NAVIGATOR_CHILD_CARD_CLOSED) { + const char *data = navigator_event_get_card_closed_data(event); + qFilePickerDebug("received data: data='%s'", data); + handleFilePickerResponse(data); + } + + return false; // do not drop the event +} + +void QQnxFilePicker::setMode(QQnxFilePicker::Mode mode) +{ + m_mode = mode; +} + +void QQnxFilePicker::setDefaultSaveFileNames(const QStringList &fileNames) +{ + m_defaultSaveFileNames = fileNames; +} + +void QQnxFilePicker::addDefaultSaveFileName(const QString &fileName) +{ + m_defaultSaveFileNames.append(fileName); +} + +void QQnxFilePicker::setDirectories(const QStringList &directories) +{ + m_directories = directories; +} + +void QQnxFilePicker::addDirectory(const QString &directory) +{ + m_directories.append(directory); +} + +void QQnxFilePicker::setFilters(const QStringList &filters) +{ + m_filters = filters; +} + +void QQnxFilePicker::setTitle(const QString &title) +{ + m_title = title; +} + +QQnxFilePicker::Mode QQnxFilePicker::mode() const +{ + return m_mode; +} + +QStringList QQnxFilePicker::defaultSaveFileNames() const +{ + return m_defaultSaveFileNames; +} + +QStringList QQnxFilePicker::directories() const +{ + return m_directories; +} + +QStringList QQnxFilePicker::filters() const +{ + return m_filters; +} + +QStringList QQnxFilePicker::selectedFiles() const +{ + return m_selectedFiles; +} + +QString QQnxFilePicker::title() const +{ + return m_title; +} + +void QQnxFilePicker::cleanup() +{ + if (m_invocationHandle) { + navigator_invoke_invocation_destroy(m_invocationHandle); + m_invocationHandle = 0; + } +} + +void QQnxFilePicker::handleFilePickerResponse(const char *data) +{ + QJsonParseError jsonError; + QJsonDocument document = QJsonDocument::fromJson(data, &jsonError); + + if (jsonError.error != QJsonParseError::NoError) { + qFilePickerDebug() << "Error parsing FilePicker response: " + << jsonError.errorString(); + Q_EMIT closed(); + cleanup(); + return; + } + + // The response is a list of Json objects. + const QVariantList array = document.array().toVariantList(); + + foreach (const QVariant &variant, array) { + const QJsonObject object = QJsonObject::fromVariantMap(variant.toMap()); + const QUrl url(object.value(QStringLiteral("uri")).toString()); + const QString localFile = url.toLocalFile(); // strip "file://" + + if (!localFile.isEmpty()) + m_selectedFiles << localFile; + + qFilePickerDebug() << "FilePicker uri response:" << localFile; + } + + Q_EMIT closed(); + cleanup(); +} + +QString QQnxFilePicker::modeToString(QQnxFilePicker::Mode mode) const +{ + switch (mode) { + case Picker: + return QStringLiteral("Picker"); + case Saver: + return QStringLiteral("Saver"); + case PickerMultiple: + return QStringLiteral("PickerMultiple"); + case SaverMultiple: + return QStringLiteral("SaverMultiple"); + } + + return QStringLiteral("Picker"); +} diff --git a/src/plugins/platforms/kms/qkmsudevlistener.cpp b/src/plugins/platforms/qnx/qqnxfilepicker.h index b2fb110479..5bb8f0969f 100644 --- a/src/plugins/platforms/kms/qkmsudevlistener.cpp +++ b/src/plugins/platforms/qnx/qqnxfilepicker.h @@ -1,6 +1,6 @@ -/**************************************************************************** +/*************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Research In Motion ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -39,63 +39,72 @@ ** ****************************************************************************/ -#include <qkmsudevlistener.h> +#ifndef QQNXFILEPICKER_H +#define QQNXFILEPICKER_H -QT_BEGIN_NAMESPACE +#include <QAbstractNativeEventFilter> +#include <QObject> +#include <QStringList> -QKmsUdevListener::QKmsUdevListener(QObject *parent) - : QObject(parent) -{ - m_udev = udev_new(); -} +struct navigator_invoke_invocation_t; -QKmsUdevListener::~QKmsUdevListener() +class QQnxFilePicker : public QObject, public QAbstractNativeEventFilter { - udev_unref(m_udev); -} + Q_OBJECT -void QKmsUdevListener::addHandler(QKmsUdevHandler *handler) -{ - m_handlers.removeAll((QKmsUdevHandler *) 0); - m_handlers.removeAll(handler); - m_handlers.prepend(handler); +public: + explicit QQnxFilePicker(QObject *parent = 0); + ~QQnxFilePicker(); - scan(); -} + enum Mode { + Picker, + Saver, + PickerMultiple, + SaverMultiple + }; -bool QKmsUdevListener::create(struct udev_device *device) -{ - foreach (QKmsUdevHandler *handler, m_handlers) { - if (!handler) - continue; + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; - QObject *obj = handler->create(device); - if (obj) { - m_devices[udev_device_get_syspath(device)] = obj; - return true; - } - } + void setMode(Mode mode); + void setDefaultSaveFileNames(const QStringList &fileNames); + void addDefaultSaveFileName(const QString &fileName); + void setDirectories(const QStringList &directories); + void addDirectory(const QString &directory); + void setFilters(const QStringList &filters); + void setTitle(const QString &title); - return false; -} + Mode mode() const; -void QKmsUdevListener::scan() -{ - struct udev_enumerate *e; - struct udev_list_entry *entry; - - e = udev_enumerate_new(m_udev); - udev_enumerate_scan_devices(e); - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { - const char *path = udev_list_entry_get_name(entry); - if (m_devices.contains(path)) - continue; - - struct udev_device *device = udev_device_new_from_syspath(m_udev, path); - create(device); - udev_device_unref(device); - } - udev_enumerate_unref(e); -} - -QT_END_NAMESPACE + QStringList defaultSaveFileNames() const; + QStringList directories() const; + QStringList filters() const; + QStringList selectedFiles() const; + + QString title() const; + +Q_SIGNALS: + void closed(); + +public Q_SLOTS: + void open(); + void close(); + +private: + void cleanup(); + void handleFilePickerResponse(const char *data); + + QString modeToString(Mode mode) const; + + navigator_invoke_invocation_t *m_invocationHandle; + + Mode m_mode; + + QStringList m_defaultSaveFileNames; + QStringList m_directories; + QStringList m_filters; + QStringList m_selectedFiles; + + QString m_title; +}; + +#endif // QQNXFILEPICKER_H diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index ed959467ff..448509c69d 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -60,36 +60,10 @@ QT_BEGIN_NAMESPACE EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY; -static EGLenum checkEGLError(const char *msg) -{ - static const char *errmsg[] = - { - "EGL function succeeded", - "EGL is not initialized, or could not be initialized, for the specified display", - "EGL cannot access a requested resource", - "EGL failed to allocate resources for the requested operation", - "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", - "EGLConfig argument does not name a valid EGLConfig", - "EGLContext argument does not name a valid EGLContext", - "EGL current surface of the calling thread is no longer valid", - "EGLDisplay argument does not name a valid EGLDisplay", - "EGL arguments are inconsistent", - "EGLNativePixmapType argument does not refer to a valid native pixmap", - "EGLNativeWindowType argument does not refer to a valid native window", - "EGL one or more argument values are invalid", - "EGLSurface argument does not name a valid surface configured for rendering", - "EGL power management event has occurred", - }; - EGLenum error = eglGetError(); - fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); - return error; -} - QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext) : QPlatformOpenGLContext(), m_glContext(glContext), - m_eglSurface(EGL_NO_SURFACE), - m_newSurfaceRequested(true) // Create a surface the first time makeCurrent() is called + m_currentEglSurface(EGL_NO_SURFACE) { qGLContextDebug() << Q_FUNC_INFO; QSurfaceFormat format = m_glContext->format(); @@ -168,9 +142,31 @@ QQnxGLContext::~QQnxGLContext() // Cleanup EGL context if it exists if (m_eglContext != EGL_NO_CONTEXT) eglDestroyContext(ms_eglDisplay, m_eglContext); +} - // Cleanup EGL surface if it exists - destroySurface(); +EGLenum QQnxGLContext::checkEGLError(const char *msg) +{ + static const char *errmsg[] = + { + "EGL function succeeded", + "EGL is not initialized, or could not be initialized, for the specified display", + "EGL cannot access a requested resource", + "EGL failed to allocate resources for the requested operation", + "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", + "EGLConfig argument does not name a valid EGLConfig", + "EGLContext argument does not name a valid EGLContext", + "EGL current surface of the calling thread is no longer valid", + "EGLDisplay argument does not name a valid EGLDisplay", + "EGL arguments are inconsistent", + "EGLNativePixmapType argument does not refer to a valid native pixmap", + "EGLNativeWindowType argument does not refer to a valid native window", + "EGL one or more argument values are invalid", + "EGLSurface argument does not name a valid surface configured for rendering", + "EGL power management event has occurred", + }; + EGLenum error = eglGetError(); + fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); + return error; } void QQnxGLContext::initialize() @@ -199,12 +195,6 @@ void QQnxGLContext::shutdown() eglTerminate(ms_eglDisplay); } -void QQnxGLContext::requestSurfaceChange() -{ - qGLContextDebug() << Q_FUNC_INFO; - m_newSurfaceRequested.testAndSetRelease(false, true); -} - bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) { qGLContextDebug() << Q_FUNC_INFO; @@ -216,14 +206,18 @@ bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) if (eglResult != EGL_TRUE) qFatal("QQnxGLContext: failed to set EGL API, err=%d", eglGetError()); - if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { - qGLContextDebug() << "New EGL surface requested"; + QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); + if (!platformWindow) + return false; + + platformWindow->setPlatformOpenGLContext(this); + + if (m_currentEglSurface == EGL_NO_SURFACE || m_currentEglSurface != platformWindow->getSurface()) { + m_currentEglSurface = platformWindow->getSurface(); doneCurrent(); - destroySurface(); - createSurface(surface); } - eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); + eglResult = eglMakeCurrent(ms_eglDisplay, m_currentEglSurface, m_currentEglSurface, m_eglContext); if (eglResult != EGL_TRUE) { checkEGLError("eglMakeCurrent"); qFatal("QQNX: failed to set current EGL context, err=%d", eglGetError()); @@ -248,18 +242,12 @@ void QQnxGLContext::doneCurrent() void QQnxGLContext::swapBuffers(QPlatformSurface *surface) { - Q_UNUSED(surface); qGLContextDebug() << Q_FUNC_INFO; + QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); + if (!platformWindow) + return; - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Post EGL surface to window - eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) - qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); + platformWindow->swapEGLBuffers(); } QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName) @@ -275,6 +263,10 @@ QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName) return static_cast<QFunctionPointer>(eglGetProcAddress(procName.constData())); } +EGLDisplay QQnxGLContext::getEglDisplay() { + return ms_eglDisplay; +} + EGLint *QQnxGLContext::contextAttrs() { qGLContextDebug() << Q_FUNC_INFO; @@ -288,66 +280,4 @@ EGLint *QQnxGLContext::contextAttrs() #endif } -bool QQnxGLContext::isCurrent() const -{ - qGLContextDebug() << Q_FUNC_INFO; - return (eglGetCurrentContext() == m_eglContext); -} - -void QQnxGLContext::createSurface(QPlatformSurface *surface) -{ - qGLContextDebug() << Q_FUNC_INFO; - - // Get a pointer to the corresponding platform window - QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); - if (!platformWindow) - qFatal("QQNX: unable to create EGLSurface without a QQnxWindow"); - - // Link the window and context - platformWindow->setPlatformOpenGLContext(this); - - // Fetch the surface size from the window and update - // the window's buffers before we create the EGL surface - const QSize surfaceSize = platformWindow->requestedBufferSize(); - if (!surfaceSize.isValid()) { - qFatal("QQNX: Trying to create 0 size EGL surface. " - "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); - } - platformWindow->setBufferSize(surfaceSize); - - // Post root window, in case it hasn't been posted yet, to make it appear. - platformWindow->screen()->onWindowPost(platformWindow); - - // Obtain the native handle for our window - screen_window_t handle = platformWindow->nativeHandle(); - - const EGLint eglSurfaceAttrs[] = - { - EGL_RENDER_BUFFER, EGL_BACK_BUFFER, - EGL_NONE - }; - - // Create EGL surface - m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs); - if (m_eglSurface == EGL_NO_SURFACE) { - checkEGLError("eglCreateWindowSurface"); - qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); - } -} - -void QQnxGLContext::destroySurface() -{ - qGLContextDebug() << Q_FUNC_INFO; - - // Destroy EGL surface if it exists - if (m_eglSurface != EGL_NO_SURFACE) { - EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) { - qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); - } - } - - m_eglSurface = EGL_NO_SURFACE; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h index 6a7fca7df2..ff57861498 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -59,6 +59,8 @@ public: QQnxGLContext(QOpenGLContext *glContext); virtual ~QQnxGLContext(); + static EGLenum checkEGLError(const char *msg); + static void initialize(); static void shutdown(); @@ -71,13 +73,10 @@ public: virtual QSurfaceFormat format() const { return m_windowFormat; } - bool isCurrent() const; - - void createSurface(QPlatformSurface *surface); - void destroySurface(); - + static EGLDisplay getEglDisplay(); + EGLConfig getEglConfig() const { return m_eglConfig;} private: - /** \todo Should this be non-static so we can use additional displays? */ + //Can be static because different displays returne the same handle static EGLDisplay ms_eglDisplay; QSurfaceFormat m_windowFormat; @@ -85,9 +84,7 @@ private: EGLConfig m_eglConfig; EGLContext m_eglContext; - EGLSurface m_eglSurface; - - QAtomicInt m_newSurfaceRequested; + EGLSurface m_currentEglSurface; static EGLint *contextAttrs(); }; diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index feb05e3093..fa9961ccce 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -40,7 +40,9 @@ ****************************************************************************/ #include "qqnxintegration.h" +#if defined(QQNX_SCREENEVENTTHREAD) #include "qqnxscreeneventthread.h" +#endif #include "qqnxnativeinterface.h" #include "qqnxrasterbackingstore.h" #include "qqnxscreen.h" @@ -84,6 +86,8 @@ #include <qpa/qplatformwindow.h> #include <qpa/qwindowsysteminterface.h> +#include <QtGui/private/qguiapplication_p.h> + #if !defined(QT_NO_OPENGL) #include "qqnxglcontext.h" #include <QtGui/QOpenGLContext> @@ -107,9 +111,20 @@ QT_BEGIN_NAMESPACE QQnxWindowMapper QQnxIntegration::ms_windowMapper; QMutex QQnxIntegration::ms_windowMapperMutex; -QQnxIntegration::QQnxIntegration() +static inline QQnxIntegration::Options parseOptions(const QStringList ¶mList) +{ + QQnxIntegration::Options options = QQnxIntegration::NoOptions; + if (!paramList.contains(QLatin1String("no-fullscreen"))) { + options |= QQnxIntegration::FullScreenApplication; + } + return options; +} + +QQnxIntegration::QQnxIntegration(const QStringList ¶mList) : QPlatformIntegration() +#if defined(QQNX_SCREENEVENTTHREAD) , m_screenEventThread(0) +#endif , m_navigatorEventHandler(new QQnxNavigatorEventHandler()) , m_virtualKeyboard(0) #if defined(QQNX_PPS) @@ -134,6 +149,7 @@ QQnxIntegration::QQnxIntegration() #if !defined(QT_NO_DRAGANDDROP) , m_drag(new QSimpleDrag()) #endif + , m_options(parseOptions(paramList)) { qIntegrationDebug() << Q_FUNC_INFO; // Open connection to QNX composition manager @@ -185,8 +201,13 @@ QQnxIntegration::QQnxIntegration() #if defined(Q_OS_BLACKBERRY) QQnxVirtualKeyboardBps* virtualKeyboardBps = new QQnxVirtualKeyboardBps; - m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler, - (m_screenEventThread ? 0 : m_screenEventHandler), virtualKeyboardBps); + +#if defined(QQNX_SCREENEVENTTHREAD) + m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler, 0, virtualKeyboardBps); +#else + m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler, m_screenEventHandler, virtualKeyboardBps); +#endif + m_bpsEventFilter->installOnEventDispatcher(m_eventDispatcher); m_virtualKeyboard = virtualKeyboardBps; @@ -383,7 +404,7 @@ QPlatformDrag *QQnxIntegration::drag() const QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { qIntegrationDebug() << Q_FUNC_INFO; - if (hint == ShowIsFullScreen) + if ((hint == ShowIsFullScreen) && (m_options & FullScreenApplication)) return true; return QPlatformIntegration::styleHint(hint); @@ -526,6 +547,11 @@ QQnxScreen *QQnxIntegration::primaryDisplay() const return m_screens.first(); } +QQnxIntegration::Options QQnxIntegration::options() const +{ + return m_options; +} + bool QQnxIntegration::supportsNavigatorEvents() const { // If QQNX_PPS or Q_OS_BLACKBERRY is defined then we have navigator diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index e3eb9e06ba..dd8973b767 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -51,7 +51,9 @@ QT_BEGIN_NAMESPACE class QQnxBpsEventFilter; +#if defined(QQNX_SCREENEVENTTHREAD) class QQnxScreenEventThread; +#endif class QQnxFileDialogHelper; class QQnxNativeInterface; class QQnxWindow; @@ -80,7 +82,12 @@ typedef QHash<screen_window_t, QWindow *> QQnxWindowMapper; class QQnxIntegration : public QPlatformIntegration { public: - QQnxIntegration(); + enum Option { // Options to be passed on command line. + NoOptions = 0x0, + FullScreenApplication = 0x1 + }; + Q_DECLARE_FLAGS(Options, Option) + explicit QQnxIntegration(const QStringList ¶mList); ~QQnxIntegration(); bool hasCapability(QPlatformIntegration::Capability cap) const; @@ -129,6 +136,8 @@ public: void createDisplay(screen_display_t display, bool isPrimary); void removeDisplay(QQnxScreen *screen); QQnxScreen *primaryDisplay() const; + Options options() const; + private: void createDisplays(); void destroyDisplays(); @@ -137,7 +146,9 @@ private: static void removeWindow(screen_window_t qnxWindow); screen_context_t m_screenContext; +#if defined(QQNX_SCREENEVENTTHREAD) QQnxScreenEventThread *m_screenEventThread; +#endif QQnxNavigatorEventHandler *m_navigatorEventHandler; QQnxAbstractVirtualKeyboard *m_virtualKeyboard; #if defined(QQNX_PPS) @@ -164,6 +175,8 @@ private: static QQnxWindowMapper ms_windowMapper; static QMutex ms_windowMapperMutex; + const Options m_options; + friend class QQnxWindow; }; diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp index 6a7a4d0944..1da3cd5446 100644 --- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp +++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp @@ -91,6 +91,11 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const if (window) targetWindow = static_cast<QQnxWindow *>(window->handle()); + // we only need to flush the platformWindow backing store, since this is + // the buffer where all drawing operations of all windows, including the + // child windows, are performed; conceptually ,child windows have no buffers + // (actually they do have a 1x1 placeholder buffer due to libscreen limitations), + // since Qt will only draw to the backing store of the top-level window. QQnxWindow *platformWindow = this->platformWindow(); if (!targetWindow || targetWindow == platformWindow) { @@ -108,28 +113,6 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const // update the display with newly rendered content platformWindow->post(region); - } else if (targetWindow) { - - // The contents of the backing store should be flushed to a different window than the - // window which owns the buffer. - // This typically happens for child windows, since child windows share a backing store with - // their top-level window (TLW). - // Simply copy the buffer over to the child window, to emulate a painting operation, and - // then post the window. - // - // ### Note that because of the design in the QNX QPA plugin, each window has its own buffers, - // even though they might share a backing store. This is unneeded overhead, but I don't think - // libscreen allows to have windows without buffers, or does it? - - // We assume that the TLW has been flushed previously and that no changes were made to the - // backing store inbetween (### does Qt guarantee this?) - - targetWindow->adjustBufferSize(); - targetWindow->blitFrom(platformWindow, offset, region); - targetWindow->post(region); - - } else { - qWarning() << Q_FUNC_INFO << "flush() called without a valid window!"; } m_hasUnflushedPaintOperations = false; diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index 84721c9c2a..7959617443 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -85,7 +85,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { if (val[0] > 0 && val[1] > 0) return QSize(val[0], val[1]); - qWarning("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]); + 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]); const QString envPhySizeStr = qgetenv("QQNX_PHYSICAL_SCREEN_SIZE"); if (!envPhySizeStr.isEmpty()) { @@ -94,7 +96,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { const int envHeight = envPhySizeStrList.size() == 2 ? envPhySizeStrList[1].toInt() : -1; if (envWidth <= 0 || envHeight <= 0) { - qFatal("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format \"width,height\" in mm, with width, height > 0. Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90"); + qFatal("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format " + "\"width,height\" in mm, with width, height > 0. " + "Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90"); return QSize(150, 90); } @@ -103,11 +107,14 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { #if defined(QQNX_PHYSICAL_SCREEN_SIZE_DEFINED) const QSize defSize(QQNX_PHYSICAL_SCREEN_WIDTH, QQNX_PHYSICAL_SCREEN_HEIGHT); - qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. Falling back to defines QQNX_PHYSICAL_SCREEN_WIDTH/QQNX_PHYSICAL_SCREEN_HEIGHT (%dx%d)", defSize.width(), defSize.height()); + qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. Falling back to defines " + "QQNX_PHYSICAL_SCREEN_WIDTH/QQNX_PHYSICAL_SCREEN_HEIGHT (%dx%d)", + defSize.width(), defSize.height()); return defSize; #else if (primaryScreen) - qFatal("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. Could not determine physical screen size."); + qFatal("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. " + "Could not determine physical screen size."); return QSize(150, 90); #endif } @@ -119,7 +126,6 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, m_posted(false), m_keyboardHeight(0), m_nativeOrientation(Qt::PrimaryOrientation), - m_platformContext(0), m_cursor(new QQnxCursor()) { qScreenDebug() << Q_FUNC_INFO; @@ -475,9 +481,14 @@ void QQnxScreen::updateHierarchy() int topZorder; errno = 0; - result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder); - if (result != 0) - qFatal("QQnxScreen: failed to query root window z-order, errno=%d", errno); + if (isPrimaryScreen()) { + result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder); + if (result != 0) + qFatal("QQnxScreen: failed to query root window z-order, errno=%d", errno); + } else { + topZorder = 0; //We do not need z ordering on the secondary screen, because only one window + //is supported there + } topZorder++; // root window has the lowest z-order in the windowgroup diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 6e8c2c6a60..e498d27c14 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -133,7 +133,6 @@ private: Qt::ScreenOrientation m_nativeOrientation; QRect m_initialGeometry; QRect m_currentGeometry; - QPlatformOpenGLContext *m_platformContext; QList<QQnxWindow *> m_childWindows; QList<screen_window_t> m_overlays; diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index c2d0e3e41c..c869d29c99 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -469,8 +469,14 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event) qScreenEventDebug() << Q_FUNC_INFO << "display attachment is now:" << isAttached; QQnxScreen *screen = m_qnxIntegration->screenForNative(nativeDisplay); + if (!screen) { if (isAttached) { + int val[2]; + screen_get_display_property_iv(nativeDisplay, SCREEN_PROPERTY_SIZE, val); + 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"; m_qnxIntegration->createDisplay(nativeDisplay, false /* not primary, we assume */); } diff --git a/src/plugins/platforms/qnx/qqnxtheme.cpp b/src/plugins/platforms/qnx/qqnxtheme.cpp index 733b7223b6..37c1079441 100644 --- a/src/plugins/platforms/qnx/qqnxtheme.cpp +++ b/src/plugins/platforms/qnx/qqnxtheme.cpp @@ -58,10 +58,8 @@ QQnxTheme::~QQnxTheme() bool QQnxTheme::usePlatformNativeDialog(DialogType type) const { -#if defined(Q_OS_BLACKBERRY_TABLET) if (type == QPlatformTheme::FileDialog) return true; -#endif #if !defined(QT_NO_COLORDIALOG) if (type == QPlatformTheme::ColorDialog) return false; @@ -76,10 +74,8 @@ bool QQnxTheme::usePlatformNativeDialog(DialogType type) const QPlatformDialogHelper *QQnxTheme::createPlatformDialogHelper(DialogType type) const { switch (type) { -#if defined(Q_OS_BLACKBERRY_TABLET) case QPlatformTheme::FileDialog: return new QQnxFileDialogHelper(m_integration); -#endif #if !defined(QT_NO_COLORDIALOG) case QPlatformTheme::ColorDialog: #endif diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 5aa1c970fd..45e565f24f 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -72,13 +72,15 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) m_window(0), m_currentBufferIndex(-1), m_previousBufferIndex(-1), -#if !defined(QT_NO_OPENGL) - m_platformOpenGLContext(0), -#endif m_screen(0), m_parentWindow(0), m_visible(false), m_windowState(Qt::WindowNoState), +#if !defined(QT_NO_OPENGL) + m_platformOpenGLContext(0), + m_newSurfaceRequested(true), + m_eglSurface(EGL_NO_SURFACE), +#endif m_requestedBufferSize(window->geometry().size()) { qWindowDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size(); @@ -86,7 +88,11 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) // Create child QNX window errno = 0; - result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + if (static_cast<QQnxScreen *>(window->screen()->handle())->isPrimaryScreen()) { + result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + } else { + result = screen_create_window(&m_window, m_screenContext); + } if (result != 0) qFatal("QQnxWindow: failed to create window, errno=%d", errno); @@ -172,6 +178,11 @@ QQnxWindow::~QQnxWindow() // Cleanup QNX window and its buffers screen_destroy_window(m_window); + +#if !defined(QT_NO_OPENGL) + // Cleanup EGL surface if it exists + destroyEGLSurface(); +#endif } void QQnxWindow::setGeometry(const QRect &rect) @@ -180,16 +191,16 @@ void QQnxWindow::setGeometry(const QRect &rect) #if !defined(QT_NO_OPENGL) // If this is an OpenGL window we need to request that the GL context updates - // the EGLsurface on which it is rendering. The surface will be recreated the - // next time QQnxGLContext::makeCurrent() is called. + // the EGLsurface on which it is rendering. { // We want the setting of the atomic bool in the GL context to be atomic with // setting m_requestedBufferSize and therefore extended the scope to include // that test. const QMutexLocker locker(&m_mutex); m_requestedBufferSize = rect.size(); - if (m_platformOpenGLContext != 0 && bufferSize() != rect.size()) - m_platformOpenGLContext->requestSurfaceChange(); + if (m_platformOpenGLContext != 0 && bufferSize() != rect.size()) { + m_newSurfaceRequested.testAndSetRelease(false, true); + } } #endif @@ -336,6 +347,9 @@ QSize QQnxWindow::requestedBufferSize() const void QQnxWindow::adjustBufferSize() { + if (m_parentWindow) + return; + const QSize windowSize = window()->size(); if (windowSize != bufferSize()) setBufferSize(windowSize); @@ -514,8 +528,12 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) if (m_screen == platformScreen) return; - if (m_screen) + if (m_screen) { + qWindowDebug() << Q_FUNC_INFO << "Moving window to different screen"; m_screen->removeWindow(this); + screen_leave_window_group(m_window); + } + platformScreen->addWindow(this); m_screen = platformScreen; @@ -526,17 +544,20 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) if (result != 0) qFatal("QQnxWindow: failed to set window display, errno=%d", errno); - // Add window to display's window group - errno = 0; - result = screen_join_window_group(m_window, platformScreen->windowGroupName()); - if (result != 0) - qFatal("QQnxWindow: failed to join window group, errno=%d", errno); - Q_FOREACH (QQnxWindow *childWindow, m_childWindows) { - // Only subwindows and tooltips need necessarily be moved to another display with the window. - if ((window()->type() & Qt::WindowType_Mask) == Qt::SubWindow || - (window()->type() & Qt::WindowType_Mask) == Qt::ToolTip) - childWindow->setScreen(platformScreen); + if (m_screen->isPrimaryScreen()) { + // Add window to display's window group + errno = 0; + result = screen_join_window_group(m_window, platformScreen->windowGroupName()); + if (result != 0) + qFatal("QQnxWindow: failed to join window group, errno=%d", errno); + + Q_FOREACH (QQnxWindow *childWindow, m_childWindows) { + // Only subwindows and tooltips need necessarily be moved to another display with the window. + if ((window()->type() & Qt::WindowType_Mask) == Qt::SubWindow || + (window()->type() & Qt::WindowType_Mask) == Qt::ToolTip) + childWindow->setScreen(platformScreen); + } } m_screen->updateHierarchy(); @@ -574,8 +595,18 @@ void QQnxWindow::setParent(const QPlatformWindow *window) setScreen(m_parentWindow->m_screen); m_parentWindow->m_childWindows.push_back(this); + + // we don't need any buffers, since + // Qt will draw to the parent TLW + // backing store. + setBufferSize(QSize(1, 1)); } else { m_screen->addWindow(this); + + // recreate buffers, in case the + // window has been reparented and + // becomes a TLW + adjustBufferSize(); } m_screen->updateHierarchy(); @@ -634,6 +665,12 @@ void QQnxWindow::setWindowState(Qt::WindowState state) applyWindowState(); } +void QQnxWindow::propagateSizeHints() +{ + // nothing to do; silence base class warning + qWindowDebug() << Q_FUNC_INFO << ": ignored"; +} + void QQnxWindow::gainedFocus() { qWindowDebug() << Q_FUNC_INFO << "window =" << window(); @@ -699,6 +736,79 @@ void QQnxWindow::minimize() #endif } +#if !defined(QT_NO_OPENGL) +void QQnxWindow::createEGLSurface() +{ + // Fetch the surface size from the window and update + // the window's buffers before we create the EGL surface + const QSize surfaceSize = requestedBufferSize(); + if (!surfaceSize.isValid()) { + qFatal("QQNX: Trying to create 0 size EGL surface. " + "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); + } + setBufferSize(surfaceSize); + + // Post root window, in case it hasn't been posted yet, to make it appear. + screen()->onWindowPost(0); + + const EGLint eglSurfaceAttrs[] = + { + EGL_RENDER_BUFFER, EGL_BACK_BUFFER, + EGL_NONE + }; + + qWindowDebug() << "Creating EGL surface" << platformOpenGLContext()->getEglDisplay() + << platformOpenGLContext()->getEglConfig(); + // Create EGL surface + m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay() + , platformOpenGLContext()->getEglConfig(), + (EGLNativeWindowType) m_window, eglSurfaceAttrs); + if (m_eglSurface == EGL_NO_SURFACE) { + QQnxGLContext::checkEGLError("eglCreateWindowSurface"); + qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); + } +} + +void QQnxWindow::destroyEGLSurface() +{ + // Destroy EGL surface if it exists + if (m_eglSurface != EGL_NO_SURFACE) { + EGLBoolean eglResult = eglDestroySurface(platformOpenGLContext()->getEglDisplay(), m_eglSurface); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); + } + + m_eglSurface = EGL_NO_SURFACE; +} + +void QQnxWindow::swapEGLBuffers() +{ + qWindowDebug() << Q_FUNC_INFO; + // Set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); + + // Post EGL surface to window + eglResult = eglSwapBuffers(m_platformOpenGLContext->getEglDisplay(), m_eglSurface); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); +} + +EGLSurface QQnxWindow::getSurface() +{ + if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { + if (m_eglSurface != EGL_NO_SURFACE) { + platformOpenGLContext()->doneCurrent(); + destroyEGLSurface(); + } + createEGLSurface(); + } + + return m_eglSurface; +} +#endif + void QQnxWindow::updateZorder(int &topZorder) { errno = 0; diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index 63d5dc0979..4fabccf4cb 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -103,6 +103,8 @@ public: void requestActivateWindow(); void setWindowState(Qt::WindowState state); + void propagateSizeHints(); + void gainedFocus(); QQnxScreen *screen() const { return m_screen; } @@ -118,6 +120,13 @@ public: void blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset, const QRegion &targetRegion); void minimize(); +#if !defined(QT_NO_OPENGL) + void createEGLSurface(); + void destroyEGLSurface(); + void swapEGLBuffers(); + EGLSurface getSurface(); +#endif + private: QRect setGeometryHelper(const QRect &rect); void removeFromParent(); @@ -145,9 +154,6 @@ private: QRegion m_previousDirty; QRegion m_scrolled; -#if !defined(QT_NO_OPENGL) - QQnxGLContext *m_platformOpenGLContext; -#endif QQnxScreen *m_screen; QList<QQnxWindow*> m_childWindows; QQnxWindow *m_parentWindow; @@ -162,6 +168,13 @@ private: // EGL surface. All of this has to be done from the thread that is calling // QQnxGLContext::makeCurrent() mutable QMutex m_mutex; + +#if !defined(QT_NO_OPENGL) + QQnxGLContext *m_platformOpenGLContext; + QAtomicInt m_newSurfaceRequested; + EGLSurface m_eglSurface; +#endif + QSize m_requestedBufferSize; }; diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index e5c3269a6c..ffd87af193 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -105,12 +105,12 @@ QT_BEGIN_NAMESPACE class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "windows.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "windows.json") public: - QPlatformIntegration *create(const QString&, const QStringList&); + QPlatformIntegration *create(const QString&, const QStringList&, int &, char **); }; -QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList) +QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList, int &, char **) { if (system.compare(system, QStringLiteral("windows"), Qt::CaseInsensitive) == 0) return new QWindowsIntegration(paramList); diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index ae48887a80..dcd3db2d47 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -83,6 +83,7 @@ enum WindowsEventType // Simplify event types CalculateSize = WindowEventFlag + 16, FocusInEvent = WindowEventFlag + 17, FocusOutEvent = WindowEventFlag + 18, + WhatsThisEvent = WindowEventFlag + 19, MouseEvent = MouseEventFlag + 1, MouseWheelEvent = MouseEventFlag + 2, CursorEvent = MouseEventFlag + 3, @@ -199,6 +200,12 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI case WM_CONTEXTMENU: return QtWindows::ContextMenu; #endif + case WM_SYSCOMMAND: +#ifndef Q_OS_WINCE + if ((wParamIn & 0xfff0) == SC_CONTEXTHELP) + return QtWindows::WhatsThisEvent; +#endif + break; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 37a51e1fec..de0a583e58 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -47,6 +47,7 @@ #include "qtwindowsglobal.h" #include "qwindowsmime.h" #include "qwindowsinputcontext.h" +#include "qwindowstabletsupport.h" #ifndef QT_NO_ACCESSIBILITY #include "accessible/qwindowsaccessibility.h" #endif @@ -83,6 +84,7 @@ int QWindowsContext::verboseOLE = 0; int QWindowsContext::verboseInputMethods = 0; int QWindowsContext::verboseDialogs = 0; int QWindowsContext::verboseTheming = 0; +int QWindowsContext::verboseTablet = 0; // Get verbosity of components from "foo:2,bar:3" static inline int componentVerbose(const char *v, const char *keyWord) @@ -259,17 +261,20 @@ struct QWindowsContextPrivate { QWindowsMimeConverter m_mimeConverter; QWindowsScreenManager m_screenManager; QSharedPointer<QWindowCreationContext> m_creationContext; +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + QScopedPointer<QWindowsTabletSupport> m_tabletSupport; +#endif const HRESULT m_oleInitializeResult; const QByteArray m_eventType; QWindow *m_lastActiveWindow; bool m_asyncExpose; }; -QWindowsContextPrivate::QWindowsContextPrivate() : - m_systemInfo(0), - m_oleInitializeResult(OleInitialize(NULL)), - m_eventType(QByteArrayLiteral("windows_generic_MSG")), - m_lastActiveWindow(0), m_asyncExpose(0) +QWindowsContextPrivate::QWindowsContextPrivate() + : m_systemInfo(0) + , m_oleInitializeResult(OleInitialize(NULL)) + , m_eventType(QByteArrayLiteral("windows_generic_MSG")) + , m_lastActiveWindow(0), m_asyncExpose(0) { const QSysInfo::WinVersion ver = QSysInfo::windowsVersion(); #ifndef Q_OS_WINCE @@ -310,7 +315,13 @@ QWindowsContext::QWindowsContext() : QWindowsContext::verboseInputMethods = componentVerbose(v, "im"); QWindowsContext::verboseDialogs = componentVerbose(v, "dialogs"); QWindowsContext::verboseTheming = componentVerbose(v, "theming"); + QWindowsContext::verboseTablet = componentVerbose(v, "tablet"); } +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + d->m_tabletSupport.reset(QWindowsTabletSupport::create()); + if (QWindowsContext::verboseTablet) + qDebug() << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description()); +#endif } QWindowsContext::~QWindowsContext() @@ -631,6 +642,15 @@ QWindowsScreenManager &QWindowsContext::screenManager() return d->m_screenManager; } +QWindowsTabletSupport *QWindowsContext::tabletSupport() const +{ +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + return d->m_tabletSupport.data(); +#else + return 0; +#endif +} + /*! \brief Convenience to create a non-visible, message-only dummy window for example used as clipboard watcher or for GL. @@ -864,6 +884,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, } #ifndef Q_OS_WINCE case QtWindows::ActivateWindowEvent: +#ifndef QT_NO_TABLETEVENT + if (!d->m_tabletSupport.isNull()) + d->m_tabletSupport->notifyActivate(); +#endif // !QT_NO_TABLETEVENT if (platformWindow->testFlag(QWindowsWindow::BlockedByModal)) if (const QWindow *modalWindow = QGuiApplication::modalWindow()) QWindowsWindow::baseWindowOf(modalWindow)->alertWindow(); @@ -873,6 +897,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::ContextMenu: return handleContextMenuEvent(platformWindow->window(), msg); #endif + case QtWindows::WhatsThisEvent: { +#ifndef QT_NO_WHATSTHIS + QWindowSystemInterface::handleEnterWhatsThisEvent(); + return true; +#endif + } break; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 6b80075379..0d3476e00f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE class QWindow; class QPlatformScreen; class QWindowsScreenManager; +class QWindowsTabletSupport; class QWindowsWindow; class QWindowsMimeConverter; struct QWindowCreationContext; @@ -135,6 +136,7 @@ public: static int verboseInputMethods; static int verboseDialogs; static int verboseTheming; + static int verboseTablet; explicit QWindowsContext(); ~QWindowsContext(); @@ -185,6 +187,7 @@ public: QWindowsMimeConverter &mimeConverter() const; QWindowsScreenManager &screenManager(); + QWindowsTabletSupport *tabletSupport() const; #ifndef Q_OS_WINCE static QWindowsUser32DLL user32dll; static QWindowsShell32DLL shell32dll; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 27a7044868..354f6700b3 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#define QT_NO_URL_CAST_FROM_STRING 1 + #include "qwindowsdialoghelpers.h" #include "qwindowscontext.h" @@ -651,34 +653,34 @@ public: QWindowsFileDialogSharedData() : m_data(new Data) {} void fromOptions(const QSharedPointer<QFileDialogOptions> &o); - QString directory() const; - void setDirectory(const QString &); + QUrl directory() const; + void setDirectory(const QUrl &); QString selectedNameFilter() const; void setSelectedNameFilter(const QString &); - QStringList selectedFiles() const; - void setSelectedFiles(const QStringList &); + QList<QUrl> selectedFiles() const; + void setSelectedFiles(const QList<QUrl> &); QString selectedFile() const; private: class Data : public QSharedData { public: - QString directory; + QUrl directory; QString selectedNameFilter; - QStringList selectedFiles; + QList<QUrl> selectedFiles; QMutex mutex; }; QExplicitlySharedDataPointer<Data> m_data; }; -inline QString QWindowsFileDialogSharedData::directory() const +inline QUrl QWindowsFileDialogSharedData::directory() const { m_data->mutex.lock(); - const QString result = m_data->directory; + const QUrl result = m_data->directory; m_data->mutex.unlock(); return result; } -inline void QWindowsFileDialogSharedData::setDirectory(const QString &d) +inline void QWindowsFileDialogSharedData::setDirectory(const QUrl &d) { QMutexLocker (&m_data->mutex); m_data->directory = d; @@ -698,24 +700,24 @@ inline void QWindowsFileDialogSharedData::setSelectedNameFilter(const QString &f m_data->selectedNameFilter = f; } -inline QStringList QWindowsFileDialogSharedData::selectedFiles() const +inline QList<QUrl> QWindowsFileDialogSharedData::selectedFiles() const { m_data->mutex.lock(); - const QStringList result = m_data->selectedFiles; + const QList<QUrl> result = m_data->selectedFiles; m_data->mutex.unlock(); return result; } inline QString QWindowsFileDialogSharedData::selectedFile() const { - const QStringList files = selectedFiles(); - return files.isEmpty() ? QString() : files.front(); + const QList<QUrl> files = selectedFiles(); + return files.isEmpty() ? QString() : files.front().toLocalFile(); } -inline void QWindowsFileDialogSharedData::setSelectedFiles(const QStringList &f) +inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList<QUrl> &urls) { QMutexLocker (&m_data->mutex); - m_data->selectedFiles = f; + m_data->selectedFiles = urls; } inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFileDialogOptions> &o) @@ -822,7 +824,7 @@ public: virtual void setWindowTitle(const QString &title); inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::FileDialogOptions options); inline void setDirectory(const QString &directory); - inline void updateDirectory() { setDirectory(m_data.directory()); } + inline void updateDirectory() { setDirectory(m_data.directory().toLocalFile()); } inline QString directory() const; virtual void exec(HWND owner = 0); virtual void setNameFilters(const QStringList &f); @@ -837,10 +839,10 @@ public: inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text); // Return the selected files for tracking in OnSelectionChanged(). - virtual QStringList selectedFiles() const = 0; + virtual QList<QUrl> selectedFiles() const = 0; // Return the result for tracking in OnFileOk(). Differs from selection for // example by appended default suffixes, etc. - virtual QStringList dialogResult() const = 0; + virtual QList<QUrl> dialogResult() const = 0; inline void onFolderChange(IShellItem *); inline void onSelectionChange(); @@ -848,8 +850,8 @@ public: inline bool onFileOk(); signals: - void directoryEntered(const QString& directory); - void currentChanged(const QString& file); + void directoryEntered(const QUrl &directory); + void currentChanged(const QUrl &file); void filterSelected(const QString & filter); public slots: @@ -861,9 +863,9 @@ protected: void setDefaultSuffixSys(const QString &s); inline IFileDialog * fileDialog() const { return m_fileDialog; } static QString itemPath(IShellItem *item); - static QStringList libraryItemFolders(IShellItem *item); + static QList<QUrl> libraryItemFolders(IShellItem *item); static QString libraryItemDefaultSaveFolder(IShellItem *item); - static int itemPaths(IShellItemArray *items, QStringList *fileResult = 0); + static int itemPaths(IShellItemArray *items, QList<QUrl> *fileResult = 0); static IShellItem *shellItem(const QString &path); const QWindowsFileDialogSharedData &data() const { return m_data; } @@ -1031,9 +1033,9 @@ static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) } // Return all folders of a library-type item. -QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) +QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) { - QStringList result; + QList<QUrl> result; if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { IShellItemArray *itemArray = 0; if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) { @@ -1062,9 +1064,9 @@ QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *i #else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__ -QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) +QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) { - return QStringList(); + return QList<QUrl>(); } QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *) @@ -1096,7 +1098,7 @@ QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item) } int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, - QStringList *result /* = 0 */) + QList<QUrl> *result /* = 0 */) { DWORD itemCount = 0; if (result) @@ -1108,7 +1110,7 @@ int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, for (DWORD i = 0; i < itemCount; ++i) { IShellItem *item = 0; if (SUCCEEDED(items->GetItemAt(i, &item))) - result->push_back(QWindowsNativeFileDialogBase::itemPath(item)); + result->push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); } } return itemCount; @@ -1270,7 +1272,7 @@ QString QWindowsNativeFileDialogBase::selectedNameFilter() const void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) { if (item) { - const QString directory = QWindowsNativeFileDialogBase::itemPath(item); + const QUrl directory = QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item)); m_data.setDirectory(directory); emit directoryEntered(directory); } @@ -1278,7 +1280,7 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) void QWindowsNativeFileDialogBase::onSelectionChange() { - const QStringList current = selectedFiles(); + const QList<QUrl> current = selectedFiles(); m_data.setSelectedFiles(current); if (current.size() == 1) emit currentChanged(current.front()); @@ -1338,8 +1340,8 @@ public: explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} virtual void setNameFilters(const QStringList &f); - virtual QStringList selectedFiles() const; - virtual QStringList dialogResult() const; + virtual QList<QUrl> selectedFiles() const; + virtual QList<QUrl> dialogResult() const; }; // Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". @@ -1374,22 +1376,22 @@ void QWindowsNativeSaveFileDialog::setNameFilters(const QStringList &f) } // m_hasDefaultSuffix } -QStringList QWindowsNativeSaveFileDialog::dialogResult() const +QList<QUrl> QWindowsNativeSaveFileDialog::dialogResult() const { - QStringList result; + QList<QUrl> result; IShellItem *item = 0; if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) - result.push_back(QWindowsNativeFileDialogBase::itemPath(item)); + result.push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); return result; } -QStringList QWindowsNativeSaveFileDialog::selectedFiles() const +QList<QUrl> QWindowsNativeSaveFileDialog::selectedFiles() const { - QStringList result; + QList<QUrl> result; IShellItem *item = 0; const HRESULT hr = fileDialog()->GetCurrentSelection(&item); if (SUCCEEDED(hr) && item) - result.push_back(QWindowsNativeSaveFileDialog::itemPath(item)); + result.push_back(QUrl::fromLocalFile(QWindowsNativeSaveFileDialog::itemPath(item))); return result; } @@ -1408,26 +1410,26 @@ class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase public: explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} - virtual QStringList selectedFiles() const; - virtual QStringList dialogResult() const; + virtual QList<QUrl> selectedFiles() const; + virtual QList<QUrl> dialogResult() const; private: inline IFileOpenDialog *openFileDialog() const { return static_cast<IFileOpenDialog *>(fileDialog()); } }; -QStringList QWindowsNativeOpenFileDialog::dialogResult() const +QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const { - QStringList result; + QList<QUrl> result; IShellItemArray *items = 0; if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) QWindowsNativeFileDialogBase::itemPaths(items, &result); return result; } -QStringList QWindowsNativeOpenFileDialog::selectedFiles() const +QList<QUrl> QWindowsNativeOpenFileDialog::selectedFiles() const { - QStringList result; + QList<QUrl> result; IShellItemArray *items = 0; const HRESULT hr = openFileDialog()->GetSelectedItems(&items); if (SUCCEEDED(hr) && items) @@ -1484,14 +1486,13 @@ public: virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } - virtual void setDirectory(const QString &directory); - virtual QString directory() const; - virtual void selectFile(const QString &filename); - virtual QStringList selectedFiles() const; - virtual void setFilter(); - virtual void setNameFilters(const QStringList &filters); - virtual void selectNameFilter(const QString &filter); - virtual QString selectedNameFilter() const; + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE; + virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; private: virtual QWindowsNativeDialogBase *createNativeDialog(); @@ -1509,10 +1510,10 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() return 0; QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept())); QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject())); - QObject::connect(result, SIGNAL(directoryEntered(QString)), - this, SIGNAL(directoryEntered(QString))); - QObject::connect(result, SIGNAL(currentChanged(QString)), - this, SIGNAL(currentChanged(QString))); + QObject::connect(result, SIGNAL(directoryEntered(QUrl)), + this, SIGNAL(directoryEntered(QUrl))); + QObject::connect(result, SIGNAL(currentChanged(QUrl)), + this, SIGNAL(currentChanged(QUrl))); QObject::connect(result, SIGNAL(filterSelected(QString)), this, SIGNAL(filterSelected(QString))); @@ -1532,11 +1533,16 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept)); result->updateDirectory(); result->updateSelectedNameFilter(); - const QStringList initialSelection = opts->initiallySelectedFiles(); + const QList<QUrl> initialSelection = opts->initiallySelectedFiles(); if (initialSelection.size() > 0) { - QFileInfo info(initialSelection.front()); - if (!info.isDir()) - result->selectFile(info.fileName()); + const QUrl url = initialSelection.front(); + if (url.isLocalFile()) { + QFileInfo info(url.toLocalFile()); + if (!info.isDir()) + result->selectFile(info.fileName()); + } else { + result->selectFile(url.path()); // TODO url.fileName() once it exists + } } // No need to select initialNameFilter if mode is Dir if (mode != QFileDialogOptions::Directory && mode != QFileDialogOptions::DirectoryOnly) { @@ -1550,31 +1556,31 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() return result; } -void QWindowsFileDialogHelper::setDirectory(const QString &directory) +void QWindowsFileDialogHelper::setDirectory(const QUrl &directory) { if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(directory)); + qDebug("%s %s" , __FUNCTION__, qPrintable(directory.toString())); m_data.setDirectory(directory); if (hasNativeDialog()) nativeFileDialog()->updateDirectory(); } -QString QWindowsFileDialogHelper::directory() const +QUrl QWindowsFileDialogHelper::directory() const { return m_data.directory(); } -void QWindowsFileDialogHelper::selectFile(const QString &fileName) +void QWindowsFileDialogHelper::selectFile(const QUrl &fileName) { if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(fileName)); + qDebug("%s %s" , __FUNCTION__, qPrintable(fileName.toString())); if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->selectFile(fileName); + nfd->selectFile(fileName.toLocalFile()); // ## should use QUrl::fileName() once it exists } -QStringList QWindowsFileDialogHelper::selectedFiles() const +QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const { return m_data.selectedFiles(); } @@ -1585,14 +1591,6 @@ void QWindowsFileDialogHelper::setFilter() qDebug("%s" , __FUNCTION__); } -void QWindowsFileDialogHelper::setNameFilters(const QStringList &filters) -{ - if (QWindowsContext::verboseDialogs) - qDebug("%s" , __FUNCTION__); - if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->setNameFilters(filters); -} - void QWindowsFileDialogHelper::selectNameFilter(const QString &filter) { m_data.setSelectedNameFilter(filter); @@ -1643,8 +1641,8 @@ private: explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const; - QStringList execExistingDir(HWND owner); - QStringList execFileNames(HWND owner, int *selectedFilterIndex) const; + QList<QUrl> execExistingDir(HWND owner); + QList<QUrl> execFileNames(HWND owner, int *selectedFilterIndex) const; const OptionsPtr m_options; QString m_title; @@ -1683,7 +1681,7 @@ QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options void QWindowsXpNativeFileDialog::exec(HWND owner) { int selectedFilterIndex = -1; - const QStringList selectedFiles = + const QList<QUrl> selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ? execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex); m_data.setSelectedFiles(selectedFiles); @@ -1695,7 +1693,8 @@ void QWindowsXpNativeFileDialog::exec(HWND owner) const QStringList nameFilters = m_options->nameFilters(); if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size()) m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex)); - m_data.setDirectory(QFileInfo(selectedFiles.front()).absolutePath()); + QUrl firstFile = selectedFiles.front(); + m_data.setDirectory(firstFile.adjusted(QUrl::RemoveFilename)); m_result = QPlatformDialogHelper::Accepted; emit accepted(); } @@ -1722,7 +1721,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM case BFFM_INITIALIZED: { if (!m_title.isEmpty()) SetWindowText(hwnd, (wchar_t *)m_title.utf16()); - const QString initialFile = QDir::toNativeSeparators(m_data.directory()); + const QString initialFile = QDir::toNativeSeparators(m_data.directory().toLocalFile()); if (!initialFile.isEmpty()) SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16())); } @@ -1738,7 +1737,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM return 0; } -QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) +QList<QUrl> QWindowsXpNativeFileDialog::execExistingDir(HWND owner) { BROWSEINFO bi; wchar_t initPath[MAX_PATH]; @@ -1750,12 +1749,12 @@ QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE; bi.lpfn = xpFileDialogGetExistingDirCallbackProc; bi.lParam = LPARAM(this); - QStringList selectedFiles; + QList<QUrl> selectedFiles; if (qt_LpItemIdList pItemIDList = SHBrowseForFolder(&bi)) { wchar_t path[MAX_PATH]; path[0] = 0; if (SHGetPathFromIDList(pItemIDList, path) && path[0]) - selectedFiles.push_back(QDir::cleanPath(QString::fromWCharArray(path))); + selectedFiles.push_back(QUrl::fromLocalFile(QDir::cleanPath(QString::fromWCharArray(path)))); IMalloc *pMalloc; if (SHGetMalloc(&pMalloc) == NOERROR) { pMalloc->Free(pItemIDList); @@ -1807,7 +1806,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')). remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|')); ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile); - ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory())); + ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory().toLocalFile())); ofn->lpstrTitle = (wchar_t*)m_title.utf16(); // Determine lpstrDefExt. Note that the current MSDN docs document this // member wrong. It should rather be documented as "the default extension @@ -1832,25 +1831,27 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow ofn->Flags |= OFN_OVERWRITEPROMPT; } -QStringList QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const +QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const { *selectedFilterIndex = -1; OPENFILENAME ofn; populateOpenFileName(&ofn, owner); - QStringList result; + QList<QUrl> result; const bool isSave = m_options->acceptMode() == QFileDialogOptions::AcceptSave; if (isSave ? m_getSaveFileNameW(&ofn) : m_getOpenFileNameW(&ofn)) { *selectedFilterIndex = ofn.nFilterIndex - 1; - result.push_back(QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile))); + const QString dir = QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile)); + result.push_back(QUrl::fromLocalFile(dir)); // For multiselection, the first item is the path followed // by "\0<file1>\0<file2>\0\0". if (ofn.Flags & (OFN_ALLOWMULTISELECT)) { - wchar_t *ptr = ofn.lpstrFile + result.front().size() + 1; + wchar_t *ptr = ofn.lpstrFile + dir.size() + 1; if (*ptr) { - const QString path = result.takeAt(0) + QLatin1Char('/'); + result.pop_front(); + const QString path = dir + QLatin1Char('/'); while (*ptr) { const QString fileName = QString::fromWCharArray(ptr); - result.push_back(path + fileName); + result.push_back(QUrl::fromLocalFile(path + fileName)); ptr += fileName.size() + 1; } // extract multiple files } // has multiple files @@ -1879,14 +1880,13 @@ public: virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } - virtual void setDirectory(const QString &directory); - virtual QString directory() const; - virtual void selectFile(const QString &filename); - virtual QStringList selectedFiles() const; - virtual void setFilter() {} - virtual void setNameFilters(const QStringList &); - virtual void selectNameFilter(const QString &); - virtual QString selectedNameFilter() const; + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &url) Q_DECL_OVERRIDE; + virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE {} + virtual void selectNameFilter(const QString &) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; private: virtual QWindowsNativeDialogBase *createNativeDialog(); @@ -1907,31 +1907,26 @@ QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog() return 0; } -void QWindowsXpFileDialogHelper::setDirectory(const QString &directory) +void QWindowsXpFileDialogHelper::setDirectory(const QUrl &directory) { m_data.setDirectory(directory); // Dialog cannot be updated at run-time. } -QString QWindowsXpFileDialogHelper::directory() const +QUrl QWindowsXpFileDialogHelper::directory() const { return m_data.directory(); } -void QWindowsXpFileDialogHelper::selectFile(const QString &filename) +void QWindowsXpFileDialogHelper::selectFile(const QUrl &url) { - m_data.setSelectedFiles(QStringList(filename)); // Dialog cannot be updated at run-time. + m_data.setSelectedFiles(QList<QUrl>() << url); // Dialog cannot be updated at run-time. } -QStringList QWindowsXpFileDialogHelper::selectedFiles() const +QList<QUrl> QWindowsXpFileDialogHelper::selectedFiles() const { return m_data.selectedFiles(); } -void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &) -{ - // Dialog cannot be updated at run-time. -} - void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f) { m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time. diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index b7ccb5767e..a6bce6502b 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -838,8 +838,6 @@ error: return i18n_name; } -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); - static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, @@ -932,7 +930,7 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0); if (!englishName.isEmpty()) - qt_registerAliasToFontFamily(familyName, englishName); + QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); return true; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 7f97d58be4..6037c201ac 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -122,8 +122,6 @@ static FontFile * createFontFile(const QString &fileName, int index) extern bool localizedName(const QString &name); extern QString getEnglishName(const QString &familyName); -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); - static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, @@ -304,7 +302,7 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); if (!englishName.isEmpty()) - qt_registerAliasToFontFamily(faceName, englishName); + QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); return true; } diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index c0f1b3a000..7407d88f8b 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -215,7 +215,9 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di if (QWindowsContext::verboseFonts) qDebug("%s %g", __FUNCTION__, pixelSize); - d->directWriteFactory->AddRef(); + Q_ASSERT(m_directWriteFontFace); + + m_fontEngineData->directWriteFactory->AddRef(); m_directWriteFontFace->AddRef(); fontDef.pixelSize = pixelSize; @@ -237,19 +239,17 @@ QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() void QWindowsFontEngineDirectWrite::collectMetrics() { - if (m_directWriteFontFace != 0) { - DWRITE_FONT_METRICS metrics; - - m_directWriteFontFace->GetMetrics(&metrics); - m_unitsPerEm = metrics.designUnitsPerEm; - - m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); - m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); - m_descent = DESIGN_TO_LOGICAL(metrics.descent); - m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); - m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); - m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); - } + DWRITE_FONT_METRICS metrics; + + m_directWriteFontFace->GetMetrics(&metrics); + m_unitsPerEm = metrics.designUnitsPerEm; + + m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); + m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); + m_descent = DESIGN_TO_LOGICAL(metrics.descent); + m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); + m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); + m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); } QFixed QWindowsFontEngineDirectWrite::underlinePosition() const @@ -272,31 +272,24 @@ bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, ui { bool ret = false; - if (m_directWriteFontFace) { - DWORD t = qbswap<quint32>(tag); - - const void *tableData = 0; - void *tableContext = 0; - UINT32 tableSize; - BOOL exists; - HRESULT hr = m_directWriteFontFace->TryGetFontTable( - t, &tableData, &tableSize, &tableContext, &exists - ); - - if (SUCCEEDED(hr)) { - if (exists) { - if (!buffer) { - *length = tableSize; - ret = true; - } else if (*length >= tableSize) { - memcpy(buffer, tableData, tableSize); - ret = true; - } - } - m_directWriteFontFace->ReleaseFontTable(tableContext); - } else { - qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); + const void *tableData = 0; + UINT32 tableSize; + void *tableContext = 0; + BOOL exists; + HRESULT hr = m_directWriteFontFace->TryGetFontTable(qbswap<quint32>(tag) + &tableData, &tableSize, + &tableContext, &exists); + if (SUCCEEDED(hr)) { + if (exists) { + ret = true; + if (buffer && *length >= tableSize) + memcpy(buffer, tableData, tableSize); + else + *length = tableSize; } + m_directWriteFontFace->ReleaseFontTable(tableContext); + } else { + qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); } return ret; @@ -327,43 +320,43 @@ inline unsigned int getChar(const QChar *str, int &i, const int len) bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { - if (m_directWriteFontFace != 0) { - QVarLengthArray<UINT32> codePoints(len); - for (int i=0; i<len; ++i) { - codePoints[i] = getChar(str, i, len); - if (flags & QFontEngine::RightToLeft) - codePoints[i] = QChar::mirroredChar(codePoints[i]); - } + if (*nglyphs < len) { + *nglyphs = len; + return false; + } - QVarLengthArray<UINT16> glyphIndices(len); - HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), - len, - glyphIndices.data()); + QVarLengthArray<UINT32> codePoints(len); + int actualLength = 0; + if (flags & QFontEngine::RightToLeft) { + for (int i = 0; i < len; ++i) + codePoints[actualLength++] = QChar::mirroredChar(getChar(str, i, len)); + } else { + for (int i = 0; i < len; ++i) + codePoints[actualLength++] = getChar(str, i, len); + } - if (SUCCEEDED(hr)) { - for (int i=0; i<len; ++i) - glyphs->glyphs[i] = glyphIndices[i]; + QVarLengthArray<UINT16> glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); + return false; + } - *nglyphs = len; - glyphs->numGlyphs = len; + for (int i = 0; i < actualLength; ++i) + glyphs->glyphs[i] = glyphIndices.at(i); - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, 0); + *nglyphs = actualLength; + glyphs->numGlyphs = actualLength; - return true; - } else { - qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); - } - } + if (!(flags & GlyphIndicesOnly)) + recalcAdvances(glyphs, 0); - return false; + return true; } void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const { - if (m_directWriteFontFace == 0) - return; - QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs); // ### Caching? @@ -391,9 +384,6 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags) { - if (m_directWriteFontFace == 0) - return; - QVarLengthArray<UINT16> glyphIndices(nglyphs); QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs); QVarLengthArray<FLOAT> glyphAdvances(nglyphs); @@ -439,9 +429,6 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &g glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) { - if (m_directWriteFontFace == 0) - return glyph_metrics_t(); - UINT16 glyphIndex = g; DWRITE_GLYPH_METRICS glyphMetrics; @@ -668,14 +655,14 @@ bool QWindowsFontEngineDirectWrite::canRender(const QChar *string, int len) if (FAILED(hr)) { qErrnoWarning("%s: GetGlyphIndices failed", __FUNCTION__); return false; - } else { - for (int i=0; i<glyphIndices.size(); ++i) { - if (glyphIndices.at(i) == 0) - return false; - } + } - return true; + for (int i = 0; i < actualLength; ++i) { + if (glyphIndices.at(i) == 0) + return false; } + + return true; } QFontEngine::Type QWindowsFontEngineDirectWrite::type() const diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 106087f757..ab14cb49eb 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -107,8 +107,6 @@ public: static QString fontNameSubstitute(const QString &familyName); private: - friend class QRawFontPrivate; - QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); void collectMetrics(); diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp new file mode 100644 index 0000000000..4a5d7b5a78 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -0,0 +1,473 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowstabletsupport.h" + +#ifndef QT_NO_TABLETEVENT + +#include "qwindowscontext.h" +#include "qwindowskeymapper.h" +#include "qwindowswindow.h" + +#include <qpa/qwindowsysteminterface.h> + +#include <QtGui/QTabletEvent> +#include <QtGui/QScreen> +#include <QtGui/QGuiApplication> +#include <QtGui/QWindow> +#include <QtCore/QDebug> +#include <QtCore/QScopedArrayPointer> +#include <QtCore/QtMath> + +#include <private/qguiapplication_p.h> +#include <QtCore/private/qsystemlibrary_p.h> + +// Note: The definition of the PACKET structure in pktdef.h depends on this define. +#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z) +#include <pktdef.h> + +QT_BEGIN_NAMESPACE + +enum { + PacketMode = 0, + TabletPacketQSize = 128, + DeviceIdMask = 0xFF6, // device type mask && device color mask + CursorTypeBitMask = 0x0F06 // bitmask to find the specific cursor type (see Wacom FAQ) +}; + +extern "C" LRESULT QT_WIN_CALLBACK qWindowsTabletSupportWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WT_PROXIMITY: + if (QWindowsContext::instance()->tabletSupport()->translateTabletProximityEvent(wParam, lParam)) + return 0; + break; + case WT_PACKET: + if (QWindowsContext::instance()->tabletSupport()->translateTabletPacketEvent()) + return 0; + break; + } + return DefWindowProc(hwnd, message, wParam, lParam); +} + + +// Scale tablet coordinates to screen coordinates. + +static inline int sign(int x) +{ + return x >= 0 ? 1 : -1; +} + +inline QPointF QWindowsTabletDeviceData::scaleCoordinates(int coordX, int coordY, const QRect &targetArea) const +{ + const int targetX = targetArea.x(); + const int targetY = targetArea.y(); + const int targetWidth = targetArea.width(); + const int targetHeight = targetArea.height(); + + const qreal x = sign(targetWidth) == sign(maxX) ? + ((coordX - minX) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX : + ((qAbs(maxX) - (coordX - minX)) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX; + + const qreal y = sign(targetHeight) == sign(maxY) ? + ((coordY - minY) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY : + ((qAbs(maxY) - (coordY - minY)) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY; + + return QPointF(x, y); +} + +QWindowsWinTab32DLL QWindowsTabletSupport::m_winTab32DLL; + +/*! + \class QWindowsWinTab32DLL QWindowsTabletSupport + \brief Functions from wintabl32.dll shipped with WACOM tablets used by QWindowsTabletSupport. + + \internal + \ingroup qt-lighthouse-win +*/ + +bool QWindowsWinTab32DLL::init() +{ + if (wTInfo) + return true; + QSystemLibrary library(QStringLiteral("wintab32")); + if (!library.load()) + return false; + wTOpen = (PtrWTOpen)library.resolve("WTOpenW"); + wTClose = (PtrWTClose)library.resolve("WTClose"); + wTInfo = (PtrWTInfo)library.resolve("WTInfoW"); + wTEnable = (PtrWTEnable)library.resolve("WTEnable"); + wTOverlap = (PtrWTEnable)library.resolve("WTOverlap"); + wTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet"); + wTGet = (PtrWTGet)library.resolve("WTGetW"); + wTQueueSizeGet = (PtrWTQueueSizeGet)library.resolve("WTQueueSizeGet"); + wTQueueSizeSet = (PtrWTQueueSizeSet)library.resolve("WTQueueSizeSet"); + return wTOpen && wTClose && wTInfo && wTEnable && wTOverlap && wTPacketsGet && wTQueueSizeGet && wTQueueSizeSet; +} + +/*! + \class QWindowsTabletSupport + \brief Tablet support for Windows. + + Support for WACOM tablets. + + \sa http://www.wacomeng.com/windows/docs/Wintab_v140.htm + + \internal + \since 5.2 + \ingroup qt-lighthouse-win +*/ + +QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context) + : m_window(window) + , m_context(context) + , m_tiltSupport(false) + , m_currentDevice(-1) +{ + AXIS orientation[3]; + // Some tablets don't support tilt, check if it is possible, + if (QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_ORIENTATION, &orientation)) + m_tiltSupport = orientation[0].axResolution && orientation[1].axResolution; +} + +QWindowsTabletSupport::~QWindowsTabletSupport() +{ + QWindowsTabletSupport::m_winTab32DLL.wTClose(m_context); + DestroyWindow(m_window); +} + +QWindowsTabletSupport *QWindowsTabletSupport::create() +{ + if (!m_winTab32DLL.init()) + return 0; + const HWND window = QWindowsContext::instance()->createDummyWindow(QStringLiteral("TabletDummyWindow"), + L"TabletDummyWindow", + qWindowsTabletSupportWndProc); + if (!window) { + if (QWindowsContext::verboseTablet) + qWarning() << __FUNCTION__ << "Unable to create window for tablet."; + return 0; + } + LOGCONTEXT lcMine; + // build our context from the default context + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFSYSCTX, 0, &lcMine); + // Go for the raw coordinates, the tablet event will return good stuff + lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES; + lcMine.lcPktData = lcMine.lcMoveMask = PACKETDATA; + lcMine.lcPktMode = PacketMode; + lcMine.lcOutOrgX = 0; + lcMine.lcOutExtX = lcMine.lcInExtX; + lcMine.lcOutOrgY = 0; + lcMine.lcOutExtY = -lcMine.lcInExtY; + const HCTX context = QWindowsTabletSupport::m_winTab32DLL.wTOpen(window, &lcMine, true); + if (!context) { + if (QWindowsContext::verboseTablet) + qWarning() << __FUNCTION__ << "Unable to open tablet."; + DestroyWindow(window); + return 0; + + } + // Set the size of the Packet Queue to the correct size + const int currentQueueSize = QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeGet(context); + if (currentQueueSize != TabletPacketQSize) { + if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, TabletPacketQSize)) { + if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, currentQueueSize)) { + qWarning() << "Unable to set queue size on tablet. The tablet will not work."; + QWindowsTabletSupport::m_winTab32DLL.wTClose(context); + DestroyWindow(window); + return 0; + } // cannot restore old size + } // cannot set + } // mismatch + if (QWindowsContext::verboseTablet) + qDebug("Opened tablet context %p on window %p, changed packet queue size %d -> %d", + context, window, currentQueueSize, TabletPacketQSize); + return new QWindowsTabletSupport(window, context); +} + +unsigned QWindowsTabletSupport::options() const +{ + UINT result = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_CTXOPTIONS, &result); + return result; +} + +QString QWindowsTabletSupport::description() const +{ + const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0); + if (!size) + return QString(); + QScopedPointer<TCHAR> winTabId(new TCHAR[size + 1]); + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data()); + WORD implementationVersion = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion); + WORD specificationVersion = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_SPECVERSION, &specificationVersion); + const unsigned opts = options(); + QString result = QString::fromLatin1("%1 specification: v%2.%3 implementation: v%4.%5 options: 0x%6") + .arg(QString::fromWCharArray(winTabId.data())) + .arg(specificationVersion >> 8).arg(specificationVersion & 0xFF) + .arg(implementationVersion >> 8).arg(implementationVersion & 0xFF) + .arg(opts, 0, 16); + if (opts & CXO_MESSAGES) + result += QStringLiteral(" CXO_MESSAGES"); + if (opts & CXO_CSRMESSAGES) + result += QStringLiteral(" CXO_CSRMESSAGES"); + if (m_tiltSupport) + result += QStringLiteral(" tilt"); + return result; +} + +void QWindowsTabletSupport::notifyActivate() +{ + // Cooperate with other tablet applications, but when we get focus, I want to use the tablet. + const bool result = QWindowsTabletSupport::m_winTab32DLL.wTEnable(m_context, true) + && QWindowsTabletSupport::m_winTab32DLL.wTOverlap(m_context, true); + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << result; +} + +static inline int indexOfDevice(const QVector<QWindowsTabletDeviceData> &devices, qint64 uniqueId) +{ + for (int i = 0; i < devices.size(); ++i) + if (devices.at(i).uniqueId == uniqueId) + return i; + return -1; +} + +static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType) +{ + if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902)) + return QTabletEvent::Stylus; + switch (cursorType & CursorTypeBitMask) { + case 0x0802: + return QTabletEvent::Stylus; + case 0x0902: + return QTabletEvent::Airbrush; + case 0x0004: + return QTabletEvent::FourDMouse; + case 0x0006: + return QTabletEvent::Puck; + case 0x0804: + return QTabletEvent::RotationStylus; + default: + break; + } + return QTabletEvent::NoDevice; +} + +static inline QTabletEvent::PointerType pointerType(unsigned currentCursor) +{ + switch (currentCursor % 3) { // %3 for dual track + case 0: + return QTabletEvent::Cursor; + case 1: + return QTabletEvent::Pen; + case 2: + return QTabletEvent::Eraser; + default: + break; + } + return QTabletEvent::UnknownPointer; +} + +QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t) +{ + d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure + << ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".." + << t.maxTanPressure << " area:" << t.minX << t.minY <<t.minZ + << ".." << t.maxX << t.maxY << t.maxZ << " device " << t.currentDevice + << " pointer " << t.currentPointerType; + return d; +} + +QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(const quint64 uniqueId, const UINT cursorType) const +{ + QWindowsTabletDeviceData result; + result.uniqueId = uniqueId; + /* browse WinTab's many info items to discover pressure handling. */ + AXIS axis; + LOGCONTEXT lc; + /* get the current context for its device variable. */ + QWindowsTabletSupport::m_winTab32DLL.wTGet(m_context, &lc); + /* get the size of the pressure axis. */ + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &axis); + result.minPressure = int(axis.axMin); + result.maxPressure = int(axis.axMax); + + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &axis); + result.minTanPressure = int(axis.axMin); + result.maxTanPressure = int(axis.axMax); + + LOGCONTEXT defaultLc; + /* get default region */ + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFCONTEXT, 0, &defaultLc); + result.maxX = int(defaultLc.lcInExtX) - int(defaultLc.lcInOrgX); + result.maxY = int(defaultLc.lcInExtY) - int(defaultLc.lcInOrgY); + result.maxZ = int(defaultLc.lcInExtZ) - int(defaultLc.lcInOrgZ); + result.currentDevice = deviceType(cursorType); + return result; +} + +bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam) +{ + const bool enteredProximity = LOWORD(lParam) != 0; + PACKET proximityBuffer[1]; // we are only interested in the first packet in this case + const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); + if (!totalPacks) + return false; + const UINT currentCursor = proximityBuffer[0].pkCursor; + UINT physicalCursorId; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId); + UINT cursorType; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &cursorType); + const qint64 uniqueId = (qint64(cursorType & DeviceIdMask) << 32L) | qint64(physicalCursorId); + // initializing and updating the cursor should be done in response to + // WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send + // the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES + m_currentDevice = indexOfDevice(m_devices, uniqueId); + if (m_currentDevice < 0) { + m_currentDevice = m_devices.size(); + m_devices.push_back(tabletInit(uniqueId, cursorType)); + } + m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor); + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << (enteredProximity ? "enter" : "leave") + << " proximity for device #" + << m_currentDevice << m_devices.at(m_currentDevice); + if (enteredProximity) { + QWindowSystemInterface::handleTabletEnterProximityEvent(m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + } else { + QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + } + return true; +} + +bool QWindowsTabletSupport::translateTabletPacketEvent() +{ + static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue. + const int packetCount = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, TabletPacketQSize, &localPacketBuf); + if (!packetCount || m_currentDevice < 0) + return false; + + const int currentDevice = m_devices.at(m_currentDevice).currentDevice; + const int currentPointer = m_devices.at(m_currentDevice).currentPointerType; + + // When entering proximity, the tablet driver snaps the mouse pointer to the + // tablet position scaled to the virtual desktop and keeps it in sync. + const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); + + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << "processing " << packetCount + << "target:" << QGuiApplicationPrivate::tabletPressTarget; + + const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); + + for (int i = 0; i < packetCount ; ++i) { + const PACKET &packet = localPacketBuf[i]; + + const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0; + const QPointF globalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea); + + QWindow *target = QGuiApplicationPrivate::tabletPressTarget; // Pass to window that grabbed it. + const QPoint globalPos = globalPosF.toPoint(); + if (!target) + if (QPlatformWindow *pw = QWindowsContext::instance()->findPlatformWindowAt(GetDesktopWindow(), globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT)) + target = pw->window(); + if (!target) + continue; + + const QPoint localPos = target->mapFromGlobal(globalPos); + + const qreal pressureNew = packet.pkButtons && (currentPointer == QTabletEvent::Pen || currentPointer == QTabletEvent::Eraser) ? + m_devices.at(m_currentDevice).scalePressure(packet.pkNormalPressure) : + qreal(0); + const qreal tangentialPressure = currentDevice == QTabletEvent::Airbrush ? + m_devices.at(m_currentDevice).scaleTangentialPressure(packet.pkTangentPressure) : + qreal(0); + + int tiltX = 0; + int tiltY = 0; + qreal rotation = 0; + if (m_tiltSupport) { + // Convert from azimuth and altitude to x tilt and y tilt. What + // follows is the optimized version. Here are the equations used: + // X = sin(azimuth) * cos(altitude) + // Y = cos(azimuth) * cos(altitude) + // Z = sin(altitude) + // X Tilt = arctan(X / Z) + // Y Tilt = arctan(Y / Z) + const double radAzim = (packet.pkOrientation.orAzimuth / 10) * (M_PI / 180); + const double tanAlt = tan((abs(packet.pkOrientation.orAltitude / 10)) * (M_PI / 180)); + + const double degX = atan(sin(radAzim) / tanAlt); + const double degY = atan(cos(radAzim) / tanAlt); + tiltX = int(degX * (180 / M_PI)); + tiltY = int(-degY * (180 / M_PI)); + rotation = packet.pkOrientation.orTwist; + } + + if (QWindowsContext::verboseTablet > 1) { + qDebug() + << "Packet #" << i << '/' << packetCount << "button:" << packet.pkButtons + << globalPosF << z << "to:" << target << localPos << "(packet" << packet.pkX + << packet.pkY << ") dev:" << currentDevice << "pointer:" + << currentPointer << "P:" << pressureNew << "tilt:" << tiltX << ',' + << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; + } + + QWindowSystemInterface::handleTabletEvent(target, packet.pkButtons, localPos, globalPosF, + currentDevice, currentPointer, + pressureNew, tiltX, tiltY, + tangentialPressure, rotation, z, + m_devices.at(m_currentDevice).uniqueId, + keyboardModifiers); + } + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_TABLETEVENT diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h new file mode 100644 index 0000000000..12f96b618d --- /dev/null +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSTABLETSUPPORT_H +#define QWINDOWSTABLETSUPPORT_H + +#include "qtwindowsglobal.h" + +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + +#include <QtCore/QVector> +#include <QtCore/QPointF> + +#include <wintab.h> + +QT_BEGIN_NAMESPACE + +class QDebug; +class QWindow; +class QRect; + +struct QWindowsWinTab32DLL +{ + QWindowsWinTab32DLL() : wTOpen(0), wTClose(0), wTInfo(0), wTEnable(0), wTOverlap(0), wTPacketsGet(0), wTGet(0), + wTQueueSizeGet(0), wTQueueSizeSet(0) {} + + bool init(); + + typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL); + typedef BOOL (API *PtrWTClose)(HCTX); + typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID); + typedef BOOL (API *PtrWTEnable)(HCTX, BOOL); + typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL); + typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID); + typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT); + typedef int (API *PtrWTQueueSizeGet)(HCTX); + typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int); + + PtrWTOpen wTOpen; + PtrWTClose wTClose; + PtrWTInfo wTInfo; + PtrWTEnable wTEnable; + PtrWTOverlap wTOverlap; + PtrWTPacketsGet wTPacketsGet; + PtrWTGet wTGet; + PtrWTQueueSizeGet wTQueueSizeGet; + PtrWTQueueSizeSet wTQueueSizeSet; +}; + +struct QWindowsTabletDeviceData +{ + QWindowsTabletDeviceData() : minPressure(0), maxPressure(0), minTanPressure(0), + maxTanPressure(0), minX(0), maxX(0), minY(0), maxY(0), minZ(0), maxZ(0), + uniqueId(0), currentDevice(0), currentPointerType(0) {} + + QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const; + qreal scalePressure(qreal p) const { return p / qreal(maxPressure - minPressure); } + qreal scaleTangentialPressure(qreal p) const { return p / qreal(maxTanPressure - minTanPressure); } + + int minPressure; + int maxPressure; + int minTanPressure; + int maxTanPressure; + int minX, maxX, minY, maxY, minZ, maxZ; + qint64 uniqueId; + int currentDevice; + int currentPointerType; +}; + +QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t); + +class QWindowsTabletSupport +{ + Q_DISABLE_COPY(QWindowsTabletSupport) + + explicit QWindowsTabletSupport(HWND window, HCTX context); + +public: + ~QWindowsTabletSupport(); + + static QWindowsTabletSupport *create(); + + void notifyActivate(); + QString description() const; + + bool translateTabletProximityEvent(WPARAM wParam, LPARAM lParam); + bool translateTabletPacketEvent(); + +private: + unsigned options() const; + QWindowsTabletDeviceData tabletInit(const quint64 uniqueId, const UINT cursorType) const; + + static QWindowsWinTab32DLL m_winTab32DLL; + const HWND m_window; + const HCTX m_context; + bool m_tiltSupport; + QVector<QWindowsTabletDeviceData> m_devices; + int m_currentDevice; +}; + +QT_END_NAMESPACE + +#endif // !QT_NO_TABLETEVENT && !Q_OS_WINCE +#endif // QWINDOWSTABLETSUPPORT_H diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 0fcd20f7bb..882967d22c 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -404,6 +404,8 @@ void QWindowsTheme::refreshFonts() const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont); const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont); + QFont fixedFont(QStringLiteral("Courier New"), messageBoxFont.pointSize()); + fixedFont.setStyleHint(QFont::TypeWriter); LOGFONT lfIconTitleFont; SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); @@ -418,6 +420,7 @@ void QWindowsTheme::refreshFonts() m_fonts[MdiSubWindowTitleFont] = new QFont(titleFont); m_fonts[DockWidgetTitleFont] = new QFont(titleFont); m_fonts[ItemViewFont] = new QFont(iconTitleFont); + m_fonts[FixedFont] = new QFont(fixedFont); if (QWindowsContext::verboseTheming) qDebug() << __FUNCTION__ << '\n' @@ -595,7 +598,8 @@ public: void operator delete (void *) {} }; -QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { /* We don't use the variable, but by storing it statically, we * ensure CoInitialize is only called once. */ @@ -604,6 +608,8 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s static QCache<QString, FakePointer<int> > dirIconEntryCache(1000); static QMutex mx; + static int defaultFolderIIcon = 0; + const bool useDefaultFolderIcon = iconOptions & QPlatformTheme::DontUseCustomDirectoryIcons; QPixmap pixmap; const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); @@ -612,7 +618,8 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); if (cacheableDirIcon) { QMutexLocker locker(&mx); - int iIcon = **dirIconEntryCache.object(filePath); + int iIcon = (useDefaultFolderIcon && defaultFolderIIcon) ? defaultFolderIIcon + : **dirIconEntryCache.object(filePath); if (iIcon) { QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); if (pixmap.isNull()) // Let's keep both caches in sync @@ -629,13 +636,24 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s #else iconSize|SHGFI_SYSICONINDEX; #endif // Q_OS_WINCE - unsigned long val = SHGetFileInfo((const wchar_t *)filePath.utf16(), 0, - &info, sizeof(SHFILEINFO), flags); + unsigned long val = 0; + if (cacheableDirIcon && useDefaultFolderIcon) { + flags |= SHGFI_USEFILEATTRIBUTES; + val = SHGetFileInfo(L"dummy", + FILE_ATTRIBUTE_DIRECTORY, + &info, sizeof(SHFILEINFO), flags); + } else { + val = SHGetFileInfo(reinterpret_cast<const wchar_t *>(filePath.utf16()), 0, + &info, sizeof(SHFILEINFO), flags); + } // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases if (val && info.hIcon) { QString key; if (cacheableDirIcon) { + if (useDefaultFolderIcon && !defaultFolderIIcon) + defaultFolderIIcon = info.iIcon; + //using the unique icon index provided by windows save us from duplicate keys key = dirIconPixmapCacheKey(info.iIcon, iconSize); QPixmapCache::find(key, pixmap); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index bbd7f4623f..9346621d59 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -68,7 +68,8 @@ public: { return m_fonts[type]; } virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const; void windowsThemeChanged(QWindow *window); diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 3aa9caaa0f..d4e6e558ed 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -102,6 +102,12 @@ contains(QT_CONFIG, opengles2) { } } +!wince*:!contains( DEFINES, QT_NO_TABLETEVENT ) { + INCLUDEPATH += ../../../3rdparty/wintab + HEADERS += qwindowstabletsupport.h + SOURCES += qwindowstabletsupport.cpp +} + contains(QT_CONFIG, freetype) { DEFINES *= QT_NO_FONTCONFIG QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype diff --git a/src/plugins/platforms/xcb/main.cpp b/src/plugins/platforms/xcb/main.cpp index be5a0e3501..e114827703 100644 --- a/src/plugins/platforms/xcb/main.cpp +++ b/src/plugins/platforms/xcb/main.cpp @@ -47,15 +47,15 @@ QT_BEGIN_NAMESPACE class QXcbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "xcb.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "xcb.json") public: - QPlatformIntegration *create(const QString&, const QStringList&); + QPlatformIntegration *create(const QString&, const QStringList&, int &, char **); }; -QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters) +QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv) { if (system.toLower() == "xcb") - return new QXcbIntegration(parameters); + return new QXcbIntegration(parameters, argc, argv); return 0; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 01af23377e..3f717ae2df 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -51,6 +51,7 @@ #include "qxcbwmsupport.h" #include "qxcbnativeinterface.h" #include "qxcbintegration.h" +#include "qxcbsystemtraytracker.h" #include <QtAlgorithms> #include <QSocketNotifier> @@ -262,6 +263,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , has_xkb(false) , m_buttons(0) , m_focusWindow(0) + , m_systemTrayTracker(0) { #ifdef XCB_USE_XLIB Display *dpy = XOpenDisplay(m_displayName.constData()); @@ -656,6 +658,11 @@ void QXcbConnection::log(const char *file, int line, int sequence) void QXcbConnection::handleXcbError(xcb_generic_error_t *error) { + long result = 0; + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); + if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result)) + return; + uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); @@ -813,6 +820,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); case XCB_UNMAP_NOTIFY: HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); + case XCB_DESTROY_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent); case XCB_CLIENT_MESSAGE: handleClientMessageEvent((xcb_client_message_event_t *)event); break; @@ -1193,6 +1202,8 @@ void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t * drag()->handleFinished(event); } #endif + if (m_systemTrayTracker && event->type == atom(QXcbAtom::MANAGER)) + m_systemTrayTracker->notifyManagerClientMessageEvent(event); QXcbWindow *window = platformWindowFromId(event->window); if (!window) @@ -1228,6 +1239,8 @@ static const char * xcb_atomnames = { "_NET_WM_CONTEXT_HELP\0" "_NET_WM_SYNC_REQUEST\0" "_NET_WM_SYNC_REQUEST_COUNTER\0" + "MANAGER\0" + "_NET_SYSTEM_TRAY_OPCODE\0" // ICCCM window state "WM_STATE\0" @@ -1385,6 +1398,8 @@ static const char * xcb_atomnames = { "Abs MT Pressure\0" "Abs MT Tracking ID\0" "Max Contacts\0" + "Rel X\0" + "Rel Y\0" // XInput2 tablet "Abs X\0" "Abs Y\0" @@ -1401,11 +1416,16 @@ static const char * xcb_atomnames = { "_XSETTINGS_SETTINGS\0" // \0\0 terminates loop. }; -xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom) +xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; } +QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const +{ + return static_cast<QXcbAtom::Atom>(qFind(m_allAtoms, m_allAtoms + QXcbAtom::NAtoms, xatom) - m_allAtoms); +} + void QXcbConnection::initializeAllAtoms() { const char *names[QXcbAtom::NAtoms]; const char *ptr = xcb_atomnames; @@ -1721,6 +1741,17 @@ bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int o } #endif // defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) +QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() +{ + if (!m_systemTrayTracker) { + if ( (m_systemTrayTracker = QXcbSystemTrayTracker::create(this)) ) { + connect(m_systemTrayTracker, SIGNAL(systemTrayWindowChanged(QScreen*)), + QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*))); + } + } + return m_systemTrayTracker; +} + QXcbConnectionGrabber::QXcbConnectionGrabber(QXcbConnection *connection) :m_connection(connection) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 2a5ff0b1cb..aa0e070061 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -87,6 +87,7 @@ class QXcbKeyboard; class QXcbClipboard; class QXcbWMSupport; class QXcbNativeInterface; +class QXcbSystemTrayTracker; namespace QXcbAtom { enum Atom { @@ -98,6 +99,8 @@ namespace QXcbAtom { _NET_WM_CONTEXT_HELP, _NET_WM_SYNC_REQUEST, _NET_WM_SYNC_REQUEST_COUNTER, + MANAGER, // System tray notification + _NET_SYSTEM_TRAY_OPCODE, // System tray operation // ICCCM window state WM_STATE, @@ -256,6 +259,8 @@ namespace QXcbAtom { AbsMTPressure, AbsMTTrackingID, MaxContacts, + RelX, + RelY, // XInput2 tablet AbsX, AbsY, @@ -319,6 +324,7 @@ public: virtual void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *) {} virtual void handleMapNotifyEvent(const xcb_map_notify_event_t *) {} virtual void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *) {} + virtual void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *) {} virtual void handleButtonPressEvent(const xcb_button_press_event_t *) {} virtual void handleButtonReleaseEvent(const xcb_button_release_event_t *) {} virtual void handleMotionNotifyEvent(const xcb_motion_notify_event_t *) {} @@ -346,7 +352,8 @@ public: const QList<QXcbScreen *> &screens() const { return m_screens; } int primaryScreen() const { return m_primaryScreen; } - xcb_atom_t atom(QXcbAtom::Atom atom); + xcb_atom_t atom(QXcbAtom::Atom atom) const; + QXcbAtom::Atom qatom(xcb_atom_t atom) const; xcb_atom_t internAtom(const char *name); QByteArray atomName(xcb_atom_t atom); @@ -430,6 +437,9 @@ public: void ungrabServer(); QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; } + + QXcbSystemTrayTracker *systemTrayTracker(); + private slots: void processXcbEvents(); @@ -478,8 +488,6 @@ private: }; QHash<int, ValuatorClassInfo> valuatorInfo; }; - void xi2QueryTabletData(void *dev, TabletData *tabletData); // use no XI stuff in headers - void xi2SetupTabletDevices(); bool xi2HandleTabletEvent(void *event, TabletData *tabletData); void xi2ReportTabletEvent(const TabletData &tabletData, void *event); QVector<TabletData> m_tabletData; @@ -565,6 +573,7 @@ private: QXcbWindow *m_focusWindow; QByteArray m_startupId; + QXcbSystemTrayTracker *m_systemTrayTracker; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 991c82eaaa..466193b7a1 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -44,8 +44,8 @@ #include "qxcbwindow.h" #include "qtouchdevice.h" #include <qpa/qwindowsysteminterface.h> -//#define XI2_TOUCH_DEBUG -#ifdef XI2_TOUCH_DEBUG +//#define XI2_DEBUG +#ifdef XI2_DEBUG #include <QDebug> #endif @@ -63,20 +63,19 @@ struct XInput2DeviceData { } XIDeviceInfo *xiDeviceInfo; QTouchDevice *qtTouchDevice; -}; -#ifndef QT_NO_TABLETEVENT -static inline bool q_xi2_is_tablet(XIDeviceInfo *dev) -{ - QByteArray name(dev->name); - name = name.toLower(); - // Cannot just check for "wacom" because that would also pick up the touch and tablet-button devices. - return name.contains("stylus") || name.contains("eraser"); -} -#endif // QT_NO_TABLETEVENT + // Stuff that is relevant only for touchpads + QHash<int, QPointF> pointPressedPosition; // in screen coordinates where each point was pressed + QPointF firstPressedPosition; // in screen coordinates where the first point was pressed + QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed + QSizeF size; // device size in mm +}; void QXcbConnection::initializeXInput2() { +#ifndef QT_NO_TABLETEVENT + m_tabletData.clear(); +#endif Display *xDisplay = static_cast<Display *>(m_xlib_display); if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) { int xiMajor = 2; @@ -88,13 +87,76 @@ void QXcbConnection::initializeXInput2() m_xi2Enabled = true; } if (m_xi2Enabled) { +#ifdef XI2_DEBUG + qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor); +#endif + int deviceCount = 0; + XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); + for (int i = 0; i < deviceCount; ++i) { + // Only non-master pointing devices are relevant here. + if (devices[i].use != XISlavePointer) + continue; +#ifdef XI2_DEBUG + qDebug() << "input device "<< devices[i].name; +#endif #ifndef QT_NO_TABLETEVENT - // Tablet support: Find the stylus-related devices. - xi2SetupTabletDevices(); + TabletData tabletData; +#endif + for (int c = 0; c < devices[i].num_classes; ++c) { + switch (devices[i].classes[c]->type) { + case XIValuatorClass: { + XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]); + const int valuatorAtom = qatom(vci->label); +#ifdef XI2_DEBUG + qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); +#endif +#ifndef QT_NO_TABLETEVENT + if (valuatorAtom < QXcbAtom::NAtoms) { + TabletData::ValuatorClassInfo info; + info.minVal = vci->min; + info.maxVal = vci->max; + info.number = vci->number; + tabletData.valuatorInfo[valuatorAtom] = info; + } #endif // QT_NO_TABLETEVENT -#ifdef XI2_TOUCH_DEBUG - qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor); + } break; + default: + break; + } + } + bool isTablet = false; +#ifndef QT_NO_TABLETEVENT + // If we have found the valuators which we expect a tablet to have, assume it's a tablet. + if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsY) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) { + tabletData.deviceId = devices[i].deviceid; + tabletData.pointerType = QTabletEvent::Pen; + if (QByteArray(devices[i].name).toLower().contains("eraser")) + tabletData.pointerType = QTabletEvent::Eraser; + m_tabletData.append(tabletData); + isTablet = true; +#ifdef XI2_DEBUG + qDebug() << " it's a tablet with pointer type" << tabletData.pointerType; #endif + } +#endif // QT_NO_TABLETEVENT +#ifdef XI2_DEBUG + if (!isTablet) { + XInput2DeviceData *dev = deviceForId(devices[i].deviceid); + if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) + qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints()); + else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad) + qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints(), + dev->size.width(), dev->size.height()); + } +#endif // XI2_DEBUG + } + XIFreeDeviceInfo(devices); } } } @@ -113,25 +175,24 @@ void QXcbConnection::xi2Select(xcb_window_t window) unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask); #ifdef XCB_USE_XINPUT22 - // Select touch events on all master devices indiscriminately. bitMask |= XI_TouchBeginMask; bitMask |= XI_TouchUpdateMask; bitMask |= XI_TouchEndMask; XIEventMask mask; - mask.deviceid = XIAllMasterDevices; mask.mask_len = sizeof(bitMask); mask.mask = xiBitMask; - Status result = XISelectEvents(xDisplay, window, &mask, 1); - // If we have XInput 2.2 and successfully enable touch on the master - // devices, then evdev touchscreens will provide touch only. In most other - // cases, there will be emulated mouse events, because true X11 touch - // support is so new that for the older drivers, mouse emulation was the - // only way; and it's still the fallback even with the modern evdev driver. - // But if neither Qt nor X11 does mouse emulation, it will not be possible - // to interact with mouse-oriented QWidgets; so we have to let Qt do it. - if (m_xi2Minor >= 2 && result == Success) - has_touch_without_mouse_emulation = true; -#endif + // Enable each touchscreen + foreach (XInput2DeviceData *dev, m_touchDevices.values()) { + mask.deviceid = dev->xiDeviceInfo->deviceid; + Status result = XISelectEvents(xDisplay, window, &mask, 1); + // If we have XInput >= 2.2 and successfully enable a touchscreen, then + // it will provide touch only. In most other cases, there will be + // emulated mouse events from the driver. If not, then Qt must do its + // own mouse emulation to enable interaction with mouse-oriented QWidgets. + if (m_xi2Minor >= 2 && result == Success) + has_touch_without_mouse_emulation = true; + } +#endif // XCB_USE_XINPUT22 #ifndef QT_NO_TABLETEVENT // For each tablet, select some additional event types. @@ -163,23 +224,29 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) QTouchDevice::Capabilities caps = 0; dev = new XInput2DeviceData; dev->xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), id, &unused); - dev->qtTouchDevice = new QTouchDevice; + int type = -1; + int maxTouchPoints = 1; + bool hasRelativeCoords = false; for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; switch (classinfo->type) { #ifdef XCB_USE_XINPUT22 case XITouchClass: { XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo); + maxTouchPoints = tci->num_touches; +#ifdef XI2_DEBUG + qDebug(" has touch class with mode %d", tci->mode); +#endif switch (tci->mode) { case XIModeRelative: - dev->qtTouchDevice->setType(QTouchDevice::TouchPad); + type = QTouchDevice::TouchPad; break; case XIModeAbsolute: - dev->qtTouchDevice->setType(QTouchDevice::TouchScreen); + type = QTouchDevice::TouchScreen; break; } } break; -#endif +#endif // XCB_USE_XINPUT22 case XIValuatorClass: { XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); if (vci->label == atom(QXcbAtom::AbsMTPositionX)) @@ -188,18 +255,36 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) caps |= QTouchDevice::Area; else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure)) caps |= QTouchDevice::Pressure; + else if (vci->label == atom(QXcbAtom::RelX)) { + hasRelativeCoords = true; + dev->size.setWidth((vci->max - vci->min) * 1000.0 / vci->resolution); + } else if (vci->label == atom(QXcbAtom::RelY)) { + hasRelativeCoords = true; + dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); + } } break; } } - dev->qtTouchDevice->setCapabilities(caps); - dev->qtTouchDevice->setName(dev->xiDeviceInfo->name); - if (caps != 0) - QWindowSystemInterface::registerTouchDevice(dev->qtTouchDevice); -#ifdef XI2_TOUCH_DEBUG - qDebug("registered new device %s with %d classes and %d max touch points", - dev->xiDeviceInfo->name, dev->xiDeviceInfo->num_classes, dev->qtTouchDevice->maxTouchPoints()); -#endif - m_touchDevices[id] = dev; + if (type < 0 && caps && hasRelativeCoords) { + type = QTouchDevice::TouchPad; + if (dev->size.width() < 10 || dev->size.height() < 10 || + dev->size.width() > 10000 || dev->size.height() > 10000) + dev->size = QSizeF(130, 110); + } + if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) { + dev->qtTouchDevice = new QTouchDevice; + dev->qtTouchDevice->setName(dev->xiDeviceInfo->name); + dev->qtTouchDevice->setType((QTouchDevice::DeviceType)type); + dev->qtTouchDevice->setCapabilities(caps); + dev->qtTouchDevice->setMaximumTouchPoints(maxTouchPoints); + if (caps != 0) + QWindowSystemInterface::registerTouchDevice(dev->qtTouchDevice); + m_touchDevices[id] = dev; + } else { + m_touchDevices.remove(id); + delete dev; + dev = 0; + } } return dev; } @@ -218,7 +303,7 @@ static qreal valuatorNormalized(double value, XIValuatorClassInfo *vci) value = vci->min; return (value - vci->min) / (vci->max - vci->min); } -#endif +#endif // XCB_USE_XINPUT22 void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { @@ -237,7 +322,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) #ifdef XCB_USE_XINPUT22 if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); -#ifdef XI2_TOUCH_DEBUG +#ifdef XI2_DEBUG qDebug("XI2 event type %d seq %d detail %d pos 0x%X,0x%X %f,%f root pos %f,%f", event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, xiDeviceEvent->event_x, xiDeviceEvent->event_y, @@ -247,6 +332,8 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { XInput2DeviceData *dev = deviceForId(xiEvent->deviceid); + Q_ASSERT(dev); + const bool firstTouch = m_touchPoints.isEmpty(); if (xiEvent->evtype == XI_TouchBegin) { QWindowSystemInterface::TouchPoint tp; tp.id = xiDeviceEvent->detail % INT_MAX; @@ -267,11 +354,15 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) double value; if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) continue; -#ifdef XI2_TOUCH_DEBUG - qDebug(" valuator class label %d value %lf from range %lf -> %lf name %s", - vci->label, value, vci->min, vci->max, XGetAtomName(static_cast<Display *>(m_xlib_display), vci->label) ); +#ifdef XI2_DEBUG + qDebug(" valuator %20s value %lf from range %lf -> %lf", + atomName(vci->label).constData(), value, vci->min, vci->max ); #endif - if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { + if (vci->label == atom(QXcbAtom::RelX)) { + nx = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::RelY)) { + ny = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { nx = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { ny = valuatorNormalized(value, vci); @@ -306,19 +397,45 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) } switch (xiEvent->evtype) { + case XI_TouchBegin: + if (firstTouch) { + dev->firstPressedPosition = QPointF(x, y); + dev->firstPressedNormalPosition = QPointF(nx, ny); + } + dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y)); + break; case XI_TouchUpdate: - if (touchPoint.area.center() != QPoint(x, y)) + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.height() * screen->geometry().height() / screen->physicalSize().height(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + touchPoint.state = Qt::TouchPointMoved; + } else if (touchPoint.area.center() != QPoint(x, y)) { touchPoint.state = Qt::TouchPointMoved; + dev->pointPressedPosition[touchPoint.id] = QPointF(x, y); + } else touchPoint.state = Qt::TouchPointStationary; break; case XI_TouchEnd: touchPoint.state = Qt::TouchPointReleased; + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + } + dev->pointPressedPosition.remove(touchPoint.id); } touchPoint.area = QRectF(x - w/2, y - h/2, w, h); touchPoint.normalPosition = QPointF(nx, ny); -#ifdef XI2_TOUCH_DEBUG +#ifdef XI2_DEBUG qDebug() << " tp " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << " area " << touchPoint.area << " pressure " << touchPoint.pressure; #endif @@ -328,80 +445,11 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) m_touchPoints.remove(touchPoint.id); } } -#endif +#endif // XCB_USE_XINPUT22 } } #ifndef QT_NO_TABLETEVENT -void QXcbConnection::xi2QueryTabletData(void *dev, TabletData *tabletData) -{ - XIDeviceInfo *device = static_cast<XIDeviceInfo *>(dev); - tabletData->deviceId = device->deviceid; - - tabletData->pointerType = QTabletEvent::Pen; - if (QByteArray(device->name).toLower().contains("eraser")) - tabletData->pointerType = QTabletEvent::Eraser; - - for (int i = 0; i < device->num_classes; ++i) { - switch (device->classes[i]->type) { - case XIValuatorClass: { - XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(device->classes[i]); - int val = 0; - if (vci->label == atom(QXcbAtom::AbsX)) - val = QXcbAtom::AbsX; - else if (vci->label == atom(QXcbAtom::AbsY)) - val = QXcbAtom::AbsY; - else if (vci->label == atom(QXcbAtom::AbsPressure)) - val = QXcbAtom::AbsPressure; - else if (vci->label == atom(QXcbAtom::AbsTiltX)) - val = QXcbAtom::AbsTiltX; - else if (vci->label == atom(QXcbAtom::AbsTiltY)) - val = QXcbAtom::AbsTiltY; - else if (vci->label == atom(QXcbAtom::AbsWheel)) - val = QXcbAtom::AbsWheel; - else if (vci->label == atom(QXcbAtom::AbsDistance)) - val = QXcbAtom::AbsDistance; - if (val) { - TabletData::ValuatorClassInfo info; - info.minVal = vci->min; - info.maxVal = vci->max; - info.number = vci->number; - tabletData->valuatorInfo[val] = info; - } - } - break; - default: - break; - } - } -} - -void QXcbConnection::xi2SetupTabletDevices() -{ - Display *xDisplay = static_cast<Display *>(m_xlib_display); - m_tabletData.clear(); - int deviceCount = 0; - XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); - if (devices) { - for (int i = 0; i < deviceCount; ++i) { - int unused = 0; - XIDeviceInfo *dev = XIQueryDevice(xDisplay, devices[i].deviceid, &unused); - if (dev) { - if (q_xi2_is_tablet(dev)) { - TabletData tabletData; - xi2QueryTabletData(dev, &tabletData); -#ifdef XI2_TOUCH_DEBUG - qDebug() << "found tablet" << dev->name; -#endif - m_tabletData.append(tabletData); - } - XIFreeDeviceInfo(dev); - } - } - XIFreeDeviceInfo(devices); - } -} - bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) { bool handled = true; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index cf7e99023a..68ad93143b 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -119,9 +119,10 @@ static bool runningUnderDebugger() } #endif -QXcbIntegration::QXcbIntegration(const QStringList ¶meters) +QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char **argv) : m_eventDispatcher(createUnixEventDispatcher()) , m_services(new QGenericUnixServices) + , m_instanceName(0) { QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); @@ -138,7 +139,28 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters) if (canNotGrabEnv) canGrab = false; - m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab); + // Parse arguments + const char *displayName = 0; + if (argc) { + int j = 1; + for (int i = 1; i < argc; i++) { + char *arg = argv[i]; + if (arg) { + if (!strcmp(arg, "-display") && i < argc - 1) { + displayName = argv[++i]; + arg = 0; + } else if (!strcmp(arg, "-name") && i < argc - 1) { + m_instanceName = argv[++i]; + arg = 0; + } + } + if (arg) + argv[j++] = arg; + } + argc = j; + } // argc + + m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab, displayName); for (int i = 0; i < parameters.size() - 1; i += 2) { #ifdef Q_XCB_DEBUG @@ -365,6 +387,8 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::SynthesizeMouseFromTouchEvents: // We do not want Qt to synthesize mouse events if X11 already does it. return m_connections.at(0)->hasTouchWithoutMouseEmulation(); + default: + break; } return QPlatformIntegration::styleHint(hint); } @@ -389,6 +413,8 @@ QByteArray QXcbIntegration::wmClass() const if (m_wmClass.isEmpty()) { // Instance name according to ICCCM 4.1.2.5 QString name; + if (m_instanceName) + name = QString::fromLocal8Bit(m_instanceName); if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar)) name = QString::fromLocal8Bit(qgetenv(resourceNameVar)); if (name.isEmpty()) diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 07b6b8d678..09fc0d32b5 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -55,7 +55,7 @@ class QXcbScreen; class QXcbIntegration : public QPlatformIntegration { public: - QXcbIntegration(const QStringList ¶meters); + QXcbIntegration(const QStringList ¶meters, int &argc, char **argv); ~QXcbIntegration(); QPlatformWindow *createPlatformWindow(QWindow *window) const; @@ -119,6 +119,7 @@ private: friend class QXcbConnection; // access QPlatformIntegration::screenAdded() mutable QByteArray m_wmClass; + const char *m_instanceName; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index d1729ed168..2529fb8a83 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -243,6 +243,10 @@ #define XF86XK_Select 0x1008FFA0 #define XF86XK_View 0x1008FFA1 #define XF86XK_TopMenu 0x1008FFA2 +#define XF86XK_Red 0x1008FFA3 +#define XF86XK_Green 0x1008FFA4 +#define XF86XK_Yellow 0x1008FFA5 +#define XF86XK_Blue 0x1008FFA6 #define XF86XK_Suspend 0x1008FFA7 #define XF86XK_Hibernate 0x1008FFA8 #define XF86XK_TouchpadToggle 0x1008FFA9 @@ -538,6 +542,10 @@ static const unsigned int KeyTbl[] = { XF86XK_Select, Qt::Key_Select, XF86XK_View, Qt::Key_View, XF86XK_TopMenu, Qt::Key_TopMenu, + XF86XK_Red, Qt::Key_Red, + XF86XK_Green, Qt::Key_Green, + XF86XK_Yellow, Qt::Key_Yellow, + XF86XK_Blue, Qt::Key_Blue, XF86XK_Bluetooth, Qt::Key_Bluetooth, XF86XK_Suspend, Qt::Key_Suspend, XF86XK_Hibernate, Qt::Key_Hibernate, diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 9e9fd2914f..99e9932847 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -42,7 +42,9 @@ #include "qxcbnativeinterface.h" #include "qxcbscreen.h" +#include "qxcbwindow.h" #include "qxcbintegration.h" +#include "qxcbsystemtraytracker.h" #include <private/qguiapplication_p.h> #include <QtCore/QMap> @@ -82,6 +84,8 @@ public: insert("appusertime",QXcbNativeInterface::AppUserTime); insert("hintstyle", QXcbNativeInterface::ScreenHintStyle); insert("startupid", QXcbNativeInterface::StartupId); + insert(QByteArrayLiteral("traywindow"), QXcbNativeInterface::TrayWindow); + insert(QByteArrayLiteral("gettimestamp"), QXcbNativeInterface::GetTimestamp); } }; @@ -100,6 +104,36 @@ void QXcbNativeInterface::beep() // For QApplication::beep() xcb_bell(connection, 0); } +static inline QXcbSystemTrayTracker *systemTrayTracker(const QScreen *s) +{ + return static_cast<const QXcbScreen *>(s->handle())->connection()->systemTrayTracker(); +} + +bool QXcbNativeInterface::systemTrayAvailable(const QScreen *screen) const +{ + return systemTrayTracker(screen); +} + +bool QXcbNativeInterface::requestSystemTrayWindowDock(const QWindow *window) +{ + const QPlatformWindow *platformWindow = window->handle(); + if (!platformWindow) + return false; + QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen()); + if (!trayTracker) + return false; + trayTracker->requestSystemTrayWindowDock(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); + return true; +} + +QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window) +{ + if (const QPlatformWindow *platformWindow = window->handle()) + if (const QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen())) + return trayTracker->systemTrayWindowGlobalGeometry(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); + return QRect(); +} + void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) { QByteArray lowerCaseResource = resourceString.toLower(); @@ -162,6 +196,14 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q break; case ScreenHintStyle: result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1); + break; + case TrayWindow: + if (QXcbSystemTrayTracker *s = systemTrayTracker(screen)) + result = (void *)quintptr(s->trayWindow()); + break; + case GetTimestamp: + result = getTimestamp(xcbScreen); + break; default: break; } @@ -216,6 +258,11 @@ void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen) return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime())); } +void *QXcbNativeInterface::getTimestamp(const QXcbScreen *screen) +{ + return reinterpret_cast<void *>(quintptr(screen->connection()->getTimestamp())); +} + void *QXcbNativeInterface::startupId() { QXcbIntegration* integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index e27bfa5a46..86b94e62e4 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -45,6 +45,8 @@ #include <qpa/qplatformnativeinterface.h> #include <xcb/xcb.h> +#include <QtCore/QRect> + QT_BEGIN_NAMESPACE class QWidget; @@ -66,7 +68,9 @@ public: AppTime, AppUserTime, ScreenHintStyle, - StartupId + StartupId, + TrayWindow, + GetTimestamp }; QXcbNativeInterface(); @@ -88,6 +92,7 @@ public: void *graphicsDeviceForWindow(QWindow *window); void *appTime(const QXcbScreen *screen); void *appUserTime(const QXcbScreen *screen); + void *getTimestamp(const QXcbScreen *screen); void *startupId(); static void setAppTime(QScreen *screen, xcb_timestamp_t time); static void setAppUserTime(QScreen *screen, xcb_timestamp_t time); @@ -95,6 +100,12 @@ public: static void *glxContextForContext(QOpenGLContext *context); Q_INVOKABLE void beep(); + Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const; + Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window); + Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window); + +signals: + void systemTrayWindowChanged(QScreen *screen); private: const QByteArray m_genericEventFilterType; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 37c6c97bc4..0971b6ca8e 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -112,6 +112,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_PROPERTY_CHANGE + | XCB_EVENT_MASK_STRUCTURE_NOTIFY // for the "MANAGER" atom (system tray notification). }; xcb_change_window_attributes(xcb_connection(), screen()->root, mask, values); diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp new file mode 100644 index 0000000000..24d2feb106 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbsystemtraytracker.h" +#include "qxcbconnection.h" +#include "qxcbscreen.h" + +#include <QtCore/QDebug> +#include <QtCore/QRect> +#include <QtGui/QScreen> + +#include <qpa/qplatformnativeinterface.h> + +QT_BEGIN_NAMESPACE + +enum { + SystemTrayRequestDock = 0, + SystemTrayBeginMessage = 1, + SystemTrayCancelMessage = 2 +}; + +// QXcbSystemTrayTracker provides API for accessing the tray window and tracks +// its lifecyle by listening for its destruction and recreation. +// See http://standards.freedesktop.org/systemtray-spec/systemtray-spec-latest.html + +QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection) +{ + // Selection, tray atoms for GNOME, NET WM Specification + const xcb_atom_t trayAtom = connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_OPCODE); + if (!trayAtom) + return 0; + const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreen()); + const xcb_atom_t selection = connection->internAtom(netSysTray.constData()); + if (!selection) + return 0; + return new QXcbSystemTrayTracker(connection, trayAtom, selection, connection); +} + +QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection, + xcb_atom_t trayAtom, + xcb_atom_t selection, + QObject *parent) + : QObject(parent) + , m_selection(selection) + , m_trayAtom(trayAtom) + , m_connection(connection) + , m_trayWindow(0) +{ +} + +xcb_window_t QXcbSystemTrayTracker::locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection) +{ + xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(connection->xcb_connection(), selection); + xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(connection->xcb_connection(), cookie, 0); + if (!reply) + return 0; + const xcb_window_t result = reply->owner; + free(reply); + return result; +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Request a window +// to be docked on the tray. +void QXcbSystemTrayTracker::requestSystemTrayWindowDock(xcb_window_t window) const +{ + xcb_client_message_event_t trayRequest; + memset(&trayRequest, 0, sizeof(trayRequest)); + trayRequest.response_type = XCB_CLIENT_MESSAGE; + trayRequest.format = 32; + trayRequest.window = m_trayWindow; + trayRequest.type = m_trayAtom; + trayRequest.data.data32[0] = XCB_CURRENT_TIME; + trayRequest.data.data32[1] = SystemTrayRequestDock; + trayRequest.data.data32[2] = window; + xcb_send_event(m_connection->xcb_connection(), 0, m_trayWindow, XCB_EVENT_MASK_NO_EVENT, (const char *)&trayRequest); +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Return tray window. +xcb_window_t QXcbSystemTrayTracker::trayWindow() +{ + if (!m_trayWindow) { + m_trayWindow = QXcbSystemTrayTracker::locateTrayWindow(m_connection, m_selection); + if (m_trayWindow) { // Listen for DestroyNotify on tray. + m_connection->addWindowEventListener(m_trayWindow, this); + const quint32 mask = XCB_CW_EVENT_MASK; + const quint32 value = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + Q_XCB_CALL(xcb_change_window_attributes(m_connection->xcb_connection(), m_trayWindow, mask, &value)); + } + } + return m_trayWindow; +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Return the geometry of a +// a window parented on the tray. Determines the global geometry via XCB since mapToGlobal +// does not work for the QWindow parented on the tray. +QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) const +{ + xcb_connection_t *conn = m_connection->xcb_connection(); + xcb_get_geometry_reply_t *geomReply = + xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), 0); + if (!geomReply) + return QRect(); + + xcb_translate_coordinates_reply_t *translateReply = + xcb_translate_coordinates_reply(conn, xcb_translate_coordinates(conn, window, m_connection->rootWindow(), 0, 0), 0); + if (!translateReply) { + free(geomReply); + return QRect(); + } + + const QRect result(QPoint(translateReply->dst_x, translateReply->dst_y), QSize(geomReply->width, geomReply->height)); + free(translateReply); + return result; +} + +inline void QXcbSystemTrayTracker::emitSystemTrayWindowChanged() +{ + const int screen = m_connection->primaryScreen(); + if (screen >= 0 && screen < m_connection->screens().size()) { + const QPlatformScreen *ps = m_connection->screens().at(screen); + emit systemTrayWindowChanged(ps->screen()); + } +} + +// Client messages with the "MANAGER" atom on the root window indicate creation of a new tray. +void QXcbSystemTrayTracker::notifyManagerClientMessageEvent(const xcb_client_message_event_t *t) +{ + if (t->data.data32[1] == m_selection) + emitSystemTrayWindowChanged(); +} + +// Listen for destruction of the tray. +void QXcbSystemTrayTracker::handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *event) +{ + if (event->window == m_trayWindow) { + m_connection->removeWindowEventListener(m_trayWindow); + m_trayWindow = 0; + emitSystemTrayWindowChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h new file mode 100644 index 0000000000..c6b0a0659e --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBSYSTEMTRAYTRACKER_H +#define QXCBSYSTEMTRAYTRACKER_H + +#include "qxcbconnection.h" + +#include <xcb/xcb.h> + +QT_BEGIN_NAMESPACE + +class QXcbConnection; +class QScreen; + +class QXcbSystemTrayTracker : public QObject, public QXcbWindowEventListener +{ + Q_OBJECT +public: + static QXcbSystemTrayTracker *create(QXcbConnection *connection); + + xcb_window_t trayWindow(); + void requestSystemTrayWindowDock(xcb_window_t window) const; + QRect systemTrayWindowGlobalGeometry(xcb_window_t window) const; + + void notifyManagerClientMessageEvent(const xcb_client_message_event_t *); + + void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *); + +signals: + void systemTrayWindowChanged(QScreen *screen); + +private: + explicit QXcbSystemTrayTracker(QXcbConnection *connection, + xcb_atom_t trayAtom, + xcb_atom_t selection, + QObject *parent = 0); + static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection); + void emitSystemTrayWindowChanged(); + + const xcb_atom_t m_selection; + const xcb_atom_t m_trayAtom; + QXcbConnection *m_connection; + xcb_window_t m_trayWindow; +}; + +QT_END_NAMESPACE + +#endif // QXCBSYSTEMTRAYTRACKER_H diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 028cd9ab72..35b95b84a1 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1515,8 +1515,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even m_syncValue.hi = event->data.data32[3]; #ifndef QT_NO_WHATSTHIS } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) { - QEvent *e = new QEvent(QEvent::EnterWhatsThisMode); - QGuiApplication::postEvent(QGuiApplication::instance(), e); + QWindowSystemInterface::handleEnterWhatsThisEvent(); #endif } else { qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); @@ -1533,6 +1532,9 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even #endif } else if (event->type == atom(QXcbAtom::_XEMBED)) { handleXEmbedMessage(event); + } else if (event->type == atom(QXcbAtom::MANAGER) || event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) { + // Ignore _NET_ACTIVE_WINDOW which is received when the user clicks on a system tray icon and + // MANAGER which indicates the creation of a system tray. } else { qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type); } diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 82995286c4..b198ab1717 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -21,7 +21,8 @@ SOURCES = \ qxcbnativeinterface.cpp \ qxcbcursor.cpp \ qxcbimage.cpp \ - qxcbxsettings.cpp + qxcbxsettings.cpp \ + qxcbsystemtraytracker.cpp HEADERS = \ qxcbclipboard.h \ @@ -38,7 +39,8 @@ HEADERS = \ qxcbnativeinterface.h \ qxcbcursor.h \ qxcbimage.h \ - qxcbxsettings.h + qxcbxsettings.h \ + qxcbsystemtraytracker.h LIBS += -ldl diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp index 91a23afac5..e8758da1c7 100644 --- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp +++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp @@ -282,13 +282,13 @@ bool QGtk2FileDialogHelper::defaultNameFilterDisables() const return false; } -void QGtk2FileDialogHelper::setDirectory(const QString &directory) +void QGtk2FileDialogHelper::setDirectory(const QUrl &directory) { GtkDialog *gtkDialog = d->gtkDialog(); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toUtf8()); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toLocalFile().toUtf8()); } -QString QGtk2FileDialogHelper::directory() const +QUrl QGtk2FileDialogHelper::directory() const { // While GtkFileChooserDialog is hidden, gtk_file_chooser_get_current_folder() // returns a bogus value -> return the cached value before hiding @@ -302,27 +302,27 @@ QString QGtk2FileDialogHelper::directory() const ret = QString::fromUtf8(folder); g_free(folder); } - return ret; + return QUrl::fromLocalFile(ret); } -void QGtk2FileDialogHelper::selectFile(const QString &filename) +void QGtk2FileDialogHelper::selectFile(const QUrl &filename) { GtkDialog *gtkDialog = d->gtkDialog(); - gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toUtf8()); + gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toLocalFile().toUtf8()); } -QStringList QGtk2FileDialogHelper::selectedFiles() const +QList<QUrl> QGtk2FileDialogHelper::selectedFiles() const { // While GtkFileChooserDialog is hidden, gtk_file_chooser_get_filenames() // returns a bogus value -> return the cached value before hiding if (!_selection.isEmpty()) return _selection; - QStringList selection; + QList<QUrl> selection; GtkDialog *gtkDialog = d->gtkDialog(); GSList *filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(gtkDialog)); for (GSList *it = filenames; it; it = it->next) - selection += QString::fromUtf8((const char*)it->data); + selection += QUrl::fromLocalFile(QString::fromUtf8((const char*)it->data)); g_slist_free(filenames); return selection; } @@ -356,7 +356,7 @@ void QGtk2FileDialogHelper::onAccepted() if (filter.isEmpty()) emit filterSelected(filter); - QStringList files = selectedFiles(); + QList<QUrl> files = selectedFiles(); emit filesSelected(files); if (files.count() == 1) emit fileSelected(files.first()); @@ -370,7 +370,7 @@ void QGtk2FileDialogHelper::onSelectionChanged(GtkDialog *gtkDialog, QGtk2FileDi selection = QString::fromUtf8(filename); g_free(filename); } - emit helper->currentChanged(selection); + emit helper->currentChanged(QUrl::fromLocalFile(selection)); } void QGtk2FileDialogHelper::onCurrentFolderChanged(QGtk2FileDialogHelper *dialog) @@ -419,12 +419,12 @@ void QGtk2FileDialogHelper::applyOptions() if (!nameFilters.isEmpty()) setNameFilters(nameFilters); - const QString initialDirectory = opts->initialDirectory(); + const QString initialDirectory = opts->initialDirectory().toLocalFile(); if (!initialDirectory.isEmpty()) setDirectory(initialDirectory); - foreach (const QString &filename, opts->initiallySelectedFiles()) - selectFile(filename); + foreach (const QUrl &filename, opts->initiallySelectedFiles()) + selectFile(filename.toLocalFile()); const QString initialNameFilter = opts->initiallySelectedNameFilter(); if (!initialNameFilter.isEmpty()) diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h index c2d12625f5..47a6153fbc 100644 --- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h +++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h @@ -90,10 +90,10 @@ public: void hide(); bool defaultNameFilterDisables() const; - void setDirectory(const QString &directory); - QString directory() const; - void selectFile(const QString &filename); - QStringList selectedFiles() const; + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; void setFilter(); void selectNameFilter(const QString &filter); QString selectedNameFilter() const; @@ -107,8 +107,8 @@ private: void applyOptions(); void setNameFilters(const QStringList &filters); - QString _dir; - QStringList _selection; + QUrl _dir; + QList<QUrl> _selection; QHash<QString, GtkFileFilter*> _filters; QHash<GtkFileFilter*, QString> _filterNames; QScopedPointer<QGtk2Dialog> d; diff --git a/src/printsupport/doc/qtprintsupport.qdocconf b/src/printsupport/doc/qtprintsupport.qdocconf index c7b14e16c1..d5015fa46a 100644 --- a/src/printsupport/doc/qtprintsupport.qdocconf +++ b/src/printsupport/doc/qtprintsupport.qdocconf @@ -40,3 +40,6 @@ excludedirs += ../../../examples/widgets/doc imagedirs += images \ ../../widgets/doc/images \ + +navigation.landingpage = "Qt Print Support" +navigation.cppclassespage = "Qt Print Support C++ Classes" diff --git a/src/printsupport/doc/src/qtprintsupport-module.qdoc b/src/printsupport/doc/src/qtprintsupport-module.qdoc index aaff476bc5..20ff11d8cb 100644 --- a/src/printsupport/doc/src/qtprintsupport-module.qdoc +++ b/src/printsupport/doc/src/qtprintsupport-module.qdoc @@ -31,6 +31,7 @@ \brief The Qt PrintSupport module provides classes to make printing easier and portable. \ingroup modules + \qtvariable printsupport To include the definitions of the module's classes, use the following directive: diff --git a/src/sql/doc/qtsql.qdocconf b/src/sql/doc/qtsql.qdocconf index c2686079d5..a2a05d7c8a 100644 --- a/src/sql/doc/qtsql.qdocconf +++ b/src/sql/doc/qtsql.qdocconf @@ -39,3 +39,6 @@ exampledirs += ../../../examples/sql \ imagedirs += images \ ../../../examples/sql/doc/images + +navigation.landingpage = "Qt SQL" +navigation.cppclassespage = "Qt SQL C++ Classes" diff --git a/src/sql/doc/src/qtsql.qdoc b/src/sql/doc/src/qtsql.qdoc index 8ce981756a..2f806b4b45 100644 --- a/src/sql/doc/src/qtsql.qdoc +++ b/src/sql/doc/src/qtsql.qdoc @@ -62,6 +62,7 @@ \module QtSql \title Qt SQL C++ Classes \ingroup modules + \qtvariable sql \brief Provides a driver layer, SQL API layer, and a user interface layer for SQL databases. diff --git a/src/src.pro b/src/src.pro index b4c96025c1..6815fe4a75 100644 --- a/src/src.pro +++ b/src/src.pro @@ -102,12 +102,14 @@ src_android.subdir = $$PWD/android # this order is important SUBDIRS += src_tools_bootstrap src_tools_moc src_tools_rcc src_corelib +TOOLS = src_tools_moc src_tools_rcc win32:SUBDIRS += src_winmain SUBDIRS += src_network src_sql src_xml src_testlib contains(QT_CONFIG, dbus) { SUBDIRS += src_dbus force_bootstrap: SUBDIRS += src_tools_bootstrap_dbus SUBDIRS += src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml + TOOLS += src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml contains(QT_CONFIG, accessibility-atspi-bridge): \ src_platformsupport.depends += src_dbus src_tools_qdbusxml2cpp src_plugins.depends += src_dbus src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml @@ -123,6 +125,7 @@ contains(QT_CONFIG, concurrent):SUBDIRS += src_concurrent src_plugins.depends += src_gui src_platformsupport !contains(QT_CONFIG, no-widgets) { SUBDIRS += src_tools_uic src_widgets + TOOLS += src_tools_uic src_plugins.depends += src_widgets contains(QT_CONFIG, opengl(es1|es2)?) { SUBDIRS += src_opengl @@ -139,3 +142,6 @@ SUBDIRS += src_plugins src_tools_qdoc nacl: SUBDIRS -= src_network src_testlib android:!android-no-sdk: SUBDIRS += src_android + +sub-tools.depends = $$TOOLS +QMAKE_EXTRA_TARGETS = sub-tools diff --git a/src/testlib/doc/qttestlib.qdocconf b/src/testlib/doc/qttestlib.qdocconf index 2eea4f246a..ab2bdc1948 100644 --- a/src/testlib/doc/qttestlib.qdocconf +++ b/src/testlib/doc/qttestlib.qdocconf @@ -40,3 +40,6 @@ exampledirs += ../../../examples/qtestlib \ excludedirs += ../../../examples/widgets/doc imagedirs += images + +navigation.landingpage = "Qt Test" +navigation.cppclassespage = "Qt Test C++ Classes" diff --git a/src/testlib/doc/src/qttest.qdoc b/src/testlib/doc/src/qttest.qdoc index 6e0bd3c070..c9e1683f83 100644 --- a/src/testlib/doc/src/qttest.qdoc +++ b/src/testlib/doc/src/qttest.qdoc @@ -29,6 +29,7 @@ \module QtTest \title Qt Test C++ Classes \ingroup modules + \qtvariable testlib \keyword QtTest diff --git a/src/testlib/doc/src/qttestlib-manual.qdoc b/src/testlib/doc/src/qttestlib-manual.qdoc index c44bb49ae3..613d2c220c 100644 --- a/src/testlib/doc/src/qttestlib-manual.qdoc +++ b/src/testlib/doc/src/qttestlib-manual.qdoc @@ -247,6 +247,9 @@ 2000. \li \c -nocrashhandler \br Disables the crash handler on Unix platforms. + On Windows, it re-enables the Windows Error Reporting dialog, which is + turned off by default. + \li \c -platform \e name \br This command line argument applies to all Qt applications, but might be especially useful in the context of auto-testing. By using the "offscreen" diff --git a/src/testlib/qabstracttestlogger.cpp b/src/testlib/qabstracttestlogger.cpp index d039c3c342..41f8f37872 100644 --- a/src/testlib/qabstracttestlogger.cpp +++ b/src/testlib/qabstracttestlogger.cpp @@ -52,6 +52,10 @@ #include <unistd.h> #endif +#ifdef Q_OS_ANDROID +#include <sys/stat.h> +#endif + QT_BEGIN_NAMESPACE QAbstractTestLogger::QAbstractTestLogger(const char *filename) @@ -69,6 +73,12 @@ QAbstractTestLogger::QAbstractTestLogger(const char *filename) fprintf(stderr, "Unable to open file for logging: %s\n", filename); ::exit(1); } +#ifdef Q_OS_ANDROID + else { + // Make sure output is world-readable on Android + ::chmod(filename, 0666); + } +#endif } QAbstractTestLogger::~QAbstractTestLogger() diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 77a59d0cf0..5d5a976201 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1130,9 +1130,7 @@ namespace QTest static int keyDelay = -1; static int mouseDelay = -1; static int eventDelay = -1; -#if defined(Q_OS_UNIX) static bool noCrashHandler = false; -#endif /*! \internal Invoke a method of the object without generating warning if the method does not exist @@ -1335,9 +1333,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) " -mousedelay ms : Set default delay for mouse simulation to ms milliseconds\n" " -maxwarnings n : Sets the maximum amount of messages to output.\n" " 0 means unlimited, default: 2000\n" -#if defined(Q_OS_UNIX) " -nocrashhandler : Disables the crash handler\n" -#endif "\n" " Benchmarking options:\n" #ifdef QTESTLIB_USE_VALGRIND @@ -1468,10 +1464,8 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) } else { QTestLog::setMaxWarnings(qToInt(argv[++i])); } -#if defined(Q_OS_UNIX) } else if (strcmp(argv[i], "-nocrashhandler") == 0) { QTest::noCrashHandler = true; -#endif #ifdef QTESTLIB_USE_VALGRIND } else if (strcmp(argv[i], "-callgrind") == 0) { if (QBenchmarkValgrindUtils::haveValgrind()) @@ -2083,6 +2077,18 @@ FatalSignalHandler::~FatalSignalHandler() } // namespace +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo) +{ + char appName[MAX_PATH]; + if (!GetModuleFileNameA(NULL, appName, MAX_PATH)) + appName[0] = 0; + fprintf(stderr, "A crash occurred in %s (exception code 0x%lx).", + appName, exInfo->ExceptionRecord->ExceptionCode); + return EXCEPTION_EXECUTE_HANDLER; +} +#endif // Q_OS_WIN) && !Q_OS_WINCE + /*! Executes tests declared in \a testObject. In addition, the private slots \c{initTestCase()}, \c{cleanupTestCase()}, \c{init()} and \c{cleanup()} @@ -2138,13 +2144,6 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) try { #endif -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) -# if !defined(Q_CC_MINGW) - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); -# endif - SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); -#endif - #if defined(Q_OS_MACX) if (macNeedsActivate) { CFStringRef reasonForActivity= CFSTR("No Display Sleep"); @@ -2170,6 +2169,16 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) qtest_qParseArgs(argc, argv, false); +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + if (!noCrashHandler) { +# ifndef Q_CC_MINGW + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +# endif + SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); + SetUnhandledExceptionFilter(windowsFaultHandler); + } // !noCrashHandler +#endif // Q_OS_WIN) && !Q_OS_WINCE + #ifdef QTESTLIB_USE_VALGRIND if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) { const QStringList origAppArgs(QCoreApplication::arguments()); diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp index a6a8ee0cc1..7ab317f209 100644 --- a/src/testlib/qtestresult.cpp +++ b/src/testlib/qtestresult.cpp @@ -268,10 +268,12 @@ bool QTestResult::compare(bool success, const char *failureMsg, if (success && QTest::expectFailMode) { qsnprintf(msg, 1024, "QCOMPARE(%s, %s) returned TRUE unexpectedly.", actual, expected); } else if (val1 || val2) { - qsnprintf(msg, 1024, "%s\n Actual (%s): %s\n Expected (%s): %s", + size_t len1 = strlen(actual); + size_t len2 = strlen(expected); + qsnprintf(msg, 1024, "%s\n Actual (%s)%*s %s\n Expected (%s)%*s %s", failureMsg, - actual, val1 ? val1 : "<null>", - expected, val2 ? val2 : "<null>"); + actual, qMax(len1, len2) - len1 + 1, ":", val1 ? val1 : "<null>", + expected, qMax(len1, len2) - len2 + 1, ":", val2 ? val2 : "<null>"); } else qsnprintf(msg, 1024, "%s", failureMsg); diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp index a66757907d..0e1fa59b90 100644 --- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp +++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp @@ -47,6 +47,7 @@ #include <qbuffer.h> #include <qregexp.h> #include <qvector.h> +#include <qdebug.h> #include <stdio.h> #include <stdlib.h> @@ -95,14 +96,14 @@ static const char help[] = "\n"; -int qDBusParametersForMethod(const FunctionDef &mm, QVector<int>& metaTypes) +int qDBusParametersForMethod(const FunctionDef &mm, QVector<int>& metaTypes, QString &errorMsg) { QList<QByteArray> parameterTypes; foreach (const ArgumentDef &arg, mm.arguments) parameterTypes.append(arg.normalizedType); - return qDBusParametersForMethod(parameterTypes, metaTypes); + return qDBusParametersForMethod(parameterTypes, metaTypes, errorMsg); } @@ -140,9 +141,12 @@ static QString addFunction(const FunctionDef &mm, bool isSignal = false) { } QList<ArgumentDef> names = mm.arguments; QVector<int> types; - int inputCount = qDBusParametersForMethod(mm, types); - if (inputCount == -1) + QString errorMsg; + int inputCount = qDBusParametersForMethod(mm, types, errorMsg); + if (inputCount == -1) { + qWarning() << qPrintable(errorMsg); return QString(); // invalid form + } if (isSignal && inputCount + 1 != types.count()) return QString(); // signal with output arguments? if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message()) diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp index e6d77643de..f2b9441ea4 100644 --- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp +++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -401,6 +401,8 @@ static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, QString name = arg.name; if (name.isEmpty()) name = QString( QLatin1String("in%1") ).arg(i); + else + name.replace(QLatin1Char('-'), QLatin1Char('_')); while (retval.contains(name)) name += QLatin1String("_"); retval << name; @@ -410,6 +412,8 @@ static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, QString name = arg.name; if (name.isEmpty()) name = QString( QLatin1String("out%1") ).arg(i); + else + name.replace(QLatin1Char('-'), QLatin1Char('_')); while (retval.contains(name)) name += QLatin1String("_"); retval << name; diff --git a/src/tools/qdoc/codemarker.cpp b/src/tools/qdoc/codemarker.cpp index c7d9c5b339..8faac66b1b 100644 --- a/src/tools/qdoc/codemarker.cpp +++ b/src/tools/qdoc/codemarker.cpp @@ -398,7 +398,7 @@ void CodeMarker::insert(FastSection &fastSection, bool inheritedMember = false; if (!node->relates()) { InnerNode* p = node->parent(); - if (p->subType() == Node::QmlPropertyGroup) + if (p->type() == Node::QmlPropertyGroup) p = p->parent(); if (p != fastSection.parent_) { // && !node->parent()->isAbstract()) { if (p->subType() != Node::QmlClass || !p->isAbstract()) { diff --git a/src/tools/qdoc/codeparser.cpp b/src/tools/qdoc/codeparser.cpp index 7b534a6c95..1be67894cc 100644 --- a/src/tools/qdoc/codeparser.cpp +++ b/src/tools/qdoc/codeparser.cpp @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords")) #define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary")) #define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup")) +#define COMMAND_QTVARIABLE Doc::alias(QLatin1String("qtvariable")) #define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant")) #define COMMAND_SINCE Doc::alias(QLatin1String("since")) #define COMMAND_SUBTITLE Doc::alias(QLatin1String("subtitle")) @@ -199,29 +200,34 @@ CodeParser *CodeParser::parserForSourceFile(const QString &filePath) return 0; } +static QSet<QString> commonMetaCommands_; /*! Returns the set of strings representing the common metacommands. */ -QSet<QString> CodeParser::commonMetaCommands() +const QSet<QString>& CodeParser::commonMetaCommands() { - return QSet<QString>() << COMMAND_COMPAT - << COMMAND_DEPRECATED - << COMMAND_INGROUP - << COMMAND_INMODULE - << COMMAND_INQMLMODULE - << COMMAND_INTERNAL - << COMMAND_MAINCLASS - << COMMAND_NONREENTRANT - << COMMAND_OBSOLETE - << COMMAND_PAGEKEYWORDS - << COMMAND_PRELIMINARY - << COMMAND_INPUBLICGROUP - << COMMAND_REENTRANT - << COMMAND_SINCE - << COMMAND_SUBTITLE - << COMMAND_THREADSAFE - << COMMAND_TITLE - << COMMAND_WRAPPER; + if (commonMetaCommands_.isEmpty()) { + commonMetaCommands_ << COMMAND_COMPAT + << COMMAND_DEPRECATED + << COMMAND_INGROUP + << COMMAND_INMODULE + << COMMAND_INQMLMODULE + << COMMAND_INTERNAL + << COMMAND_MAINCLASS + << COMMAND_NONREENTRANT + << COMMAND_OBSOLETE + << COMMAND_PAGEKEYWORDS + << COMMAND_PRELIMINARY + << COMMAND_INPUBLICGROUP + << COMMAND_QTVARIABLE + << COMMAND_REENTRANT + << COMMAND_SINCE + << COMMAND_SUBTITLE + << COMMAND_THREADSAFE + << COMMAND_TITLE + << COMMAND_WRAPPER; + } + return commonMetaCommands_; } /*! @@ -269,8 +275,8 @@ void CodeParser::processCommonMetaCommand(const Location& location, if (!showInternal) { node->setAccess(Node::Private); node->setStatus(Node::Internal); - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { @@ -317,6 +323,15 @@ void CodeParser::processCommonMetaCommand(const Location& location, else location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE)); } + else if (command == COMMAND_QTVARIABLE) { + if (node->subType() == Node::Module) { + DocNode *dn = static_cast<DocNode *>(node); + dn->setQtVariable(arg.first); + } + else + location.warning(tr("Command '\\%1' found outside of '\\module'. It can only be used within a module page.") + .arg(COMMAND_QTVARIABLE)); + } } /*! diff --git a/src/tools/qdoc/codeparser.h b/src/tools/qdoc/codeparser.h index 8c398aeb05..89f661abeb 100644 --- a/src/tools/qdoc/codeparser.h +++ b/src/tools/qdoc/codeparser.h @@ -86,7 +86,7 @@ public: static const QString& currentOutputSubdirectory() { return currentSubDir_; } protected: - QSet<QString> commonMetaCommands(); + const QSet<QString>& commonMetaCommands(); void processCommonMetaCommand(const Location& location, const QString& command, const ArgLocPair& arg, diff --git a/src/tools/qdoc/config.cpp b/src/tools/qdoc/config.cpp index a475ccbfb6..8729bf387f 100644 --- a/src/tools/qdoc/config.cpp +++ b/src/tools/qdoc/config.cpp @@ -279,10 +279,19 @@ int Config::getInt(const QString& var) const */ QString Config::getOutputDir() const { + QString t; if (overrideOutputDir.isNull()) - return getString(QLatin1String(CONFIG_OUTPUTDIR)); + t = getString(QLatin1String(CONFIG_OUTPUTDIR)); else - return overrideOutputDir; + t = overrideOutputDir; + if (!Generator::useOutputSubdirs()) { + t = t.left(t.lastIndexOf('/')); + QString singleOutputSubdir = getString("HTML.outputsubdir"); + if (singleOutputSubdir.isEmpty()) + singleOutputSubdir = "html"; + t += QLatin1Char('/') + singleOutputSubdir; + } + return t; } /*! diff --git a/src/tools/qdoc/config.h b/src/tools/qdoc/config.h index 8787d27eb3..948f31c01a 100644 --- a/src/tools/qdoc/config.h +++ b/src/tools/qdoc/config.h @@ -165,7 +165,9 @@ private: #define CONFIG_ALIAS "alias" #define CONFIG_BASE "base" #define CONFIG_BASEDIR "basedir" +#define CONFIG_BUILDVERSION "buildversion" #define CONFIG_CODEINDENT "codeindent" +#define CONFIG_CPPCLASSESPAGE "cppclassespage" #define CONFIG_DEFINES "defines" #define CONFIG_DEPENDS "depends" #define CONFIG_DESCRIPTION "description" @@ -184,15 +186,18 @@ private: #define CONFIG_HEADERS "headers" #define CONFIG_HEADERSCRIPTS "headerscripts" #define CONFIG_HEADERSTYLES "headerstyles" +#define CONFIG_HOMEPAGE "homepage" #define CONFIG_IGNOREDIRECTIVES "ignoredirectives" #define CONFIG_IGNORETOKENS "ignoretokens" #define CONFIG_IMAGEDIRS "imagedirs" #define CONFIG_IMAGES "images" #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" +#define CONFIG_LANDINGPAGE "landingpage" #define CONFIG_MACRO "macro" #define CONFIG_MANIFESTMETA "manifestmeta" #define CONFIG_NATURALLANGUAGE "naturallanguage" +#define CONFIG_NAVIGATION "navigation" #define CONFIG_NOLINKERRORS "nolinkerrors" #define CONFIG_OBSOLETELINKS "obsoletelinks" #define CONFIG_OUTPUTDIR "outputdir" @@ -201,7 +206,9 @@ private: #define CONFIG_OUTPUTFORMATS "outputformats" #define CONFIG_OUTPUTPREFIXES "outputprefixes" #define CONFIG_PROJECT "project" +#define CONFIG_REDIRECTDOCUMENTATIONTODEVNULL "redirectdocumentationtodevnull" #define CONFIG_QHP "qhp" +#define CONFIG_QMLTYPESPAGE "qmltypespage" #define CONFIG_QUOTINGINFORMATION "quotinginformation" #define CONFIG_SCRIPTDIRS "scriptdirs" #define CONFIG_SCRIPTS "scripts" diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp index 75e49f288a..ad3c5cba47 100644 --- a/src/tools/qdoc/cppcodemarker.cpp +++ b/src/tools/qdoc/cppcodemarker.cpp @@ -1110,40 +1110,15 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { - if ((*c)->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c); - NodeList::ConstIterator p = qpgn->childNodes().constBegin(); - while (p != qpgn->childNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p); - if (pn->isAttached()) - insert(qmlattachedproperties,*p,style,Okay); - else - insert(qmlproperties,*p,style,Okay); - } - ++p; - } + if ((*c)->type() == Node::QmlPropertyGroup) { + insert(qmlproperties, *c, style, Okay); } else if ((*c)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c); - if (pn->qmlPropNodes().isEmpty()) { - if (pn->isAttached()) - insert(qmlattachedproperties,*c,style,Okay); - else - insert(qmlproperties,*c,style,Okay); - } + if (pn->isAttached()) + insert(qmlattachedproperties,*c,style,Okay); else { - NodeList::ConstIterator p = pn->qmlPropNodes().constBegin(); - while (p != pn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p); - if (pn->isAttached()) - insert(qmlattachedproperties,*p,style,Okay); - else - insert(qmlproperties,*p,style,Okay); - } - ++p; - } + insert(qmlproperties,*c,style,Okay); } } else if ((*c)->type() == Node::QmlSignal) { @@ -1196,24 +1171,8 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { - if ((*c)->subType() == Node::QmlPropertyGroup) { - bool attached = false; - const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c); - NodeList::ConstIterator C = pgn->childNodes().constBegin(); - while (C != pgn->childNodes().constEnd()) { - if ((*C)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*C); - if (pn->isAttached()) { - attached = true; - break; - } - } - ++C; - } - if (attached) - insert(qmlattachedproperties,*c,style,Okay); - else - insert(qmlproperties,*c,style,Okay); + if ((*c)->type() == Node::QmlPropertyGroup) { + insert(qmlproperties,*c,style,Okay); } else if ((*c)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c); @@ -1278,8 +1237,8 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno } NodeList::ConstIterator c = current->childNodes().constBegin(); while (c != current->childNodes().constEnd()) { - if ((*c)->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c); + if ((*c)->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(*c); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index 5c25eeedc4..3e63432047 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -272,37 +272,42 @@ void CppCodeParser::doneParsingSourceFiles() qdb_->treeRoot()->makeUndocumentedChildrenInternal(); } +static QSet<QString> topicCommands_; /*! Returns the set of strings reopresenting the topic commands. */ -QSet<QString> CppCodeParser::topicCommands() +const QSet<QString>& CppCodeParser::topicCommands() { - return QSet<QString>() << COMMAND_CLASS - << COMMAND_DITAMAP - << COMMAND_ENUM - << COMMAND_EXAMPLE - << COMMAND_EXTERNALPAGE - << COMMAND_FILE - << COMMAND_FN - << COMMAND_GROUP - << COMMAND_HEADERFILE - << COMMAND_MACRO - << COMMAND_MODULE - << COMMAND_NAMESPACE - << COMMAND_PAGE - << COMMAND_PROPERTY - << COMMAND_TYPEDEF - << COMMAND_VARIABLE - << COMMAND_QMLCLASS - << COMMAND_QMLTYPE - << COMMAND_QMLPROPERTY - << COMMAND_QMLATTACHEDPROPERTY - << COMMAND_QMLSIGNAL - << COMMAND_QMLATTACHEDSIGNAL - << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD - << COMMAND_QMLBASICTYPE - << COMMAND_QMLMODULE; + if (topicCommands_.isEmpty()) { + topicCommands_ << COMMAND_CLASS + << COMMAND_DITAMAP + << COMMAND_ENUM + << COMMAND_EXAMPLE + << COMMAND_EXTERNALPAGE + << COMMAND_FILE + << COMMAND_FN + << COMMAND_GROUP + << COMMAND_HEADERFILE + << COMMAND_MACRO + << COMMAND_MODULE + << COMMAND_NAMESPACE + << COMMAND_PAGE + << COMMAND_PROPERTY + << COMMAND_TYPEDEF + << COMMAND_VARIABLE + << COMMAND_QMLCLASS + << COMMAND_QMLTYPE + << COMMAND_QMLPROPERTY + << COMMAND_QMLPROPERTYGROUP + << COMMAND_QMLATTACHEDPROPERTY + << COMMAND_QMLSIGNAL + << COMMAND_QMLATTACHEDSIGNAL + << COMMAND_QMLMETHOD + << COMMAND_QMLATTACHEDMETHOD + << COMMAND_QMLBASICTYPE + << COMMAND_QMLMODULE; + } + return topicCommands_; } /*! @@ -607,10 +612,10 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, (command == COMMAND_QMLATTACHEDSIGNAL) || (command == COMMAND_QMLATTACHEDMETHOD)) { QString module; - QString element; + QString qmlType; QString type; - if (splitQmlMethodArg(arg.first,type,module,element)) { - QmlClassNode* qmlClass = qdb_->findQmlType(module,element); + if (splitQmlMethodArg(arg.first,type,module,qmlType)) { + QmlClassNode* qmlClass = qdb_->findQmlType(module,qmlType); if (qmlClass) { bool attached = false; Node::Type nodeType = Node::QmlMethod; @@ -643,28 +648,57 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, } /*! + A QML property group argument has the form... + + <QML-module>::<QML-type>::<name> + + This function splits the argument into those parts. + A <QML-module> is the QML equivalent of a C++ namespace. + So this function splits \a arg on "::" and stores the + parts in \a module, \a qmlType, and \a name, and returns + true. If any part is not found, a qdoc warning is emitted + and false is returned. + */ +bool CppCodeParser::splitQmlPropertyGroupArg(const QString& arg, + QString& module, + QString& qmlType, + QString& name) +{ + QStringList colonSplit = arg.split("::"); + if (colonSplit.size() == 3) { + module = colonSplit[0]; + qmlType = colonSplit[1]; + name = colonSplit[2]; + return true; + } + QString msg = "Unrecognizable QML module/component qualifier for " + arg; + location().warning(tr(msg.toLatin1().data())); + return false; +} + +/*! A QML property argument has the form... - <type> <element>::<name> - <type> <QML-module>::<element>::<name> + <type> <QML-type>::<name> + <type> <QML-module>::<QML-type>::<name> This function splits the argument into one of those two forms. The three part form is the old form, which was used before the creation of Qt Quick 2 and Qt Components. A <QML-module> is the QML equivalent of a C++ namespace. So this function splits \a arg on "::" - and stores the parts in \a type, \a module, \a element, + and stores the parts in \a type, \a module, \a qmlType, and \a name, and returns true. If any part other than \a module is not found, a qdoc warning is emitted and false is returned. - \note The two elements \e{Component} and \e{QtObject} never - have a module qualifier. + \note The two QML types \e{Component} and \e{QtObject} + never have a module qualifier. */ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, QString& type, QString& module, - QString& element, + QString& qmlType, QString& name) { QStringList blankSplit = arg.split(QLatin1Char(' ')); @@ -673,13 +707,13 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, QStringList colonSplit(blankSplit[1].split("::")); if (colonSplit.size() == 3) { module = colonSplit[0]; - element = colonSplit[1]; + qmlType = colonSplit[1]; name = colonSplit[2]; return true; } if (colonSplit.size() == 2) { module.clear(); - element = colonSplit[0]; + qmlType = colonSplit[0]; name = colonSplit[1]; return true; } @@ -696,21 +730,21 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, /*! A QML signal or method argument has the form... - <type> <element>::<name>(<param>, <param>, ...) - <type> <QML-module>::<element>::<name>(<param>, <param>, ...) + <type> <QML-type>::<name>(<param>, <param>, ...) + <type> <QML-module>::<QML-type>::<name>(<param>, <param>, ...) This function splits the argument into one of those two - forms, sets \a module, \a element, and \a name, and returns + forms, sets \a module, \a qmlType, and \a name, and returns true. If the argument doesn't match either form, an error message is emitted and false is returned. - \note The two elements \e{Component} and \e{QtObject} never + \note The two QML types \e{Component} and \e{QtObject} never have a module qualifier. */ bool CppCodeParser::splitQmlMethodArg(const QString& arg, QString& type, QString& module, - QString& element) + QString& qmlType) { QStringList colonSplit(arg.split("::")); if (colonSplit.size() > 1) { @@ -719,22 +753,22 @@ bool CppCodeParser::splitQmlMethodArg(const QString& arg, type = blankSplit[0]; if (colonSplit.size() > 2) { module = blankSplit[1]; - element = colonSplit[1]; + qmlType = colonSplit[1]; } else { module.clear(); - element = blankSplit[1]; + qmlType = blankSplit[1]; } } else { type.clear(); if (colonSplit.size() > 2) { module = colonSplit[0]; - element = colonSplit[1]; + qmlType = colonSplit[1]; } else { module.clear(); - element = colonSplit[0]; + qmlType = colonSplit[0]; } } return true; @@ -750,79 +784,118 @@ bool CppCodeParser::splitQmlMethodArg(const QString& arg, Currently, this function is called only for \e{qmlproperty} and \e{qmlattachedproperty}. */ -Node* CppCodeParser::processTopicCommandGroup(const Doc& doc, - const QString& command, - const ArgList& args) +void CppCodeParser::processQmlProperties(const Doc& doc, NodeList& nodes, DocList& docs) { - QmlPropGroupNode* qmlPropGroup = 0; - if ((command == COMMAND_QMLPROPERTY) || - (command == COMMAND_QMLATTACHEDPROPERTY)) { - QString arg; - QString type; - QString module; - QString element; - QString property; - QmlClassNode* qmlClass = 0; - bool attached = (command == COMMAND_QMLATTACHEDPROPERTY); - ArgList::ConstIterator argsIter = args.constBegin(); - arg = argsIter->first; - if (splitQmlPropertyArg(arg,type,module,element,property)) { - qmlClass = qdb_->findQmlType(module,element); - if (qmlClass) { - qmlPropGroup = new QmlPropGroupNode(qmlClass,property); //,attached); - qmlPropGroup->setLocation(doc.startLocation()); - } + QString arg; + QString type; + QString topic; + QString module; + QString qmlType; + QString property; + QmlPropertyNode* qpn = 0; + QmlClassNode* qmlClass = 0; + QmlPropertyGroupNode* qpgn = 0; + + Topic qmlPropertyGroupTopic; + const TopicList& topics = doc.topicsUsed(); + for (int i=0; i<topics.size(); ++i) { + if (topics.at(i).topic == COMMAND_QMLPROPERTYGROUP) { + qmlPropertyGroupTopic = topics.at(i); + break; } - if (qmlPropGroup) { - if (qmlClass->hasProperty(property)) { - doc.startLocation().warning(tr("QML property documented multiple times: '%1'").arg(arg)); + } + if (qmlPropertyGroupTopic.isEmpty() && topics.size() > 1) { + qmlPropertyGroupTopic = topics.at(0); + qmlPropertyGroupTopic.topic = COMMAND_QMLPROPERTYGROUP; + arg = qmlPropertyGroupTopic.args; + if (splitQmlPropertyArg(arg, type, module, qmlType, property)) { + int i = property.indexOf('.'); + if (i != -1) { + property = property.left(i); + qmlPropertyGroupTopic.args = module + "::" + qmlType + "::" + property; + doc.location().warning(tr("No QML property group command found; using \\%1 %2") + .arg(COMMAND_QMLPROPERTYGROUP).arg(qmlPropertyGroupTopic.args)); } else { - QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlPropGroup,property,type,attached); - qmlPropNode->setLocation(doc.startLocation()); + /* + Assumption: No '.' in the property name + means there is no property group. + */ + qmlPropertyGroupTopic.clear(); + } + } + } + + if (!qmlPropertyGroupTopic.isEmpty()) { + arg = qmlPropertyGroupTopic.args; + if (splitQmlPropertyGroupArg(arg, module, qmlType, property)) { + qmlClass = qdb_->findQmlType(module, qmlType); + if (qmlClass) { + qpgn = new QmlPropertyGroupNode(qmlClass, property); + qpgn->setLocation(doc.startLocation()); } - ++argsIter; - while (argsIter != args.constEnd()) { - arg = argsIter->first; - if (splitQmlPropertyArg(arg,type,module,element,property)) { - if (qmlClass->hasProperty(property)) { - doc.startLocation().warning(tr("QML property documented multiple times: '%1'").arg(arg)); + } + if (topics.size() == 1) { + nodes.append(qpgn); + docs.append(doc); + return; + } + } + for (int i=0; i<topics.size(); ++i) { + if (topics.at(i).topic == COMMAND_QMLPROPERTYGROUP) + continue; + topic = topics.at(i).topic; + arg = topics.at(i).args; + if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY)) { + bool attached = (topic == COMMAND_QMLATTACHEDPROPERTY); + if (splitQmlPropertyArg(arg, type, module, qmlType, property)) { + qmlClass = qdb_->findQmlType(module, qmlType); + if (qmlClass) { + if (qmlClass->hasQmlProperty(property) != 0) { + QString msg = tr("QML property documented multiple times: '%1'").arg(arg); + doc.startLocation().warning(msg); + } + else if (qpgn) { + qpn = new QmlPropertyNode(qpgn, property, type, attached); + qpn->setLocation(doc.startLocation()); } else { - QmlPropertyNode* qmlPropNode = new QmlPropertyNode(qmlPropGroup, - property, - type, - attached); - qmlPropNode->setLocation(doc.startLocation()); + qpn = new QmlPropertyNode(qmlClass, property, type, attached); + qpn->setLocation(doc.startLocation()); + nodes.append(qpn); + docs.append(doc); } } - ++argsIter; } } } - return qmlPropGroup; } +static QSet<QString> otherMetaCommands_; /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ -QSet<QString> CppCodeParser::otherMetaCommands() +const QSet<QString>& CppCodeParser::otherMetaCommands() { - return commonMetaCommands() << COMMAND_INHEADERFILE - << COMMAND_OVERLOAD - << COMMAND_REIMP - << COMMAND_RELATES - << COMMAND_CONTENTSPAGE - << COMMAND_NEXTPAGE - << COMMAND_PREVIOUSPAGE - << COMMAND_INDEXPAGE - << COMMAND_STARTPAGE - << COMMAND_QMLINHERITS - << COMMAND_QMLINSTANTIATES - << COMMAND_QMLDEFAULT - << COMMAND_QMLREADONLY - << COMMAND_QMLABSTRACT; + if (otherMetaCommands_.isEmpty()) { + otherMetaCommands_ = commonMetaCommands(); + otherMetaCommands_ << COMMAND_INHEADERFILE + << COMMAND_OVERLOAD + << COMMAND_REIMP + << COMMAND_RELATES + << COMMAND_CONTENTSPAGE + << COMMAND_NEXTPAGE + << COMMAND_PREVIOUSPAGE + << COMMAND_INDEXPAGE + << COMMAND_STARTPAGE + << COMMAND_QMLINHERITS + << COMMAND_QMLINSTANTIATES + << COMMAND_QMLDEFAULT + << COMMAND_QMLREADONLY + << COMMAND_QMLABSTRACT; + } + return otherMetaCommands_; } /*! @@ -855,8 +928,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, } } else if (command == COMMAND_REIMP) { - if (node->parent() && !node->parent()->isInternal()) { - if (node != 0 && node->type() == Node::Function) { + if (node != 0 && node->parent() && !node->parent()->isInternal()) { + if (node->type() == Node::Function) { FunctionNode *func = (FunctionNode *) node; const FunctionNode *from = func->reimplementedFrom(); if (from == 0) { @@ -961,8 +1034,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); qpn->setDefault(); } - else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) { - QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node); + else if (node->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { @@ -978,8 +1051,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); qpn->setReadOnly(1); } - else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) { - QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node); + else if (node->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { @@ -2067,10 +2140,9 @@ bool CppCodeParser::matchDeclList(InnerNode *parent) bool CppCodeParser::matchDocsAndStuff() { ExtraFuncData extra; - QSet<QString> topicCommandsAllowed = topicCommands(); - QSet<QString> otherMetacommandsAllowed = otherMetaCommands(); - QSet<QString> metacommandsAllowed = topicCommandsAllowed + - otherMetacommandsAllowed; + const QSet<QString>& topicCommandsAllowed = topicCommands(); + const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); + const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; while (tok != Tok_Eoi) { if (tok == Tok_Doc) { @@ -2087,25 +2159,22 @@ bool CppCodeParser::matchDocsAndStuff() /* Doc parses the comment. */ - Doc doc(start_loc,end_loc,comment,metacommandsAllowed); - + Doc doc(start_loc,end_loc,comment,metacommandsAllowed, topicCommandsAllowed); QString topic; - ArgList args; - - QSet<QString> topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + bool isQmlPropertyTopic = false; - /* - There should be one topic command in the set, - or none. If the set is empty, then the comment - should be a function description. - */ - if (topicCommandsUsed.count() > 0) { - topic = *topicCommandsUsed.constBegin(); - args = doc.metaCommandArgs(topic); + const TopicList& topics = doc.topicsUsed(); + if (!topics.isEmpty()) { + topic = topics[0].topic; + if ((topic == COMMAND_QMLPROPERTY) || + (topic == COMMAND_QMLPROPERTYGROUP) || + (topic == COMMAND_QMLATTACHEDPROPERTY)) { + isQmlPropertyTopic = true; + } } - + // if (isQmlPropertyTopic && doc.location().fileName().endsWith("qquickitem.cpp")) { NodeList nodes; - QList<Doc> docs; + DocList docs; if (topic.isEmpty()) { QStringList parentPath; @@ -2133,43 +2202,39 @@ bool CppCodeParser::matchDocsAndStuff() .arg(COMMAND_FN).arg(COMMAND_PAGE)); } } + else if (isQmlPropertyTopic) { + Doc nodeDoc = doc; + processQmlProperties(nodeDoc, nodes, docs); + } else { - /* - There is a topic command. Process it. - */ - if ((topic == COMMAND_QMLPROPERTY) || - (topic == COMMAND_QMLATTACHEDPROPERTY)) { + ArgList args; + const QSet<QString>& topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + if (topicCommandsUsed.count() > 0) { + topic = *topicCommandsUsed.constBegin(); + args = doc.metaCommandArgs(topic); + } + if (topicCommandsUsed.count() > 1) { + QString topics; + QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin(); + while (t != topicCommandsUsed.constEnd()) { + topics += " \\" + *t + ","; + ++t; + } + topics[topics.lastIndexOf(',')] = '.'; + int i = topics.lastIndexOf(','); + topics[i] = ' '; + topics.insert(i+1,"and"); + doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); + } + ArgList::ConstIterator a = args.constBegin(); + while (a != args.constEnd()) { Doc nodeDoc = doc; - Node *node = processTopicCommandGroup(nodeDoc, topic,args); + Node *node = processTopicCommand(nodeDoc,topic,*a); if (node != 0) { nodes.append(node); docs.append(nodeDoc); } - } - else { - if (topicCommandsUsed.count() > 1) { - QString topics; - QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin(); - while (t != topicCommandsUsed.constEnd()) { - topics += " \\" + *t + ","; - ++t; - } - topics[topics.lastIndexOf(',')] = '.'; - int i = topics.lastIndexOf(','); - topics[i] = ' '; - topics.insert(i+1,"and"); - doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); - } - ArgList::ConstIterator a = args.constBegin(); - while (a != args.constEnd()) { - Doc nodeDoc = doc; - Node *node = processTopicCommand(nodeDoc,topic,*a); - if (node != 0) { - nodes.append(node); - docs.append(nodeDoc); - } - ++a; - } + ++a; } } @@ -2262,7 +2327,7 @@ bool CppCodeParser::makeFunctionNode(const QString& signature, the \a type. \a parent is the QML class node. The QML module and QML - element names have already been consumed to find \a parent. + type names have already been consumed to find \a parent. What remains in \a sig is the method signature. The method must be a child of \a parent. */ diff --git a/src/tools/qdoc/cppcodeparser.h b/src/tools/qdoc/cppcodeparser.h index 957142712b..5ab72f7f54 100644 --- a/src/tools/qdoc/cppcodeparser.h +++ b/src/tools/qdoc/cppcodeparser.h @@ -84,13 +84,16 @@ public: virtual void doneParsingSourceFiles(); protected: - virtual QSet<QString> topicCommands(); + const QSet<QString>& topicCommands(); + const QSet<QString>& otherMetaCommands(); virtual Node* processTopicCommand(const Doc& doc, const QString& command, const ArgLocPair& arg); - virtual Node *processTopicCommandGroup(const Doc& doc, - const QString& command, - const ArgList& args); + void processQmlProperties(const Doc& doc, NodeList& nodes, DocList& docs); + bool splitQmlPropertyGroupArg(const QString& arg, + QString& module, + QString& element, + QString& name); bool splitQmlPropertyArg(const QString& arg, QString& type, QString& module, @@ -100,7 +103,6 @@ protected: QString& type, QString& module, QString& element); - virtual QSet<QString> otherMetaCommands(); virtual void processOtherMetaCommand(const Doc& doc, const QString& command, const ArgLocPair& argLocPair, @@ -212,6 +214,7 @@ protected: #define COMMAND_QMLCLASS Doc::alias("qmlclass") #define COMMAND_QMLTYPE Doc::alias("qmltype") #define COMMAND_QMLPROPERTY Doc::alias("qmlproperty") +#define COMMAND_QMLPROPERTYGROUP Doc::alias("qmlpropertygroup") #define COMMAND_QMLATTACHEDPROPERTY Doc::alias("qmlattachedproperty") #define COMMAND_QMLINHERITS Doc::alias("inherits") #define COMMAND_QMLINSTANTIATES Doc::alias("instantiates") @@ -238,6 +241,7 @@ protected: #define COMMAND_LICENSENAME Doc::alias("licensename") #define COMMAND_LICENSEDESCRIPTION Doc::alias("licensedescription") #define COMMAND_RELEASEDATE Doc::alias("releasedate") +#define COMMAND_QTVARIABLE Doc::alias("qtvariable") QT_END_NAMESPACE diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp index 96f5519be4..241fcbba43 100644 --- a/src/tools/qdoc/ditaxmlgenerator.cpp +++ b/src/tools/qdoc/ditaxmlgenerator.cpp @@ -3677,8 +3677,8 @@ QString DitaXmlGenerator::guidForNode(const Node* node) return fn->guid(); } case Node::Document: - if (node->subType() != Node::QmlPropertyGroup) - break; + break; + case Node::QmlPropertyGroup: case Node::QmlProperty: case Node::Property: return node->guid(); @@ -3743,7 +3743,7 @@ QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative) } QString link = fn; - if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) { + if (!node->isInnerNode() || node->type() == Node::QmlPropertyGroup) { QString guid = guidForNode(node); if (relative && fn == fileName(relative) && guid == guidForNode(relative)) { return QString(); @@ -3758,7 +3758,7 @@ QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative) back down into the other subdirectory. */ if (node && relative && (node != relative)) { - if (node->outputSubdirectory() != relative->outputSubdirectory()) + if (useOutputSubdirs() && node->outputSubdirectory() != relative->outputSubdirectory()) link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/'))); } return link; @@ -4079,8 +4079,8 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node, QString marked; QmlPropertyNode* qpn = 0; - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); if (qpgn->childNodes().size() == 1) { qpn = static_cast<QmlPropertyNode*>(*p); @@ -4114,50 +4114,10 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node, } else if (node->type() == Node::QmlProperty) { qpn = static_cast<QmlPropertyNode*>(node); - if (qpn->qmlPropNodes().isEmpty()) { - startQmlProperty(qpn,relative,marker); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // </qmlPropertyDetail> - writeEndTag(); // </qmlProperty> - } - else if (qpn->qmlPropNodes().size() == 1) { - Node* n = qpn->qmlPropNodes().at(0); - if (n->type() == Node::QmlProperty) { - qpn = static_cast<QmlPropertyNode*>(n); - startQmlProperty(qpn,relative,marker); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // </qmlPropertyDetail> - writeEndTag(); // </qmlProperty> - } - } - else { - /* - The QML property node has multiple override nodes. - Process the whole list as we would for a QML property - group. - */ - writeStartTag(DT_qmlPropertyGroup); - QString id = "id-qml-propertygroup-" + node->name(); - id.replace('.','-'); - xmlWriter().writeAttribute("id",id); - writeStartTag(DT_apiName); - //writeCharacters("..."); - writeEndTag(); // </apiName> - writeStartTag(DT_qmlPropertyGroupDetail); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // </qmlPropertyGroupDetail> - NodeList::ConstIterator p = qpn->qmlPropNodes().constBegin(); - while (p != qpn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - QmlPropertyNode* q = static_cast<QmlPropertyNode*>(*p); - startQmlProperty(q,relative,marker); - writeEndTag(); // </qmlPropertyDetail> - writeEndTag(); // </qmlProperty> - } - ++p; - } - writeEndTag(); // </qmlPropertyGroup - } + startQmlProperty(qpn,relative,marker); + writeApiDesc(node, marker, node->title()); + writeEndTag(); // </qmlPropertyDetail> + writeEndTag(); // </qmlProperty> } else if (node->type() == Node::QmlSignal) writeQmlRef(DT_qmlSignal,node,relative,marker); @@ -5326,13 +5286,13 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node) return; if (docNode->subType() == Node::Image) return; - if (docNode->subType() == Node::QmlPropertyGroup) - return; if (docNode->subType() == Node::Page) { if (node->count() > 0) qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title())); } } + else if (node->type() == Node::QmlPropertyGroup) + return; /* Obtain a code marker for the source file. @@ -5487,8 +5447,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent) if (!isDuplicate(nodeSubtypeMaps[Node::QmlClass],child->title(),child)) nodeSubtypeMaps[Node::QmlClass]->insert(child->title(),child); break; - case Node::QmlPropertyGroup: - break; case Node::QmlBasicType: if (!isDuplicate(nodeSubtypeMaps[Node::QmlBasicType],child->title(),child)) nodeSubtypeMaps[Node::QmlBasicType]->insert(child->title(),child); @@ -5517,6 +5475,8 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent) break; case Node::QmlProperty: break; + case Node::QmlPropertyGroup: + break; case Node::QmlSignal: break; case Node::QmlSignalHandler: diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp index 42b98502e0..4d6b0b1a2c 100644 --- a/src/tools/qdoc/doc.cpp +++ b/src/tools/qdoc/doc.cpp @@ -80,7 +80,6 @@ enum { CMD_ANNOTATEDLIST, CMD_B, CMD_BADCODE, - CMD_BASENAME, CMD_BOLD, CMD_BR, CMD_BRIEF, @@ -198,7 +197,6 @@ static struct { { "annotatedlist", CMD_ANNOTATEDLIST, 0 }, { "b", CMD_B, 0 }, { "badcode", CMD_BADCODE, 0 }, - { "basename", CMD_BASENAME, 0 }, // ### don't document for now { "bold", CMD_BOLD, 0 }, { "br", CMD_BR, 0 }, { "brief", CMD_BRIEF, 0 }, @@ -316,7 +314,6 @@ Q_GLOBAL_STATIC(QHash_QString_Macro, macroHash) class DocPrivateExtra { public: - QString baseName; Doc::Sections granularity; Doc::Sections section; // ### QList<Atom*> tableOfContents; @@ -376,7 +373,7 @@ public: bool hasLegalese : 1; bool hasSectioningUnits : 1; DocPrivateExtra *extra; - TopicList topics; + TopicList topics_; DitaRefList ditamap_; }; @@ -466,7 +463,6 @@ private: Location& location(); QString detailsUnknownCommand(const QSet<QString>& metaCommandSet, const QString& str); - void insertBaseName(const QString &baseName); void insertTarget(const QString& target, bool keyword); void include(const QString& fileName, const QString& identifier); void startFormat(const QString& format, int cmd); @@ -571,7 +567,7 @@ void DocParser::parse(const QString& source, cachedPos = 0; priv = docPrivate; priv->text << Atom::Nop; - priv->topics.clear(); + priv->topics_.clear(); paraState = OutsideParagraph; inTableHeader = false; @@ -644,10 +640,6 @@ void DocParser::parse(const QString& source, leavePara(); append(Atom::CodeBad,getCode(CMD_BADCODE, marker)); break; - case CMD_BASENAME: - leavePara(); - insertBaseName(getArgument()); - break; case CMD_BR: leavePara(); append(Atom::BR); @@ -1404,7 +1396,7 @@ void DocParser::parse(const QString& source, QString arg = getMetaCommandArgument(cmdStr); priv->metaCommandMap[cmdStr].append(ArgLocPair(arg,location())); if (possibleTopics.contains(cmdStr)) { - priv->topics.append(Topic(cmdStr,arg)); + priv->topics_.append(Topic(cmdStr,arg)); } } else if (macroHash()->contains(cmdStr)) { @@ -1669,29 +1661,6 @@ QString DocParser::detailsUnknownCommand(const QSet<QString> &metaCommandSet, return tr("Maybe you meant '\\%1'?").arg(best); } -void DocParser::insertBaseName(const QString &baseName) -{ - priv->constructExtra(); - if (currentSection == priv->extra->section) { - priv->extra->baseName = baseName; - } - else { - Atom *atom = priv->text.firstAtom(); - Atom *sectionLeft = 0; - - int delta = currentSection - priv->extra->section; - - while (atom != 0) { - if (atom->type() == Atom::SectionLeft && - atom->string().toInt() == delta) - sectionLeft = atom; - atom = atom->next(); - } - if (sectionLeft != 0) - (void) new Atom(sectionLeft, Atom::BaseName, baseName); - } -} - void DocParser::insertTarget(const QString &target, bool keyword) { if (targetMap.contains(target)) { @@ -2751,6 +2720,7 @@ QString DocParser::slashed(const QString& str) #define COMMAND_BRIEF Doc::alias("brief") #define COMMAND_QMLBRIEF Doc::alias("qmlbrief") +#if 0 Doc::Doc(const Location& start_loc, const Location& end_loc, const QString& source, @@ -2760,6 +2730,7 @@ Doc::Doc(const Location& start_loc, DocParser parser; parser.parse(source,priv,metaCommandSet,QSet<QString>()); } +#endif /*! Parse the qdoc comment \a source. Build up a list of all the topic @@ -2978,17 +2949,6 @@ Text Doc::legaleseText() const return body().subText(Atom::LegaleseLeft, Atom::LegaleseRight); } -const QString& Doc::baseName() const -{ - static QString null; - if (priv == 0 || priv->extra == 0) { - return null; - } - else { - return priv->extra->baseName; - } -} - Doc::Sections Doc::granularity() const { if (priv == 0 || priv->extra == 0) { @@ -3026,7 +2986,7 @@ const QSet<QString> &Doc::metaCommandsUsed() const */ const TopicList& Doc::topicsUsed() const { - return priv == 0 ? *nullTopicList() : priv->topics; + return priv == 0 ? *nullTopicList() : priv->topics_; } ArgList Doc::metaCommandArgs(const QString& metacommand) const diff --git a/src/tools/qdoc/doc.h b/src/tools/qdoc/doc.h index ca9787595f..bd3d623a05 100644 --- a/src/tools/qdoc/doc.h +++ b/src/tools/qdoc/doc.h @@ -71,7 +71,10 @@ struct Topic { QString topic; QString args; + Topic() { } Topic(QString& t, QString a) : topic(t), args(a) { } + bool isEmpty() const { return topic.isEmpty(); } + void clear() { topic.clear(); args.clear(); } }; typedef QList<Topic> TopicList; @@ -136,10 +139,6 @@ public: }; Doc() : priv(0) {} - Doc(const Location &start_loc, - const Location &end_loc, - const QString &source, - const QSet<QString> &metaCommandSet); Doc(const Location& start_loc, const Location& end_loc, const QString& source, @@ -165,7 +164,6 @@ public: Text briefText(bool inclusive = false) const; Text trimmedBriefText(const QString &className) const; Text legaleseText() const; - const QString& baseName() const; Sections granularity() const; const QSet<QString> ¶meterNames() const; const QStringList &enumItemNames() const; @@ -196,6 +194,7 @@ private: void detach(); DocPrivate *priv; }; +typedef QList<Doc> DocList; QT_END_NAMESPACE diff --git a/src/tools/qdoc/doc/config/qdoc.qdocconf b/src/tools/qdoc/doc/config/qdoc.qdocconf index a7fbb38463..a6ae18a675 100644 --- a/src/tools/qdoc/doc/config/qdoc.qdocconf +++ b/src/tools/qdoc/doc/config/qdoc.qdocconf @@ -70,3 +70,5 @@ depends += \ qtwebkitexamples \ qtxml \ qtxmlpatterns + +navigation.landingpage = "QDoc Manual" diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index 889f0f55ca..f8d4910c28 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -97,7 +97,9 @@ QStringList Generator::styleDirs; QStringList Generator::styleFiles; bool Generator::debugging_ = false; bool Generator::noLinkErrors_ = false; +bool Generator::redirectDocumentationToDevNull_ = false; Generator::Passes Generator::qdocPass_ = Both; +bool Generator::useOutputSubdirs_ = true; void Generator::setDebugSegfaultFlag(bool b) { @@ -263,14 +265,17 @@ void Generator::writeOutFileNames() void Generator::beginSubPage(const InnerNode* node, const QString& fileName) { QString path = outputDir() + QLatin1Char('/'); - if (!node->outputSubdirectory().isEmpty()) + if (Generator::useOutputSubdirs() && !node->outputSubdirectory().isEmpty()) path += node->outputSubdirectory() + QLatin1Char('/'); path += fileName; - Generator::debugSegfault("Writing: " + path); - outFileNames.insert(fileName,fileName); - QFile* outFile = new QFile(path); + + QFile* outFile = new QFile(redirectDocumentationToDevNull_ ? QStringLiteral("/dev/null") : path); + if (outFile->exists()) + node->location().error(tr("HTML file already exists; overwriting %1").arg(outFile->fileName())); if (!outFile->open(QFile::WriteOnly)) node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName())); + Generator::debugSegfault("Writing: " + path); + outFileNames.insert(fileName,fileName); QTextStream* out = new QTextStream(outFile); #ifndef QT_NO_TEXTCODEC @@ -299,14 +304,22 @@ QString Generator::fileBase(const Node *node) const node = node->relates(); else if (!node->isInnerNode()) node = node->parent(); - if (node->subType() == Node::QmlPropertyGroup) { + if (node->type() == Node::QmlPropertyGroup) { node = node->parent(); } - QString base = node->doc().baseName(); - if (!base.isEmpty()) - return base; + if (node->type() == Node::Document && node->subType() == Node::Collision) { + const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(node); + if (ncn->currentChild()) + return fileBase(ncn->currentChild()); + } + + if (node->hasBaseName()) { + //qDebug() << "RETURNING:" << node->baseName(); + return node->baseName(); + } + QString base; const Node *p = node; forever { @@ -375,6 +388,8 @@ QString Generator::fileBase(const Node *node) const } while (res.endsWith(QLatin1Char('-'))) res.chop(1); + Node* n = const_cast<Node*>(node); + n->setBaseName(res); return res; } @@ -407,7 +422,7 @@ QMap<QString, QString>& Generator::formattingRightMap() /*! Returns the full document location. */ -QString Generator::fullDocumentLocation(const Node *node, bool subdir) +QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) { if (!node) return QString(); @@ -419,11 +434,11 @@ QString Generator::fullDocumentLocation(const Node *node, bool subdir) QString fdl; /* - If the output is being sent to subdirectories of the - output directory, and if the subdir parameter is set, - prepend the subdirectory name + '/' to the result. + If the useSubdir parameter is set, then the output is + being sent to subdirectories of the output directory. + Prepend the subdirectory name + '/' to the result. */ - if (subdir) { + if (useSubdir) { fdl = node->outputSubdirectory(); if (!fdl.isEmpty()) fdl.append(QLatin1Char('/')); @@ -467,7 +482,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool subdir) parentName = fullDocumentLocation(node->relates()); } else if ((parentNode = node->parent())) { - if (parentNode->subType() == Node::QmlPropertyGroup) { + if (parentNode->type() == Node::QmlPropertyGroup) { parentNode = parentNode->parent(); parentName = fullDocumentLocation(parentNode); } @@ -933,6 +948,8 @@ void Generator::generateInnerNode(InnerNode* node) { if (!node->url().isNull()) return; + if (node->isIndexNode()) + return; if (node->type() == Node::Document) { DocNode* docNode = static_cast<DocNode*>(node); @@ -940,13 +957,13 @@ void Generator::generateInnerNode(InnerNode* node) return; if (docNode->subType() == Node::Image) return; - if (docNode->subType() == Node::QmlPropertyGroup) - return; if (docNode->subType() == Node::Page) { if (node->count() > 0) qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title())); } } + else if (node->type() == Node::QmlPropertyGroup) + return; /* Obtain a code marker for the source file. @@ -1099,7 +1116,10 @@ void Generator::generateSince(const Node *node, CodeMarker *marker) if (project.isEmpty()) text << "version"; else - text << project; + text << Atom(Atom::Link, project) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, project) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); text << " " << since[0]; } else { // Reconstruct the <project> <version> string. @@ -1474,7 +1494,12 @@ QString Generator::indent(int level, const QString& markedCode) void Generator::initialize(const Config &config) { + + if (config.getBool(QString("HTML.nosubdirs"))) + resetUseOutputSubdirs(); + outputFormats = config.getOutputFormats(); + redirectDocumentationToDevNull_ = config.getBool(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL); if (!outputFormats.isEmpty()) { outDir_ = config.getOutputDir(); if (outDir_.isEmpty()) { @@ -1487,7 +1512,7 @@ void Generator::initialize(const Config &config) QDir dirInfo; if (dirInfo.exists(outDir_)) { - if (!runGenerateOnly()) { + if (!runGenerateOnly() && Generator::useOutputSubdirs()) { if (!Config::removeDirContents(outDir_)) config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir_)); } @@ -1907,8 +1932,6 @@ QString Generator::typeString(const Node *node) switch (node->subType()) { case Node::QmlClass: return "type"; - case Node::QmlPropertyGroup: - return "property group"; case Node::QmlBasicType: return "type"; default: @@ -1923,6 +1946,16 @@ QString Generator::typeString(const Node *node) return "function"; case Node::Property: return "property"; + case Node::QmlPropertyGroup: + return "property group"; + case Node::QmlProperty: + return "QML property"; + case Node::QmlSignal: + return "QML signal"; + case Node::QmlSignalHandler: + return "QML signal handler"; + case Node::QmlMethod: + return "QML method"; default: return "documentation"; } diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h index 58e9073922..52d73e8dea 100644 --- a/src/tools/qdoc/generator.h +++ b/src/tools/qdoc/generator.h @@ -81,7 +81,7 @@ public: virtual void initializeGenerator(const Config &config); virtual void terminateGenerator(); - QString fullDocumentLocation(const Node *node, bool subdir = false); + QString fullDocumentLocation(const Node *node, bool useSubdir = false); const Config* config() { return config_; } static Generator *currentGenerator() { return currentGenerator_; } @@ -100,6 +100,8 @@ public: static bool runPrepareOnly() { return (qdocPass_ == Prepare); } static bool runGenerateOnly() { return (qdocPass_ == Generate); } static QString defaultModuleName() { return project; } + static void resetUseOutputSubdirs() { useOutputSubdirs_ = false; } + static bool useOutputSubdirs() { return useOutputSubdirs_; } protected: virtual void beginSubPage(const InnerNode* node, const QString& fileName); @@ -185,6 +187,17 @@ protected: QString tagFile_; QStack<QTextStream*> outStreamStack; + void appendFullName(Text& text, + const Node *apparentNode, + const Node *relative, + const Node *actualNode = 0); + void appendFullName(Text& text, + const Node *apparentNode, + const QString& fullName, + const Node *actualNode); + void appendFullNames(Text& text, const NodeList& nodes, const Node* relative); + void appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes); + private: static Generator* currentGenerator_; static QStringList exampleDirs; @@ -206,18 +219,10 @@ private: static QStringList styleFiles; static bool debugging_; static bool noLinkErrors_; + static bool redirectDocumentationToDevNull_; static Passes qdocPass_; + static bool useOutputSubdirs_; - void appendFullName(Text& text, - const Node *apparentNode, - const Node *relative, - const Node *actualNode = 0); - void appendFullName(Text& text, - const Node *apparentNode, - const QString& fullName, - const Node *actualNode); - void appendFullNames(Text& text, const NodeList& nodes, const Node* relative); - void appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes); void generateReimplementedFrom(const FunctionNode *func, CodeMarker *marker); QString amp; diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp index 0cdb2de776..44292f84bb 100644 --- a/src/tools/qdoc/helpprojectwriter.cpp +++ b/src/tools/qdoc/helpprojectwriter.cpp @@ -135,6 +135,7 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["qmlsignal"] = Node::QmlSignal; typeHash["qmlsignalhandler"] = Node::QmlSignalHandler; typeHash["qmlmethod"] = Node::QmlMethod; + typeHash["qmlpropertygroup"] = Node::QmlPropertyGroup; QHash<QString, Node::SubType> subTypeHash; subTypeHash["example"] = Node::Example; @@ -145,7 +146,6 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList subTypeHash["page"] = Node::Page; subTypeHash["externalpage"] = Node::ExternalPage; subTypeHash["qmlclass"] = Node::QmlClass; - subTypeHash["qmlpropertygroup"] = Node::QmlPropertyGroup; subTypeHash["qmlbasictype"] = Node::QmlBasicType; QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values()); @@ -225,7 +225,7 @@ QStringList HelpProjectWriter::keywordDetails(const Node *node) const details << node->name(); details << node->name(); } - details << gen_->fullDocumentLocation(node,true); + details << gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); return details; } @@ -285,12 +285,12 @@ bool HelpProjectWriter::generateSection(HelpProject &project, case Node::Class: project.keywords.append(keywordDetails(node)); - project.files.insert(gen_->fullDocumentLocation(node,true)); + project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); break; case Node::Namespace: project.keywords.append(keywordDetails(node)); - project.files.insert(gen_->fullDocumentLocation(node,true)); + project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); break; case Node::Enum: @@ -310,7 +310,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, details << item.name(); // "name" details << item.name(); // "id" } - details << gen_->fullDocumentLocation(node,true); + details << gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); project.keywords.append(details); } } @@ -342,7 +342,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, if (node->relates()) { project.memberStatus[node->relates()].insert(node->status()); - project.files.insert(gen_->fullDocumentLocation(node->relates(),true)); + project.files.insert(gen_->fullDocumentLocation(node->relates(),Generator::useOutputSubdirs())); } else if (node->parent()) project.memberStatus[node->parent()].insert(node->status()); } @@ -356,7 +356,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // Use the location of any associated enum node in preference // to that of the typedef. if (enumNode) - typedefDetails[2] = gen_->fullDocumentLocation(enumNode,true); + typedefDetails[2] = gen_->fullDocumentLocation(enumNode,Generator::useOutputSubdirs()); project.keywords.append(typedefDetails); } @@ -364,7 +364,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, case Node::Variable: { - QString location = gen_->fullDocumentLocation(node,true); + QString location = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); project.files.insert(location.left(location.lastIndexOf(QLatin1Char('#')))); project.keywords.append(keywordDetails(node)); } @@ -385,18 +385,18 @@ bool HelpProjectWriter::generateSection(HelpProject &project, QStringList details; details << keyword->string() << keyword->string() - << gen_->fullDocumentLocation(node,true) + + << gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()) + QLatin1Char('#') + Doc::canonicalTitle(keyword->string()); project.keywords.append(details); } else docNode->doc().location().warning( - tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node,true)) + tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())) ); } } project.keywords.append(keywordDetails(node)); } - project.files.insert(gen_->fullDocumentLocation(node,true)); + project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); } break; } @@ -422,6 +422,11 @@ bool HelpProjectWriter::generateSection(HelpProject &project, void HelpProjectWriter::generateSections(HelpProject &project, QXmlStreamWriter &writer, const Node *node) { + /* + Don't include index nodes in the help file. Or DITA map nodes. + */ + if (node->isIndexNode() || node->subType() == Node::DitaMap) + return; if (!generateSection(project, writer, node)) return; @@ -431,29 +436,40 @@ void HelpProjectWriter::generateSections(HelpProject &project, // Ensure that we don't visit nodes more than once. QMap<QString, const Node*> childMap; foreach (const Node *childNode, inner->childNodes()) { + if (childNode->isIndexNode()) + continue; + if (childNode->access() == Node::Private) continue; if (childNode->type() == Node::Document) { + childMap[static_cast<const DocNode *>(childNode)->fullTitle()] = childNode; + } + else if (childNode->type() == Node::QmlPropertyGroup) { /* Don't visit QML property group nodes, but visit their children, which are all QML property nodes. + + This is probably not correct anymore, + because The Qml Property Group is an + actual documented thing. */ - if (childNode->subType() == Node::QmlPropertyGroup) { - const InnerNode* inner = static_cast<const InnerNode*>(childNode); - foreach (const Node* n, inner->childNodes()) { - if (n->access() == Node::Private) - continue; - childMap[n->fullDocumentName()] = n; - } + const InnerNode* inner = static_cast<const InnerNode*>(childNode); + foreach (const Node* n, inner->childNodes()) { + if (n->access() == Node::Private) + continue; + childMap[n->fullDocumentName()] = n; } - else - childMap[static_cast<const DocNode *>(childNode)->fullTitle()] = childNode; } else { // Store member status of children project.memberStatus[node].insert(childNode->status()); + if (childNode->relates()) { + project.memberStatus[childNode->relates()].insert(childNode->status()); + project.files.insert(gen_->fullDocumentLocation(childNode->relates(), + Generator::useOutputSubdirs())); + } if (childNode->type() == Node::Function) { const FunctionNode *funcNode = static_cast<const FunctionNode *>(childNode); @@ -508,7 +524,7 @@ void HelpProjectWriter::writeSection(QXmlStreamWriter &writer, const QString &pa void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &writer, const Node *node, bool writeSections) { - QString href = gen_->fullDocumentLocation(node,true); + QString href = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); href = href.left(href.size()-5); if (href.isEmpty()) return; @@ -546,7 +562,7 @@ void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &write void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer, const Node *node) { - QString href = gen_->fullDocumentLocation(node,true); + QString href = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); QString objName = node->name(); switch (node->type()) { @@ -642,7 +658,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) node = qdb_->findNode(QStringList("index.html")); QString indexPath; if (node) - indexPath = gen_->fullDocumentLocation(node,true); + indexPath = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); else indexPath = "index.html"; writer.writeAttribute("ref", indexPath); @@ -685,7 +701,8 @@ void HelpProjectWriter::generateProject(HelpProject &project) const DocNode *page = qdb_->findDocNodeByTitle(atom->string()); writer.writeStartElement("section"); - QString indexPath = gen_->fullDocumentLocation(page,true); + QString indexPath = gen_->fullDocumentLocation(page, + Generator::useOutputSubdirs()); writer.writeAttribute("ref", indexPath); writer.writeAttribute("title", atom->string()); project.files.insert(indexPath); @@ -710,7 +727,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) if (!name.isEmpty()) { writer.writeStartElement("section"); - QString indexPath = gen_->fullDocumentLocation(qdb_->findDocNodeByTitle(subproject.indexTitle),true); + QString indexPath = gen_->fullDocumentLocation(qdb_->findDocNodeByTitle(subproject.indexTitle),Generator::useOutputSubdirs()); writer.writeAttribute("ref", indexPath); writer.writeAttribute("title", subproject.title); project.files.insert(indexPath); diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 7cb56974d5..f17e3adde8 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -166,9 +166,9 @@ void HtmlGenerator::initializeGenerator(const Config &config) pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_GENERATEMACREFS); - noBreadCrumbs = config.getBool(HtmlGenerator::format() + + noNavigationBar = config.getBool(HtmlGenerator::format() + Config::dot + - HTMLGENERATOR_NOBREADCRUMBS); + HTMLGENERATOR_NONAVIGATIONBAR); project = config.getString(CONFIG_PROJECT); @@ -229,6 +229,25 @@ void HtmlGenerator::initializeGenerator(const Config &config) examplesPath = config.getString(CONFIG_EXAMPLESINSTALLPATH); if (!examplesPath.isEmpty()) examplesPath += QLatin1Char('/'); + + //retrieve the config for the navigation bar + homepage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_HOMEPAGE); + + landingpage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_LANDINGPAGE); + + cppclassespage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_CPPCLASSESPAGE); + + qmltypespage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_QMLTYPESPAGE); + + buildversion = config.getString(CONFIG_BUILDVERSION); } /*! @@ -1095,8 +1114,6 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker) QList<Section> sections; QList<Section>::ConstIterator s; - ClassNode* classe = 0; - QString title; QString rawTitle; QString fullTitle; @@ -1106,7 +1123,6 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker) title = rawTitle + " Namespace"; } else if (inner->type() == Node::Class) { - classe = static_cast<ClassNode*>(inner); rawTitle = inner->plainName(); fullTitle = inner->plainFullName(); title = rawTitle + " Class"; @@ -1121,16 +1137,9 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker) generateTableOfContents(inner,marker,§ions); generateTitle(title, subtitleText, SmallSubTitle, inner, marker); generateBrief(inner, marker); - generateIncludes(inner, marker); + generateRequisites(inner, marker); generateStatus(inner, marker); - if (classe) { - generateInherits(classe, marker); - generateInheritedBy(classe, marker); - if (classe->qmlElement() != 0) - generateInstantiatedBy(classe,marker); - } generateThreadSafeness(inner, marker); - generateSince(inner, marker); out() << "<ul>\n"; @@ -1511,10 +1520,7 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker) const_cast<DocNode*>(dn)->setCurrentChild(); ClassNode* cn = qml_cn->classNode(); generateBrief(qml_cn, marker); - generateQmlInherits(qml_cn, marker); - generateQmlInheritedBy(qml_cn, marker); - generateQmlInstantiates(qml_cn, marker); - generateSince(qml_cn, marker); + generateQmlRequisites(qml_cn, marker); QString allQmlMembersLink = generateAllQmlMembersFile(qml_cn, marker); if (!allQmlMembersLink.isEmpty()) { @@ -1616,129 +1622,67 @@ QString HtmlGenerator::fileExtension() const } /*! - Output breadcrumb list in the html file. + Output navigation list in the html file. */ -void HtmlGenerator::generateBreadCrumbs(const QString &title, +void HtmlGenerator::generateNavigationBar(const QString &title, const Node *node, CodeMarker *marker) { - if (noBreadCrumbs) + if (noNavigationBar) return; - Text breadcrumbs; + Text navigationbar; + + if (homepage == title) + return; + if (!homepage.isEmpty()) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::AutoLink, homepage) + << Atom(Atom::ListItemRight); + if (!landingpage.isEmpty() && landingpage != title) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::AutoLink, landingpage) + << Atom(Atom::ListItemRight); + if (node->type() == Node::Class) { const ClassNode *cn = static_cast<const ClassNode *>(node); QString name = node->moduleName(); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("All Modules")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Modules")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - if (!name.isEmpty()) - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, name) + + if (!cppclassespage.isEmpty()) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::Link, cppclassespage) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, QLatin1String("C++ Classes")) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(Atom::ListItemRight); + if (!cn->name().isEmpty()) - breadcrumbs << Atom(Atom::ListItemLeft) + navigationbar << Atom(Atom::ListItemLeft) << Atom(Atom::String, protectEnc(cn->name())) << Atom(Atom::ListItemRight); } else if (node->type() == Node::Document) { - const DocNode* fn = static_cast<const DocNode*>(node); - if (node->subType() == Node::Module) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("All Modules")) + if (node->subType() == Node::QmlClass || node->subType() == Node::QmlBasicType) { + if (!qmltypespage.isEmpty()) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::Link, qmltypespage) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Modules")) + << Atom(Atom::String, QLatin1String("QML Types")) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(Atom::ListItemRight); - QString name = node->name(); - if (!name.isEmpty()) - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(name)) - << Atom(Atom::ListItemRight); - } - else if (node->subType() == Node::Group) { - if (fn->name() == QString("modules")) - breadcrumbs << Atom(Atom::String, QLatin1String("Modules")); - else - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - else if (node->subType() == Node::Page) { - if (fn->name() == QString("qdeclarativeexamples.html")) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("Qt Examples")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Examples")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, QLatin1String("QML Examples & Demos")) - << Atom(Atom::ListItemRight); - } - else if (fn->name().startsWith("examples-")) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("Qt Examples")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Examples")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - else if (fn->name() == QString("namespaces.html")) - breadcrumbs << Atom(Atom::String, QLatin1String("Namespaces")); - else - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - else if (node->subType() == Node::QmlClass) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, QLatin1String("Basic QML Types")) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) + + navigationbar << Atom(Atom::ListItemLeft) << Atom(Atom::String, protectEnc(title)) << Atom(Atom::ListItemRight); } - else if (node->subType() == Node::Example) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("Qt Examples")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Examples")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - QStringList sl = fn->name().split('/'); - if (sl.contains("declarative")) - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, QLatin1String("QML Examples & Demos")) - << Atom(Atom::ListItemRight); - else { - QString name = protectEnc("examples-" + sl.at(0) + ".html"); // this generates an empty link - QString t = CodeParser::titleFromName(name); - } - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); + else { + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::String, protectEnc(title)) + << Atom(Atom::ListItemRight); } } - else if (node->type() == Node::Namespace) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("All Namespaces")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Namespaces")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - generateText(breadcrumbs, node, marker); + generateText(navigationbar, node, marker); } void HtmlGenerator::generateHeader(const QString& title, @@ -1782,7 +1726,8 @@ void HtmlGenerator::generateHeader(const QString& title, #endif out() << QString(postHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); - generateBreadCrumbs(title,node,marker); + generateNavigationBar(title,node,marker); + out() << "<li id=\"buildversion\">\n" << buildversion << "</li>\n"; out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); navigationLinks.clear(); @@ -1881,6 +1826,271 @@ void HtmlGenerator::generateFooter(const Node *node) out() << "</html>\n"; } +/*! +Lists the required imports and includes in a table. +The number of rows is known, so this path is simpler than the generateSection() path. +*/ +void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker) +{ + QMap<QString, Text> requisites; + Text text; + + const QString headerText = "Header"; + const QString sinceText = "Since"; + const QString inheritedBytext = "Inherited By"; + const QString inheritsText = "Inherits"; + const QString instantiatedByText = "Instantiated By"; + const QString qtVariableText = "qmake"; + + //add the includes to the map + if (!inner->includes().isEmpty()) { + text.clear(); + text << formattingRightMap()[ATOM_FORMATTING_BOLD] + << formattingLeftMap()[ATOM_FORMATTING_TELETYPE] + << highlightedCode(indent(codeIndent, + marker->markedUpIncludes(inner->includes())), + inner) + << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; + requisites.insert(headerText, text); + } + + //The order of the requisites matter + QStringList requisiteorder; + requisiteorder << headerText + << qtVariableText + << sinceText + << instantiatedByText + << inheritsText + << inheritedBytext; + + //add the since and project into the map + if (!inner->since().isEmpty()) { + text.clear(); + QStringList since = inner->since().split(QLatin1Char(' ')); + if (since.count() == 1) { + // Handle legacy use of \since <version>. + if (project.isEmpty()) + text << "version"; + else + text << Atom(Atom::Link, project) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, project) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " " << since[0]; + } + else { + // Reconstruct the <project> <version> string. + text << " " << since.join(' '); + } + text << Atom::ParaRight; + requisites.insert(sinceText, text); + } + + //add the instantiated-by to the map if the class node is not internal + if (inner->type() == Node::Class) { + ClassNode* classe = static_cast<ClassNode*>(inner); + if (classe->qmlElement() != 0 && classe->status() != Node::Internal) { + text.clear(); + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(classe->qmlElement())) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, classe->qmlElement()->name()) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + requisites.insert(instantiatedByText, text); + + } + + //add the inherits to the map + QList<RelatedClass>::ConstIterator r; + int index; + if (!classe->baseClasses().isEmpty()) { + text.clear(); + r = classe->baseClasses().constBegin(); + index = 0; + while (r != classe->baseClasses().constEnd()) { + text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, (*r).dataTypeWithTemplateArgs) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + if ((*r).access == Node::Protected) { + text << " (protected)"; + } + else if ((*r).access == Node::Private) { + text << " (private)"; + } + text << separator(index++, classe->baseClasses().count()); + ++r; + } + text << Atom::ParaRight; + requisites.insert(inheritsText, text); + } + + //add the inherited-by to the map + if (!classe->derivedClasses().isEmpty()) { + text.clear(); + text << Atom::ParaLeft; + appendSortedNames(text, classe, classe->derivedClasses()); + text << Atom::ParaRight; + requisites.insert(inheritedBytext, text); + } + + //add the QT variable to the map + DocNode * moduleNode = qdb_->findModule(classe->moduleName()); + if (moduleNode && !moduleNode->qtVariable().isEmpty()) { + text.clear(); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_TELETYPE) + << "QT += " + moduleNode->qtVariable() + << Atom(Atom::FormattingRight, ATOM_FORMATTING_TELETYPE); + requisites.insert(qtVariableText, text); + } + + } + + if (!requisites.isEmpty()) { + //generate the table + out() << "<table class=\"alignedsummary\">\n"; + + QStringList::ConstIterator i; + for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { + + if (requisites.contains(*i)) { + out() << "<tr>" + << "<td class=\"memItemLeft rightAlign topAlign\"> " + << *i << ":" + << "</td><td class=\"memItemRight bottomAlign\"> "; + + if (*i == headerText) + out() << requisites.value(*i).toString(); + else + generateText(requisites.value(*i), inner, marker); + out() << "</td></tr>"; + } + } + out() << "</table>"; + } +} + +/*! +Lists the required imports and includes in a table. +The number of rows is known, so this path is simpler than the generateSection() path. +*/ +void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker) +{ + if (!qcn) + return; + QMap<QString, Text> requisites; + Text text; + + const QString importText = "Import Statement:"; + const QString sinceText = "Since:"; + const QString inheritedBytext = "Inherited By:"; + const QString inheritsText = "Inherits:"; + const QString instantiatesText = "Instantiates:"; + + //The order of the requisites matter + QStringList requisiteorder; + requisiteorder << importText + << sinceText + << instantiatesText + << inheritsText + << inheritedBytext; + + //add the module name and version to the map + text.clear(); + text << formattingRightMap()[ATOM_FORMATTING_BOLD] + << formattingLeftMap()[ATOM_FORMATTING_TELETYPE] + << "import " + qcn->qmlModuleName() + " " + qcn->qmlModuleVersion() + << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; + requisites.insert(importText, text); + + //add the since and project into the map + if (!qcn->since().isEmpty()) { + text.clear(); + QStringList since = qcn->since().split(QLatin1Char(' ')); + if (since.count() == 1) { + // Handle legacy use of \since <version>. + if (project.isEmpty()) + text << "version"; + else + text << Atom(Atom::Link, project) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, project) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + text << " " << since[0]; + } + else { + // Reconstruct the <project> <version> string. + text << " " << since.join(' '); + } + text << Atom::ParaRight; + requisites.insert(sinceText, text); + } + + //add the instantiates to the map + ClassNode* cn = qcn->classNode(); + if (cn && (cn->status() != Node::Internal)) { + text.clear(); + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, cn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + requisites.insert(instantiatesText, text); + } + + //add the inherits to the map + const QmlClassNode* base = qcn->qmlBaseNode(); + while (base && base->isInternal()) { + base = base->qmlBaseNode(); + } + if (base) { + text.clear(); + text << Atom::ParaLeft + << Atom(Atom::LinkNode,CodeMarker::stringForNode(base)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, base->name()) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) + << Atom::ParaRight; + requisites.insert(inheritsText, text); + } + + //add the inherited-by to the map + NodeList subs; + QmlClassNode::subclasses(qcn->name(), subs); + if (!subs.isEmpty()) { + text.clear(); + text << Atom::ParaLeft; + appendSortedQmlNames(text, qcn, subs); + text << Atom::ParaRight; + requisites.insert(inheritedBytext, text); + } + + if (!requisites.isEmpty()) { + //generate the table + out() << "<table class=\"alignedsummary\">\n"; + + QStringList::ConstIterator i; + for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { + + if (requisites.contains(*i)) { + out() << "<tr>" + << "<td class=\"memItemLeft rightAlign topAlign\"> " + << *i + << "</td><td class=\"memItemRight bottomAlign\"> "; + + if (*i == importText) + out()<<requisites.value(*i).toString(); + else + generateText(requisites.value(*i), qcn, marker); + out() << "</td></tr>"; + } + } + out() << "</table>"; + } +} + void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, const Node *relative) { @@ -2151,7 +2361,10 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner, fileName = fileBase(inner) + "-obsolete." + fileExtension(); } if (status == CodeMarker::Obsolete) { - QString link = QString("../" + Generator::outputSubdir() + QLatin1Char('/')) + fileName; + QString link; + if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty()) + link = QString("../" + Generator::outputSubdir() + QLatin1Char('/')); + link += fileName; inner->setObsoleteLink(link); } @@ -2160,21 +2373,22 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner, generateTitle(title, Text(), SmallSubTitle, inner, marker); if (status == CodeMarker::Compat) { - out() << "<p><b>The following class members are part of the " + out() << "<p><b>The following members of class " + << "<a href=\"" << linkForNode(inner, 0) << "\">" + << protectEnc(inner->name()) << "</a>" + << "are part of the " "Qt compatibility layer.</b> We advise against " "using them in new code.</p>\n"; } else { - out() << "<p><b>The following class members are obsolete.</b> " + out() << "<p><b>The following members of class " + << "<a href=\"" << linkForNode(inner, 0) << "\">" + << protectEnc(inner->name()) << "</a>" + << " are obsolete.</b> " << "They are provided to keep old source code working. " << "We strongly advise against using them in new code.</p>\n"; } - out() << "<p><ul><li><a href=\"" - << linkForNode(inner, 0) << "\">" - << protectEnc(inner->name()) - << " class reference</a></li></ul></p>\n"; - for (i = 0; i < sections.size(); ++i) { out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); @@ -2492,8 +2706,10 @@ void HtmlGenerator::generateCompactList(ListType listType, } else if (listType == Obsolete) { QString fileName = fileBase(it.value()) + "-obsolete." + fileExtension(); - QString link = QString("../" + it.value()->outputSubdirectory() + - QLatin1Char('/')) + fileName; + QString link; + if (useOutputSubdirs()) + link = QString("../" + it.value()->outputSubdirectory() + QLatin1Char('/')); + link += fileName; out() << "<a href=\"" << link << "\">"; } @@ -3308,8 +3524,8 @@ QString HtmlGenerator::refForNode(const Node *node) } break; case Node::Document: - if (node->subType() != Node::QmlPropertyGroup) - break; + break; + case Node::QmlPropertyGroup: case Node::QmlProperty: case Node::Property: ref = node->name() + "-prop"; @@ -3372,7 +3588,7 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative) } QString link = fn; - if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) { + if (!node->isInnerNode() || node->type() == Node::QmlPropertyGroup) { QString ref = refForNode(node); if (relative && fn == fileName(relative) && ref == refForNode(relative)) return QString(); @@ -3387,7 +3603,7 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative) back down into the other subdirectory. */ if (node && relative && (node != relative)) { - if (node->outputSubdirectory() != relative->outputSubdirectory()) + if (useOutputSubdirs() && node->outputSubdirectory() != relative->outputSubdirectory()) link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/'))); } return link; @@ -3778,6 +3994,22 @@ void HtmlGenerator::generateQmlSummary(const Section& section, while (m != section.members.constEnd()) { out() << "<li class=\"fn\">"; generateQmlItem(*m,relative,marker,true); + if ((*m)->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(*m); + if (!qpgn->childNodes().isEmpty()) { + NodeList::ConstIterator p = qpgn->childNodes().constBegin(); + out() << "<ul>\n"; + while (p != qpgn->childNodes().constEnd()) { + if ((*p)->type() == Node::QmlProperty) { + out() << "<li class=\"fn\">"; + generateQmlItem(*p, relative, marker, true); + out() << "</li>\n"; + } + ++p; + } + out() << "</ul>\n"; + } + } out() << "</li>\n"; ++m; } @@ -3799,11 +4031,18 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, #endif generateExtractionMark(node, MemberMark); out() << "<div class=\"qmlitem\">"; - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); out() << "<div class=\"qmlproto\">"; out() << "<table class=\"qmlname\">"; + + QString heading = qpgn->name() + " group"; + out() << "<tr valign=\"top\" class=\"even\">"; + out() << "<th class=\"centerAlign\"><p>"; + out() << "<a name=\"" + refForNode(qpgn) + "\"></a>"; + out() << "<b>" << heading << "</b>"; + out() << "</p></th></tr>"; while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { qpn = static_cast<QmlPropertyNode*>(*p); @@ -3825,68 +4064,23 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, } else if (node->type() == Node::QmlProperty) { qpn = static_cast<QmlPropertyNode*>(node); - /* - If the QML property node has a single subproperty, - override, replace qpn with that override node and - proceed as normal. - */ - if (qpn->qmlPropNodes().size() == 1) { - Node* n = qpn->qmlPropNodes().at(0); - if (n->type() == Node::QmlProperty) - qpn = static_cast<QmlPropertyNode*>(n); - } - /* - Now qpn either has no overrides, or it has more - than 1. If it has none, proceed to output as nortmal. - */ - if (qpn->qmlPropNodes().isEmpty()) { - out() << "<div class=\"qmlproto\">"; - out() << "<table class=\"qmlname\">"; - out() << "<tr valign=\"top\" class=\"odd\">"; - out() << "<td class=\"tblQmlPropNode\"><p>"; - out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; - if (!qpn->isReadOnlySet()) { - if (qpn->declarativeCppNode()) - qpn->setReadOnly(!qpn->isWritable(qdb_)); - } - if (qpn->isReadOnly()) - out() << "<span class=\"qmlreadonly\">read-only</span>"; - if (qpn->isDefault()) - out() << "<span class=\"qmldefault\">default</span>"; - generateQmlItem(qpn, relative, marker, false); - out() << "</p></td></tr>"; - out() << "</table>"; - out() << "</div>"; - } - else { - /* - The QML property node has multiple override nodes. - Process the whole list as we would for a QML property - group. - */ - NodeList::ConstIterator p = qpn->qmlPropNodes().constBegin(); - out() << "<div class=\"qmlproto\">"; - out() << "<table class=\"qmlname\">"; - while (p != qpn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - QmlPropertyNode* q = static_cast<QmlPropertyNode*>(*p); - out() << "<tr valign=\"top\" class=\"odd\">"; - out() << "<td class=\"tblQmlPropNode\"><p>"; - out() << "<a name=\"" + refForNode(q) + "\"></a>"; - if (!qpn->isReadOnlySet()) - qpn->setReadOnly(!qpn->isWritable(qdb_)); - if (qpn->isReadOnly()) - out() << "<span class=\"qmlreadonly\">read-only</span>"; - if (qpn->isDefault()) - out() << "<span class=\"qmldefault\">default</span>"; - generateQmlItem(q, relative, marker, false); - out() << "</p></td></tr>"; - } - ++p; - } - out() << "</table>"; - out() << "</div>"; - } + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr valign=\"top\" class=\"odd\">"; + out() << "<td class=\"tblQmlPropNode\"><p>"; + out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; + if (!qpn->isReadOnlySet()) { + if (qpn->declarativeCppNode()) + qpn->setReadOnly(!qpn->isWritable(qdb_)); + } + if (qpn->isReadOnly()) + out() << "<span class=\"qmlreadonly\">read-only</span>"; + if (qpn->isDefault()) + out() << "<span class=\"qmldefault\">default</span>"; + generateQmlItem(qpn, relative, marker, false); + out() << "</p></td></tr>"; + out() << "</table>"; + out() << "</div>"; } else if (node->type() == Node::QmlSignal) { const FunctionNode* qsn = static_cast<const FunctionNode*>(node); @@ -4359,8 +4553,6 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent) break; case Node::QmlClass: break; - case Node::QmlPropertyGroup: - break; case Node::QmlBasicType: break; case Node::QmlModule: @@ -4394,6 +4586,8 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent) if (!related) child->location().warning(tr("Global variable, %1, %2").arg(child->name()).arg(message)); break; + case Node::QmlPropertyGroup: + break; case Node::QmlProperty: if (!related) child->location().warning(tr("Global QML property, %1, %2").arg(child->name()).arg(message)); diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h index 0a6717461e..8cd8664dfc 100644 --- a/src/tools/qdoc/htmlgenerator.h +++ b/src/tools/qdoc/htmlgenerator.h @@ -127,7 +127,7 @@ private: }; const QPair<QString,QString> anchorForNode(const Node *node); - void generateBreadCrumbs(const QString& title, + void generateNavigationBar(const QString& title, const Node *node, CodeMarker *marker); void generateHeader(const QString& title, @@ -139,6 +139,10 @@ private: const Node *relative, CodeMarker *marker); void generateFooter(const Node *node = 0); + void generateRequisites(InnerNode *inner, + CodeMarker *marker); + void generateQmlRequisites(QmlClassNode *qcn, + CodeMarker *marker); void generateBrief(const Node *node, CodeMarker *marker, const Node *relative = 0); @@ -182,6 +186,7 @@ private: void generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker); void generateInstantiatedBy(ClassNode* cn, CodeMarker* marker); + void generateRequisitesTable(const QStringList& requisitesOrder, QMap<QString, Text>& requisites); void generateSection(const NodeList& nl, const Node *relative, CodeMarker *marker, @@ -239,7 +244,7 @@ private: QString footer; QString address; bool pleaseGenerateMacRef; - bool noBreadCrumbs; + bool noNavigationBar; QString project; QString projectDescription; QString projectUrl; @@ -252,6 +257,12 @@ private: QStack<QXmlStreamWriter*> xmlWriterStack; static int id; QList<ManifestMetaFilter> manifestMetaContent; + QString homepage; + QString landingpage; + QString cppclassespage; + QString qmltypespage; + QString buildversion; + public: static bool debugging_on; static QString divNavTop; @@ -262,9 +273,10 @@ public: #define HTMLGENERATOR_GENERATEMACREFS "generatemacrefs" // ### document me #define HTMLGENERATOR_POSTHEADER "postheader" #define HTMLGENERATOR_POSTPOSTHEADER "postpostheader" -#define HTMLGENERATOR_NOBREADCRUMBS "nobreadcrumbs" +#define HTMLGENERATOR_NONAVIGATIONBAR "nonavigationbar" +#define HTMLGENERATOR_NOSUBDIRS "nosubdirs" + QT_END_NAMESPACE #endif - diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp index 3ec121f795..912cdad7eb 100644 --- a/src/tools/qdoc/main.cpp +++ b/src/tools/qdoc/main.cpp @@ -95,6 +95,7 @@ bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2) static bool highlighting = false; static bool showInternal = false; +static bool redirectDocumentationToDevNull = false; static bool noLinkErrors = false; static bool obsoleteLinks = false; static QStringList defines; @@ -139,6 +140,8 @@ static void printHelp() "Run qdoc to read the index files and generate the docs\n" " -showinternal " "Include content marked internal\n" + " -redirect-documentation-to-dev-null " + "Save all documentation content to /dev/null. Useful if someone is interested in qdoc errors only.\n" " -version " "Display version of qdoc and exit\n") ); } @@ -162,6 +165,15 @@ static void loadIndexFiles(Config& config) dependModules += config.getStringList(CONFIG_DEPENDS); + bool noOutputSubdirs = false; + QString singleOutputSubdir; + if (config.getBool(QString("HTML.nosubdirs"))) { + noOutputSubdirs = true; + singleOutputSubdir = config.getString("HTML.outputsubdir"); + if (singleOutputSubdir.isEmpty()) + singleOutputSubdir = "html"; + } + // Allow modules and third-party application/libraries to link // to the Qt docs without having to explicitly pass --indexdir. if (!indexDirs.contains(documentationPath)) @@ -196,8 +208,12 @@ static void loadIndexFiles(Config& config) QString indexToAdd; QList<QFileInfo> foundIndices; for (int j = 0; j < indexDirs.size(); j++) { - QString fileToLookFor = indexDirs[j] + QLatin1Char('/') + dependModules[i] + - QLatin1Char('/') + dependModules[i] + QLatin1String(".index"); + QString fileToLookFor = indexDirs[j] + QLatin1Char('/'); + if (noOutputSubdirs) + fileToLookFor += singleOutputSubdir + QLatin1Char('/'); + else + fileToLookFor += dependModules[i] + QLatin1Char('/'); + fileToLookFor += dependModules[i] + QLatin1String(".index"); if (QFile::exists(fileToLookFor)) { QFileInfo tempFileInfo(fileToLookFor); if (!foundIndices.contains(tempFileInfo)) @@ -257,6 +273,7 @@ static void processQdocconfFile(const QString &fileName) } config.setStringList(CONFIG_SYNTAXHIGHLIGHTING, QStringList(highlighting ? "true" : "false")); config.setStringList(CONFIG_SHOWINTERNAL, QStringList(showInternal ? "true" : "false")); + config.setStringList(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, QStringList(redirectDocumentationToDevNull ? "true" : "false")); config.setStringList(CONFIG_NOLINKERRORS, QStringList(noLinkErrors ? "true" : "false")); config.setStringList(CONFIG_OBSOLETELINKS, QStringList(obsoleteLinks ? "true" : "false")); @@ -573,6 +590,9 @@ int main(int argc, char **argv) else if (opt == "-showinternal") { showInternal = true; } + else if (opt == "-redirect-documentation-to-dev-null") { + redirectDocumentationToDevNull = true; + } else if (opt == "-no-examples") { Config::generateExamples = false; } diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index 2184e302ae..fd56c77742 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -151,11 +151,11 @@ QString Node::fullName(const Node* relative) const */ void Node::setDoc(const Doc& doc, bool replace) { - if (!d.isEmpty() && !replace) { + if (!doc_.isEmpty() && !replace) { doc.location().warning(tr("Overrides a previous doc")); - d.location().warning(tr("(The previous doc is here)")); + doc_.location().warning(tr("(The previous doc is here)")); } - d = doc; + doc_ = doc; } /*! @@ -311,6 +311,8 @@ QString Node::nodeTypeString(unsigned t) return "variable"; case QmlProperty: return "QML property"; + case QmlPropertyGroup: + return "QML property group"; case QmlSignal: return "QML signal"; case QmlSignalHandler: @@ -359,8 +361,6 @@ QString Node::nodeSubtypeString(unsigned t) return "external page"; case QmlClass: return "QML type"; - case QmlPropertyGroup: - return "QML property group"; case QmlBasicType: return "QML basic type"; case QmlModule: @@ -742,12 +742,12 @@ void InnerNode::getMemberClasses(NodeMap& out) Node *InnerNode::findChildNodeByName(const QString& name) { Node *node = childMap.value(name); - if (node && node->subType() != QmlPropertyGroup) + if (node && node->type() != QmlPropertyGroup) return node; if ((type() == Document) && (subType() == QmlClass)) { for (int i=0; i<children_.size(); ++i) { Node* n = children_.at(i); - if (n->subType() == QmlPropertyGroup) { + if (n->type() == QmlPropertyGroup) { node = static_cast<InnerNode*>(n)->findChildNodeByName(name); if (node) return node; @@ -771,7 +771,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n) if ((type() == Document) && (subType() == QmlClass)) { for (int i=0; i<children_.size(); ++i) { node = children_.at(i); - if (node->subType() == QmlPropertyGroup) { + if (node->type() == QmlPropertyGroup) { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); if (node) { n.append(node); @@ -793,7 +793,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n) */ for (int i=0; i<nodes.size(); ++i) { node = nodes.at(i); - if (node->subType() != QmlPropertyGroup) + if (node->type() != QmlPropertyGroup) n.append(node); else { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); @@ -829,14 +829,14 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml) if (!node->isQmlNode()) return node; } - else if (node->isQmlNode() && (node->subType() != QmlPropertyGroup)) + else if (node->isQmlNode() && (node->type() != QmlPropertyGroup)) return node; } } if (qml && (type() == Document) && (subType() == QmlClass)) { for (int i=0; i<children_.size(); ++i) { Node* node = children_.at(i); - if (node->subType() == QmlPropertyGroup) { + if (node->type() == QmlPropertyGroup) { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); if (node) return node; @@ -1371,6 +1371,26 @@ void InnerNode::removeRelated(Node *pseudoChild) } /*! + If this node has a child that is a QML property named \a n, + return the pointer to that child. + */ +QmlPropertyNode* InnerNode::hasQmlProperty(const QString& n) const +{ + foreach (Node* child, childNodes()) { + if (child->type() == Node::QmlProperty) { + if (child->name() == n) + return static_cast<QmlPropertyNode*>(child); + } + else if (child->type() == Node::QmlPropertyGroup) { + QmlPropertyNode* t = child->hasQmlProperty(n); + if (t) + return t; + } + } + return 0; +} + +/*! \class LeafNode */ @@ -1673,25 +1693,6 @@ QString DocNode::subTitle() const } /*! - Returns true if this QML type or property group contains a - property named \a name. - */ -bool DocNode::hasProperty(const QString& name) const -{ - foreach (Node* child, childNodes()) { - if (child->type() == Node::Document && child->subType() == Node::QmlPropertyGroup) { - if (child->hasProperty(name)) - return true; - } - else if (child->type() == Node::QmlProperty) { - if (child->hasProperty(name)) - return true; - } - } - return false; -} - -/*! The constructor calls the DocNode constructor with \a parent, \a name, and Node::Example. */ @@ -2273,8 +2274,8 @@ QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent, Constructor for the Qml property group node. \a parent is always a QmlClassNode. */ -QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name) - : DocNode(parent, name, QmlPropertyGroup, Node::ApiPage) +QmlPropertyGroupNode::QmlPropertyGroupNode(QmlClassNode* parent, const QString& name) + : InnerNode(QmlPropertyGroup, parent, name) { idNumber_ = -1; } @@ -2286,24 +2287,17 @@ QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name) property group count and set the id number to the new value. */ -QString QmlPropGroupNode::idNumber() +QString QmlPropertyGroupNode::idNumber() { if (idNumber_ == -1) idNumber_ = incPropertyGroupCount(); return QString().setNum(idNumber_); } - /*! - Constructor for the QML property node, when the \a parent - is QML property group node. This constructor is only used - for creating QML property nodes for QML elements, i.e. - not for creating QML property nodes for QML components. - Hopefully, this constructor will become obsolete, so don't - use it unless one of the other two constructors can't be - used. + Constructor for the QML property node. */ -QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent, +QmlPropertyNode::QmlPropertyNode(InnerNode* parent, const QString& name, const QString& type, bool attached) @@ -2311,56 +2305,14 @@ QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent, type_(type), stored_(FlagValueDefault), designable_(FlagValueDefault), + isAlias_(false), isdefault_(false), attached_(attached), readOnly_(FlagValueDefault) { setPageType(ApiPage); -} - -/*! - Constructor for the QML property node, when the \a parent - is a QML class node. - */ -QmlPropertyNode::QmlPropertyNode(QmlClassNode *parent, - const QString& name, - const QString& type, - bool attached) - : LeafNode(QmlProperty, parent, name), - type_(type), - stored_(FlagValueDefault), - designable_(FlagValueDefault), - isdefault_(false), - attached_(attached), - readOnly_(FlagValueDefault) -{ - setPageType(ApiPage); -} - -/*! - Constructor for the QML property node, when the \a parent - is a QML property node. Strictly speaking, this is not the - way QML property nodes were originally meant to be built, - because this constructor has another QML property node as - its parent. But this constructor is useful for documenting - QML properties in QML components, i.e., when you override - the definition of a property with the \e{qmlproperty} - command. It actually uses the parent of \a parent as the - parent. - */ -QmlPropertyNode::QmlPropertyNode(QmlPropertyNode* parent, - const QString& name, - const QString& type, - bool attached) - : LeafNode(parent->parent(), QmlProperty, name), - type_(type), - stored_(FlagValueDefault), - designable_(FlagValueDefault), - isdefault_(false), - attached_(attached), - readOnly_(FlagValueDefault) -{ - setPageType(ApiPage); + if (type_ == QString("alias")) + isAlias_ = true; } /*! @@ -2450,23 +2402,6 @@ PropertyNode* QmlPropertyNode::correspondingProperty(QDocDatabase* qdb) return 0; } -/*! - Returns true if this QML type or property group contains a - property named \a name. - */ -bool QmlPropertyNode::hasProperty(const QString& n) const -{ - if (name() == n) - return true; - foreach (Node* child, qmlPropNodes()) { - if (child->type() == Node::QmlProperty) { - if (child->name() == n) - return true; - } - } - return false; -} - /*! \class NameCollisionNode An instance of this node is inserted in the tree @@ -2586,11 +2521,10 @@ QString Node::fullDocumentName() const const Node* n = this; do { - if (!n->name().isEmpty() && - ((n->type() != Node::Document) || (n->subType() != Node::QmlPropertyGroup))) + if (!n->name().isEmpty() && n->type() != Node::QmlPropertyGroup) pieces.insert(0, n->name()); - if ((n->type() == Node::Document) && (n->subType() != Node::QmlPropertyGroup)) { + if (n->type() == Node::Document) { if ((n->subType() == Node::QmlClass) && !n->qmlModuleName().isEmpty()) pieces.insert(0, n->qmlModuleIdentifier()); break; @@ -2806,12 +2740,6 @@ QString Node::idForNode() const case Node::QmlClass: str = "qml-class-" + name(); break; - case Node::QmlPropertyGroup: - { - Node* n = const_cast<Node*>(this); - str = "qml-propertygroup-" + n->name(); - } - break; case Node::Page: case Node::Group: case Node::Module: @@ -2852,6 +2780,12 @@ QString Node::idForNode() const case Node::QmlProperty: str = "qml-property-" + name(); break; + case Node::QmlPropertyGroup: + { + Node* n = const_cast<Node*>(this); + str = "qml-propertygroup-" + n->name(); + } + break; case Node::Property: str = "property-" + name(); break; diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index bc75df2992..9c8950d185 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -60,6 +60,7 @@ class InnerNode; class ExampleNode; class QmlClassNode; class QDocDatabase; +class QmlPropertyNode; typedef QList<Node*> NodeList; typedef QMap<QString, Node*> NodeMap; @@ -80,6 +81,7 @@ public: Function, Property, Variable, + QmlPropertyGroup, QmlProperty, QmlSignal, QmlSignalHandler, @@ -98,7 +100,6 @@ public: Page, ExternalPage, QmlClass, - QmlPropertyGroup, QmlBasicType, QmlModule, DitaMap, @@ -163,7 +164,10 @@ public: QString plainName() const; QString plainFullName(const Node* relative = 0) const; QString fullName(const Node* relative=0) const; + const QString& baseName() const { return baseName_; } + bool hasBaseName() const { return !baseName_.isEmpty(); } + void setBaseName(const QString& bn) { baseName_ = bn; } void setAccess(Access access) { access_ = access; } void setLocation(const Location& location) { loc = location; } void setDoc(const Doc& doc, bool replace = false); @@ -200,8 +204,11 @@ public: virtual bool isQmlPropertyGroup() const { return false; } virtual bool isCollisionNode() const { return false; } virtual bool isAttached() const { return false; } + virtual bool isAlias() const { return false; } virtual bool isGroup() const { return false; } virtual bool isWrapper() const; + virtual bool isReadOnly() const { return false; } + virtual bool isDefault() const { return false; } virtual void addMember(Node* ) { } virtual bool hasMembers() const { return false; } virtual bool hasNamespaces() const { return false; } @@ -209,10 +216,12 @@ public: virtual void setAbstract(bool ) { } virtual void setWrapper() { } virtual QString title() const { return QString(); } - virtual bool hasProperty(const QString& ) const { return false; } + virtual QmlPropertyNode* hasQmlProperty(const QString& ) const { return 0; } virtual void getMemberNamespaces(NodeMap& ) { } virtual void getMemberClasses(NodeMap& ) { } virtual bool isInternal() const; + virtual void setDataType(const QString& ) { } + virtual void setReadOnly(bool ) { } bool isIndexNode() const { return indexNodeFlag_; } bool wasSeen() const { return seen_; } Type type() const { return nodeType_; } @@ -231,7 +240,7 @@ public: Access access() const { return access_; } QString accessString() const; const Location& location() const { return loc; } - const Doc& doc() const { return d; } + const Doc& doc() const { return doc_; } Status status() const { return status_; } Status inheritedStatus() const; ThreadSafeness threadSafeness() const; @@ -294,8 +303,9 @@ private: InnerNode* relatesTo_; QString name_; Location loc; - Doc d; + Doc doc_; QMap<LinkType, QPair<QString, QString> > linkMap_; + QString baseName_; QString moduleName_; QString url_; QString since_; @@ -366,6 +376,7 @@ public: virtual void setCurrentChild(InnerNode* ) { } virtual void setOutputFileName(const QString& f) { outputFileName_ = f; } virtual QString outputFileName() const { return outputFileName_; } + virtual QmlPropertyNode* hasQmlProperty(const QString& ) const; void printChildren(const QString& title); void printMembers(const QString& title); @@ -444,7 +455,7 @@ public: virtual bool isClass() const { return true; } virtual bool isWrapper() const { return wrapper_; } virtual QString obsoleteLink() const { return obsoleteLink_; } - virtual void setObsoleteLink(const QString& t) { obsoleteLink_ = t; }; + virtual void setObsoleteLink(const QString& t) { obsoleteLink_ = t; } virtual void setWrapper() { wrapper_ = true; } void addBaseClass(Access access, @@ -486,9 +497,11 @@ public: PageType ptype); virtual ~DocNode() { } + void setQtVariable(const QString &variable) { qtVariable_ = variable; } void setTitle(const QString &title) { title_ = title; } void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; } + QString qtVariable() const { return qtVariable_; } SubType subType() const { return nodeSubtype_; } virtual QString title() const; virtual QString fullTitle() const; @@ -497,13 +510,14 @@ public: virtual QString nameForLists() const { return title(); } virtual void setImageFileName(const QString& ) { } virtual bool isGroup() const { return (subType() == Node::Group); } - virtual bool isQmlPropertyGroup() const { return (nodeSubtype_ == QmlPropertyGroup); } - virtual bool hasProperty(const QString& ) const; protected: SubType nodeSubtype_; QString title_; QString subtitle_; + +private: + QString qtVariable_; }; class NameCollisionNode : public DocNode @@ -619,11 +633,11 @@ public: virtual bool isQmlNode() const { return true; } }; -class QmlPropGroupNode : public DocNode +class QmlPropertyGroupNode : public InnerNode { public: - QmlPropGroupNode(QmlClassNode* parent, const QString& name); - virtual ~QmlPropGroupNode() { } + QmlPropertyGroupNode(QmlClassNode* parent, const QString& name); + virtual ~QmlPropertyGroupNode() { } virtual bool isQmlNode() const { return true; } virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); } virtual QString qmlTypeName() const { return parent()->qmlTypeName(); } @@ -631,6 +645,7 @@ public: virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); } virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); } virtual QString idNumber(); + virtual bool isQmlPropertyGroup() const { return true; } const QString& element() const { return parent()->name(); } @@ -645,34 +660,27 @@ class QmlPropertyNode : public LeafNode Q_DECLARE_TR_FUNCTIONS(QDoc::QmlPropertyNode) public: - QmlPropertyNode(QmlClassNode *parent, - const QString& name, - const QString& type, - bool attached); - QmlPropertyNode(QmlPropGroupNode* parent, - const QString& name, - const QString& type, - bool attached); - QmlPropertyNode(QmlPropertyNode* parent, + QmlPropertyNode(InnerNode *parent, const QString& name, const QString& type, bool attached); virtual ~QmlPropertyNode() { } - void setDataType(const QString& dataType) { type_ = dataType; } + virtual void setDataType(const QString& dataType) { type_ = dataType; } void setStored(bool stored) { stored_ = toFlagValue(stored); } void setDesignable(bool designable) { designable_ = toFlagValue(designable); } - void setReadOnly(bool ro) { readOnly_ = toFlagValue(ro); } + virtual void setReadOnly(bool ro) { readOnly_ = toFlagValue(ro); } void setDefault() { isdefault_ = true; } const QString &dataType() const { return type_; } QString qualifiedDataType() const { return type_; } bool isReadOnlySet() const { return (readOnly_ != FlagValueDefault); } - bool isDefault() const { return isdefault_; } bool isStored() const { return fromFlagValue(stored_,true); } bool isDesignable() const { return fromFlagValue(designable_,false); } bool isWritable(QDocDatabase* qdb); - bool isReadOnly() const { return fromFlagValue(readOnly_,false); } + virtual bool isDefault() const { return isdefault_; } + virtual bool isReadOnly() const { return fromFlagValue(readOnly_,false); } + virtual bool isAlias() const { return isAlias_; } virtual bool isAttached() const { return attached_; } virtual bool isQmlNode() const { return true; } virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); } @@ -680,22 +688,19 @@ public: virtual QString qmlModuleName() const { return parent()->qmlModuleName(); } virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); } virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); } - virtual bool hasProperty(const QString& name) const; PropertyNode* correspondingProperty(QDocDatabase* qdb); - const QString& element() const { return static_cast<QmlPropGroupNode*>(parent())->element(); } - void appendQmlPropNode(QmlPropertyNode* p) { qmlPropNodes_.append(p); } - const NodeList& qmlPropNodes() const { return qmlPropNodes_; } + const QString& element() const { return static_cast<QmlPropertyGroupNode*>(parent())->element(); } private: QString type_; FlagValue stored_; FlagValue designable_; + bool isAlias_; bool isdefault_; bool attached_; FlagValue readOnly_; - NodeList qmlPropNodes_; }; class EnumItem @@ -892,7 +897,7 @@ public: PropertyNode(InnerNode* parent, const QString& name); virtual ~PropertyNode() { } - void setDataType(const QString& dataType) { type_ = dataType; } + virtual void setDataType(const QString& dataType) { type_ = dataType; } void addFunction(FunctionNode* function, FunctionRole role); void addSignal(FunctionNode* function, FunctionRole role); void setStored(bool stored) { stored_ = toFlagValue(stored); } diff --git a/src/tools/qdoc/puredocparser.cpp b/src/tools/qdoc/puredocparser.cpp index d11ef3a3c7..644fe05438 100644 --- a/src/tools/qdoc/puredocparser.cpp +++ b/src/tools/qdoc/puredocparser.cpp @@ -118,9 +118,9 @@ void PureDocParser::parseSourceFile(const Location& location, const QString& fil */ bool PureDocParser::processQdocComments() { - QSet<QString> topicCommandsAllowed = topicCommands(); - QSet<QString> otherMetacommandsAllowed = otherMetaCommands(); - QSet<QString> metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; + const QSet<QString>& topicCommandsAllowed = topicCommands(); + const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); + const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; while (tok != Tok_Eoi) { if (tok == Tok_Doc) { @@ -137,55 +137,68 @@ bool PureDocParser::processQdocComments() /* Doc parses the comment. */ - Doc doc(start_loc,end_loc,comment,metacommandsAllowed); + Doc doc(start_loc, end_loc, comment, metacommandsAllowed, topicCommandsAllowed); QString topic; - ArgList args; + bool isQmlPropertyTopic = false; - QSet<QString> topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); - - /* - There should be one topic command in the set, - or none. If the set is empty, then the comment - should be a function description. - */ - if (topicCommandsUsed.count() > 0) { - topic = *topicCommandsUsed.begin(); - args = doc.metaCommandArgs(topic); + const TopicList& topics = doc.topicsUsed(); + if (!topics.isEmpty()) { + topic = topics[0].topic; + if ((topic == COMMAND_QMLPROPERTY) || + (topic == COMMAND_QMLPROPERTYGROUP) || + (topic == COMMAND_QMLATTACHEDPROPERTY)) { + isQmlPropertyTopic = true; + } + } + if (isQmlPropertyTopic && topics.size() > 1) { + qDebug() << "MULTIPLE TOPICS:" << doc.location().fileName() << doc.location().lineNo(); + for (int i=0; i<topics.size(); ++i) { + qDebug() << " " << topics[i].topic << topics[i].args; + } } NodeList nodes; - QList<Doc> docs; + DocList docs; if (topic.isEmpty()) { doc.location().warning(tr("This qdoc comment contains no topic command " "(e.g., '\\%1', '\\%2').") .arg(COMMAND_MODULE).arg(COMMAND_PAGE)); } + else if (isQmlPropertyTopic) { + Doc nodeDoc = doc; + processQmlProperties(nodeDoc, nodes, docs); + } else { - /* - There is a topic command. Process it. - */ - if ((topic == COMMAND_QMLPROPERTY) || - (topic == COMMAND_QMLATTACHEDPROPERTY)) { + ArgList args; + QSet<QString> topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + if (topicCommandsUsed.count() > 0) { + topic = *topicCommandsUsed.begin(); + args = doc.metaCommandArgs(topic); + } + if (topicCommandsUsed.count() > 1) { + QString topics; + QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin(); + while (t != topicCommandsUsed.constEnd()) { + topics += " \\" + *t + ","; + ++t; + } + topics[topics.lastIndexOf(',')] = '.'; + int i = topics.lastIndexOf(','); + topics[i] = ' '; + topics.insert(i+1,"and"); + doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); + } + ArgList::ConstIterator a = args.begin(); + while (a != args.end()) { Doc nodeDoc = doc; - Node* node = processTopicCommandGroup(nodeDoc,topic,args); + Node* node = processTopicCommand(nodeDoc,topic,*a); if (node != 0) { nodes.append(node); docs.append(nodeDoc); } - } - else { - ArgList::ConstIterator a = args.begin(); - while (a != args.end()) { - Doc nodeDoc = doc; - Node* node = processTopicCommand(nodeDoc,topic,*a); - if (node != 0) { - nodes.append(node); - docs.append(nodeDoc); - } - ++a; - } + ++a; } } diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp index 7a3df4e4f2..a1e06c8020 100644 --- a/src/tools/qdoc/qdocdatabase.cpp +++ b/src/tools/qdoc/qdocdatabase.cpp @@ -612,7 +612,7 @@ void QDocDatabase::findAllObsoleteThings(const InnerNode* node) case Node::QmlMethod: if ((*c)->parent()) { Node* parent = (*c)->parent(); - if (parent->subType() == Node::QmlPropertyGroup && parent->parent()) + if (parent->type() == Node::QmlPropertyGroup && parent->parent()) parent = parent->parent(); if (parent && parent->subType() == Node::QmlClass && !parent->name().isEmpty()) name = parent->name() + "::" + name; diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 5f2ebdfd07..aab5e4f9ae 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -217,8 +217,18 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, location = Location(name); node = qbtn; } - else if (element.nodeName() == "qmlproperty") { + else if (element.nodeName() == "qmlpropertygroup") { QmlClassNode* qcn = static_cast<QmlClassNode*>(parent); + QmlPropertyGroupNode* qpgn = new QmlPropertyGroupNode(qcn, name); + if (element.hasAttribute("location")) + name = element.attribute("location", QString()); + if (!indexUrl.isEmpty()) + location = Location(indexUrl + QLatin1Char('/') + name); + else if (!indexUrl.isNull()) + location = Location(name); + node = qpgn; + } + else if (element.nodeName() == "qmlproperty") { QString type = element.attribute("type"); bool attached = false; if (element.attribute("attached") == "true") @@ -226,7 +236,15 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, bool readonly = false; if (element.attribute("writable") == "false") readonly = true; - QmlPropertyNode* qpn = new QmlPropertyNode(qcn, name, type, attached); + QmlPropertyNode* qpn = 0; + if (parent->type() == Node::Document) { + QmlClassNode* qcn = static_cast<QmlClassNode*>(parent); + qpn = new QmlPropertyNode(qcn, name, type, attached); + } + else if (parent->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(parent); + qpn = new QmlPropertyNode(qpgn, name, type, attached); + } qpn->setReadOnly(readonly); node = qpn; } @@ -281,10 +299,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, subtype = Node::QmlClass; ptype = Node::ApiPage; } - else if (element.attribute("subtype") == "qmlpropertygroup") { - subtype = Node::QmlPropertyGroup; - ptype = Node::ApiPage; - } else if (element.attribute("subtype") == "qmlbasictype") { subtype = Node::QmlBasicType; ptype = Node::ApiPage; @@ -501,7 +515,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, // Create some content for the node. QSet<QString> emptySet; - Doc doc(location, location, " ", emptySet); // placeholder + Doc doc(location, location, " ", emptySet, emptySet); // placeholder node->setDoc(doc); node->setIndexNodeFlag(); node->setOutputSubdirectory(project_.toLower()); @@ -644,6 +658,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::QmlProperty: nodeName = "qmlproperty"; break; + case Node::QmlPropertyGroup: + nodeName = "qmlpropertygroup"; + break; case Node::QmlSignal: nodeName = "qmlsignal"; break; @@ -746,7 +763,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QString fullName = node->fullDocumentName(); if (fullName != objName) writer.writeAttribute("fullname", fullName); - QString href = node->outputSubdirectory(); + QString href; + if (Generator::useOutputSubdirs()) + href = node->outputSubdirectory(); if (!href.isEmpty()) href.append(QLatin1Char('/')); href.append(gen_->fullDocumentLocation(node)); @@ -927,6 +946,12 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("brief", brief); } break; + case Node::QmlPropertyGroup: + { + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + break; case Node::Property: { const PropertyNode* propertyNode = static_cast<const PropertyNode*>(node); @@ -1179,17 +1204,12 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer, foreach (Node* child, cnodes) { /* - Don't generate anything for a QML property group node. - It is just a place holder for a collection of QML property - nodes. Recurse to its children, which are the QML property - nodes. - - Do the same thing for collision nodes - we want children - of collision nodes in the index, but leaving out the - parent collision page will make searching for nodes easier. + Don't generate anything for a collision node. We want + children of collision nodes in the index, but leaving + out the parent collision page will make searching for + nodes easier. */ - if (child->subType() == Node::QmlPropertyGroup || - child->subType() == Node::Collision) { + if (child->subType() == Node::Collision) { const InnerNode* pgn = static_cast<const InnerNode*>(child); foreach (Node* c, pgn->childNodes()) { generateIndexSections(writer, c, generateInternalNodes); diff --git a/src/tools/qdoc/qdoctagfiles.cpp b/src/tools/qdoc/qdoctagfiles.cpp index 1f6020fc09..a0054ea229 100644 --- a/src/tools/qdoc/qdoctagfiles.cpp +++ b/src/tools/qdoc/qdoctagfiles.cpp @@ -156,7 +156,7 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne if (node->type() == Node::Class) { writer.writeTextElement("name", node->fullDocumentName()); - writer.writeTextElement("filename", gen_->fullDocumentLocation(node,true)); + writer.writeTextElement("filename", gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); // Classes contain information about their base classes. const ClassNode* classNode = static_cast<const ClassNode*>(node); @@ -175,7 +175,7 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne } else { writer.writeTextElement("name", node->fullDocumentName()); - writer.writeTextElement("filename", gen_->fullDocumentLocation(node,true)); + writer.writeTextElement("filename", gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); // Recurse to write all members. generateTagFileMembers(writer, static_cast<const InnerNode*>(node)); @@ -291,7 +291,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN writer.writeTextElement("type", "virtual " + functionNode->returnType()); writer.writeTextElement("name", objName); - QStringList pieces = gen_->fullDocumentLocation(node,true).split(QLatin1Char('#')); + QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); @@ -332,7 +332,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN const PropertyNode* propertyNode = static_cast<const PropertyNode*>(node); writer.writeAttribute("type", propertyNode->dataType()); writer.writeTextElement("name", objName); - QStringList pieces = gen_->fullDocumentLocation(node,true).split(QLatin1Char('#')); + QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); writer.writeTextElement("arglist", QString()); @@ -366,7 +366,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN else writer.writeAttribute("type", QString()); writer.writeTextElement("name", objName); - QStringList pieces = gen_->fullDocumentLocation(node,true).split(QLatin1Char('#')); + QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); writer.writeTextElement("arglist", QString()); diff --git a/src/tools/qdoc/qmlcodeparser.cpp b/src/tools/qdoc/qmlcodeparser.cpp index b9c0ad9218..28b9c3ec9b 100644 --- a/src/tools/qdoc/qmlcodeparser.cpp +++ b/src/tools/qdoc/qmlcodeparser.cpp @@ -70,6 +70,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_QMLTYPE Doc::alias("qmltype") #define COMMAND_QMLMODULE Doc::alias("qmlmodule") #define COMMAND_QMLPROPERTY Doc::alias("qmlproperty") +#define COMMAND_QMLPROPERTYGROUP Doc::alias("qmlpropertygroup") #define COMMAND_QMLATTACHEDPROPERTY Doc::alias("qmlattachedproperty") #define COMMAND_QMLINHERITS Doc::alias("inherits") #define COMMAND_QMLINSTANTIATES Doc::alias("instantiates") @@ -166,9 +167,9 @@ void QmlCodeParser::parseSourceFile(const Location& location, const QString& fil extractPragmas(newCode); lexer->setCode(newCode, 1); - QSet<QString> topicCommandsAllowed = topicCommands(); - QSet<QString> otherMetacommandsAllowed = otherMetaCommands(); - QSet<QString> metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; + const QSet<QString>& topicCommandsAllowed = topicCommands(); + const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); + const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; if (parser->parse()) { QQmlJS::AST::UiProgram *ast = parser->ast(); @@ -195,42 +196,52 @@ void QmlCodeParser::doneParsingSourceFiles() { } +static QSet<QString> topicCommands_; /*! Returns the set of strings representing the topic commands. */ -QSet<QString> QmlCodeParser::topicCommands() +const QSet<QString>& QmlCodeParser::topicCommands() { - return QSet<QString>() << COMMAND_VARIABLE - << COMMAND_QMLCLASS - << COMMAND_QMLTYPE - << COMMAND_QMLPROPERTY - << COMMAND_QMLATTACHEDPROPERTY - << COMMAND_QMLSIGNAL - << COMMAND_QMLATTACHEDSIGNAL - << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD - << COMMAND_QMLBASICTYPE; + if (topicCommands_.isEmpty()) { + topicCommands_ << COMMAND_VARIABLE + << COMMAND_QMLCLASS + << COMMAND_QMLTYPE + << COMMAND_QMLPROPERTY + << COMMAND_QMLPROPERTYGROUP + << COMMAND_QMLATTACHEDPROPERTY + << COMMAND_QMLSIGNAL + << COMMAND_QMLATTACHEDSIGNAL + << COMMAND_QMLMETHOD + << COMMAND_QMLATTACHEDMETHOD + << COMMAND_QMLBASICTYPE; + } + return topicCommands_; } +static QSet<QString> otherMetaCommands_; /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ -QSet<QString> QmlCodeParser::otherMetaCommands() +const QSet<QString>& QmlCodeParser::otherMetaCommands() { - return commonMetaCommands() << COMMAND_STARTPAGE - << COMMAND_QMLINHERITS - << COMMAND_QMLDEFAULT - << COMMAND_QMLREADONLY - << COMMAND_DEPRECATED - << COMMAND_INGROUP - << COMMAND_INTERNAL - << COMMAND_OBSOLETE - << COMMAND_PRELIMINARY - << COMMAND_SINCE - << COMMAND_QMLABSTRACT - << COMMAND_INQMLMODULE - << COMMAND_WRAPPER; + if (otherMetaCommands_.isEmpty()) { + otherMetaCommands_ = commonMetaCommands(); + otherMetaCommands_ << COMMAND_STARTPAGE + << COMMAND_QMLINHERITS + << COMMAND_QMLDEFAULT + << COMMAND_QMLREADONLY + << COMMAND_DEPRECATED + << COMMAND_INGROUP + << COMMAND_INTERNAL + << COMMAND_OBSOLETE + << COMMAND_PRELIMINARY + << COMMAND_SINCE + << COMMAND_QMLABSTRACT + << COMMAND_INQMLMODULE + << COMMAND_WRAPPER; + } + return otherMetaCommands_; } /*! diff --git a/src/tools/qdoc/qmlcodeparser.h b/src/tools/qdoc/qmlcodeparser.h index 5bdcfbfbbf..71b4660fe7 100644 --- a/src/tools/qdoc/qmlcodeparser.h +++ b/src/tools/qdoc/qmlcodeparser.h @@ -79,8 +79,8 @@ public: void extractPragmas(QString &script); protected: - virtual QSet<QString> topicCommands(); - virtual QSet<QString> otherMetaCommands(); + const QSet<QString>& topicCommands(); + const QSet<QString>& otherMetaCommands(); private: QQmlJS::Engine engine; diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp index 86b86c8f34..c049857717 100644 --- a/src/tools/qdoc/qmlvisitor.cpp +++ b/src/tools/qdoc/qmlvisitor.cpp @@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_QMLTYPE Doc::alias(QLatin1String("qmltype")) #define COMMAND_QMLMODULE Doc::alias(QLatin1String("qmlmodule")) #define COMMAND_QMLPROPERTY Doc::alias(QLatin1String("qmlproperty")) +#define COMMAND_QMLPROPERTYGROUP Doc::alias(QLatin1String("qmlpropertygroup")) #define COMMAND_QMLATTACHEDPROPERTY Doc::alias(QLatin1String("qmlattachedproperty")) #define COMMAND_QMLINHERITS Doc::alias(QLatin1String("inherits")) #define COMMAND_QMLINSTANTIATES Doc::alias(QLatin1String("instantiates")) @@ -85,17 +86,17 @@ QT_BEGIN_NAMESPACE QmlDocVisitor::QmlDocVisitor(const QString &filePath, const QString &code, QQmlJS::Engine *engine, - QSet<QString> &commands, - QSet<QString> &topics) + const QSet<QString> &commands, + const QSet<QString> &topics) : nestingLevel(0) { lastEndOffset = 0; - this->filePath = filePath; + this->filePath_ = filePath; this->name = QFileInfo(filePath).baseName(); document = code; this->engine = engine; - this->commands = commands; - this->topics = topics; + this->commands_ = commands; + this->topics_ = topics; current = QDocDatabase::qdocDB()->treeRoot(); } @@ -141,13 +142,89 @@ QQmlJS::AST::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) cons return QQmlJS::AST::SourceLocation(); } +#if 0 + ArgList args; + QSet<QString>::iterator i = metacommands.begin(); + while (i != metacommands.end()) { + if (topics_.contains(*i)) { + topic = *i; + break; + } + ++i; + } + if (!topic.isEmpty()) { + args = doc.metaCommandArgs(topic); + if ((topic == COMMAND_QMLCLASS) || (topic == COMMAND_QMLTYPE)) { + // do nothing. + } + else if (topic == COMMAND_QMLPROPERTY) { + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); + qpn->setReadOnly(0); + if (qpn->dataType() == "alias") { + QStringList part = args[0].first.split(QLatin1Char(' ')); + qpn->setDataType(part[0]); + } + } + } + else if (topic == COMMAND_QMLPROPERTYGROUP) { + // zzz ? + } + else if (topic == COMMAND_QMLMODULE) { + } + else if (topic == COMMAND_QMLATTACHEDPROPERTY) { + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); + qpn->setReadOnly(0); + } + } + else if (topic == COMMAND_QMLSIGNAL) { + } + else if (topic == COMMAND_QMLATTACHEDSIGNAL) { + } + else if (topic == COMMAND_QMLMETHOD) { + } + else if (topic == COMMAND_QMLATTACHEDMETHOD) { + } + else if (topic == COMMAND_QMLBASICTYPE) { + } + } + + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); + for (int i=0; i<topicsUsed.size(); ++i) { + if (topicsUsed.at(i).topic == "qmlproperty") { + /* + A \qmlproperty command would be used in a QML file + to document the underlying property for a property + alias. + */ + QmlPropArgs qpa; + if (splitQmlPropertyArg(doc, topicsUsed.at(i).args, qpa)) { + QmlPropertyNode* n = parent->hasQmlPropertyNode(qpa.name_); + if (n == 0) + n = new QmlPropertyNode(qpn, qpa.name_, qpa.type_, false); + n->setLocation(doc.location()); + n->setReadOnly(qpn->isReadOnly()); + if (qpn->isDefault()) + n->setDefault(); + } + else + qDebug() << " FAILED TO PARSE QML PROPERTY:" + << topicsUsed.at(i).topic << topicsUsed.at(i).args; + } + } + } + +#endif + /*! Finds the nearest unused qdoc comment above the QML entity represented by the \a node and processes the qdoc commands - in that comment. The proceesed documentation is stored in + in that comment. The processed documentation is stored in the \a node. - If a qdoc comment is found about \a location, true is returned. + If a qdoc comment is found for \a location, true is returned. If a comment is not found there, false is returned. */ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Node* node) @@ -156,23 +233,66 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod if (loc.isValid()) { QString source = document.mid(loc.offset, loc.length); - Location start(filePath); + Location start(filePath_); start.setLineNo(loc.startLine); start.setColumnNo(loc.startColumn); - Location finish(filePath); + Location finish(filePath_); finish.setLineNo(loc.startLine); finish.setColumnNo(loc.startColumn); - Doc doc(start, finish, source.mid(1), commands, topics); + Doc doc(start, finish, source.mid(1), commands_, topics_); + const TopicList& topicsUsed = doc.topicsUsed(); + NodeList nodes; + Node* nodePassedIn = node; + InnerNode* parent = nodePassedIn->parent(); node->setDoc(doc); - applyMetacommands(loc, node, doc); + nodes.append(node); + if (topicsUsed.size() > 0) { + for (int i=0; i<topicsUsed.size(); ++i) { + if (topicsUsed.at(i).topic == QString("qmlpropertygroup")) { + qDebug() << "PROPERTY GROUP COMMAND SEEN:" << topicsUsed.at(i).args << filePath_; + break; + } + } + for (int i=0; i<topicsUsed.size(); ++i) { + QString topic = topicsUsed.at(i).topic; + QString args = topicsUsed.at(i).args; + if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY)) { + QmlPropArgs qpa; + if (splitQmlPropertyArg(doc, args, qpa)) { + if (qpa.name_ == nodePassedIn->name()) { + if (nodePassedIn->isAlias()) + nodePassedIn->setDataType(qpa.type_); + } + else { + bool isAttached = (topic == COMMAND_QMLATTACHEDPROPERTY); + QmlPropertyNode* n = parent->hasQmlProperty(qpa.name_); + if (n == 0) + n = new QmlPropertyNode(parent, qpa.name_, qpa.type_, isAttached); + n->setLocation(doc.location()); + n->setDoc(doc); + n->setReadOnly(nodePassedIn->isReadOnly()); + if (nodePassedIn->isDefault()) + n->setDefault(); + if (isAttached) + n->setReadOnly(0); + nodes.append(n); + } + } + else + qDebug() << " FAILED TO PARSE QML PROPERTY:" << topic << args; + } + } + } + for (int i=0; i<nodes.size(); ++i) + applyMetacommands(loc, nodes.at(i), doc); usedComments.insert(loc.offset); if (doc.isEmpty()) { return false; } return true; } - Location codeLoc(filePath); + Location codeLoc(filePath_); codeLoc.setLineNo(location.startLine); node->setLocation(codeLoc); return false; @@ -237,80 +357,13 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation, Doc& doc) { QDocDatabase* qdb = QDocDatabase::qdocDB(); - - const TopicList& topicsUsed = doc.topicsUsed(); - if (topicsUsed.size() > 0) { - if (node->type() == Node::QmlProperty) { - QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); - for (int i=0; i<topicsUsed.size(); ++i) { - if (topicsUsed.at(i).topic == "qmlproperty") { - QmlPropArgs qpa; - if (splitQmlPropertyArg(doc, topicsUsed.at(i).args, qpa)) { - QmlPropertyNode* n = new QmlPropertyNode(qpn, qpa.name_, qpa.type_, false); - n->setLocation(doc.location()); - qpn->appendQmlPropNode(n); - n->setReadOnly(qpn->isReadOnly()); - if (qpn->isDefault()) - n->setDefault(); - } - else - qDebug() << " FAILED TO PARSE QML PROPERTY:" - << topicsUsed.at(i).topic << topicsUsed.at(i).args; - } - } - } - } QSet<QString> metacommands = doc.metaCommandsUsed(); if (metacommands.count() > 0) { - QString topic; - ArgList args; + metacommands.subtract(topics_); QSet<QString>::iterator i = metacommands.begin(); while (i != metacommands.end()) { - if (topics.contains(*i)) { - topic = *i; - break; - } - ++i; - } - if (!topic.isEmpty()) { - args = doc.metaCommandArgs(topic); - if ((topic == COMMAND_QMLCLASS) || (topic == COMMAND_QMLTYPE)) { - // do nothing. - } - else if (topic == COMMAND_QMLPROPERTY) { - if (node->type() == Node::QmlProperty) { - QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); - qpn->setReadOnly(0); - if (qpn->dataType() == "alias") { - QStringList part = args[0].first.split(QLatin1Char(' ')); - qpn->setDataType(part[0]); - } - } - } - else if (topic == COMMAND_QMLMODULE) { - } - else if (topic == COMMAND_QMLATTACHEDPROPERTY) { - if (node->type() == Node::QmlProperty) { - QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); - qpn->setReadOnly(0); - } - } - else if (topic == COMMAND_QMLSIGNAL) { - } - else if (topic == COMMAND_QMLATTACHEDSIGNAL) { - } - else if (topic == COMMAND_QMLMETHOD) { - } - else if (topic == COMMAND_QMLATTACHEDMETHOD) { - } - else if (topic == COMMAND_QMLBASICTYPE) { - } - } - metacommands.subtract(topics); - i = metacommands.begin(); - while (i != metacommands.end()) { QString command = *i; - args = doc.metaCommandArgs(command); + ArgList args = doc.metaCommandArgs(command); if (command == COMMAND_QMLABSTRACT) { if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) { node->setAbstract(true); @@ -528,7 +581,9 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member) QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current); if (qmlClass) { QString name = member->name.toString(); - QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlClass, name, type, false); + QmlPropertyNode* qmlPropNode = qmlClass->hasQmlProperty(name); + if (qmlPropNode == 0) + qmlPropNode = new QmlPropertyNode(qmlClass, name, type, false); qmlPropNode->setReadOnly(member->isReadonlyMember); if (member->isDefaultMember) qmlPropNode->setDefault(); diff --git a/src/tools/qdoc/qmlvisitor.h b/src/tools/qdoc/qmlvisitor.h index 2c3ff341d6..cdb7ae7391 100644 --- a/src/tools/qdoc/qmlvisitor.h +++ b/src/tools/qdoc/qmlvisitor.h @@ -45,7 +45,6 @@ #include <qstring.h> #include "qqmljsastvisitor_p.h" #include "node.h" -#include "tree.h" QT_BEGIN_NAMESPACE @@ -72,8 +71,8 @@ public: QmlDocVisitor(const QString &filePath, const QString &code, QQmlJS::Engine *engine, - QSet<QString> &commands, - QSet<QString> &topics); + const QSet<QString> &commands, + const QSet<QString> &topics); virtual ~QmlDocVisitor(); bool visit(QQmlJS::AST::UiImportList *imports); @@ -113,12 +112,12 @@ private: QQmlJS::Engine *engine; quint32 lastEndOffset; quint32 nestingLevel; - QString filePath; + QString filePath_; QString name; QString document; ImportList importList; - QSet<QString> commands; - QSet<QString> topics; + QSet<QString> commands_; + QSet<QString> topics_; QSet<quint32> usedComments; InnerNode *current; }; diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index 553c569ae9..8c5ecdcfe9 100644 --- a/src/tools/qdoc/tree.cpp +++ b/src/tools/qdoc/tree.cpp @@ -169,7 +169,7 @@ const Node* Tree::findNode(const QStringList& path, if (node && i == path.size() && (!(findFlags & NonFunction) || node->type() != Node::Function || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) { - if ((node != self) && (node->subType() != Node::QmlPropertyGroup)) { + if ((node != self) && (node->type() != Node::QmlPropertyGroup)) { if (node->subType() == Node::Collision) { node = node->applyModuleIdentifier(start); } diff --git a/src/tools/uic/main.cpp b/src/tools/uic/main.cpp index f5a1301666..baafb8ec92 100644 --- a/src/tools/uic/main.cpp +++ b/src/tools/uic/main.cpp @@ -106,13 +106,6 @@ int runUic(int argc, char *argv[]) return 1; } driver.option().postfix = QLatin1String(argv[arg]); - } else if (opt == QLatin1String("-3")) { - ++arg; - if (!argv[arg]) { - showHelp(argv[0]); - return 1; - } - driver.option().uic3 = QFile::decodeName(argv[arg]); } else if (opt == QLatin1String("-tr") || opt == QLatin1String("-translate")) { ++arg; if (!argv[arg]) { diff --git a/src/tools/uic/option.h b/src/tools/uic/option.h index 141eb4806a..14ed422d63 100644 --- a/src/tools/uic/option.h +++ b/src/tools/uic/option.h @@ -73,7 +73,6 @@ struct Option QString prefix; QString postfix; QString translateFunction; - QString uic3; #ifdef QT_UIC_JAVA_GENERATOR QString javaPackage; QString javaOutputDirectory; diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index c08a034d9e..5da41aa0a5 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -63,6 +63,8 @@ #include "qmimedata.h" #include "qspinbox.h" #include "qdialogbuttonbox.h" +#include "qscreen.h" +#include "qcursor.h" QT_BEGIN_NAMESPACE @@ -920,6 +922,8 @@ signals: private slots: void rgbEd(); void hsvEd(); + void htmlEd(); + private: void showCurrentColor(); int hue, sat, val; @@ -931,6 +935,7 @@ private: QLabel *lblRed; QLabel *lblGreen; QLabel *lblBlue; + QLabel *lblHtml; QColSpinBox *hEd; QColSpinBox *sEd; QColSpinBox *vEd; @@ -939,6 +944,7 @@ private: QColSpinBox *bEd; QColSpinBox *alphaEd; QLabel *alphaLab; + QLineEdit *htEd; QColorShowLabel *lab; bool rgbOriginal; QColorDialog *colorDialog; @@ -1230,6 +1236,19 @@ QColorShower::QColorShower(QColorDialog *parent) #endif alphaEd->hide(); alphaLab->hide(); + lblHtml = new QLabel(this); + htEd = new QLineEdit(this); +#ifndef QT_NO_SHORTCUT + lblHtml->setBuddy(htEd); +#endif + + QRegularExpression regExp(QStringLiteral("#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})")); + QRegularExpressionValidator *validator = new QRegularExpressionValidator(regExp, this); + htEd->setValidator(validator); + + lblHtml->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(lblHtml, 5, 1); + gl->addWidget(htEd, 5, 2); connect(hEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd())); connect(sEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd())); @@ -1239,6 +1258,7 @@ QColorShower::QColorShower(QColorDialog *parent) connect(gEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd())); connect(bEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd())); connect(alphaEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd())); + connect(htEd, SIGNAL(textEdited(QString)), this, SLOT(htmlEd())); retranslateStrings(); } @@ -1251,7 +1271,7 @@ inline bool QColorDialogPrivate::isAlphaVisible() const { return cs->isAlphaVisi QColor QColorDialogPrivate::currentQColor() const { - if (!options->testOption(QColorDialogOptions::DontUseNativeDialog) && nativeDialogInUse) + if (nativeDialogInUse) return platformColorDialogHelper()->currentColor(); return cs->currentQColor(); } @@ -1273,6 +1293,8 @@ void QColorShower::rgbEd() sEd->setValue(sat); vEd->setValue(val); + htEd->setText(QColor(curCol).name()); + showCurrentColor(); emit newCol(currentColor()); updateQColor(); @@ -1293,6 +1315,31 @@ void QColorShower::hsvEd() gEd->setValue(qGreen(currentColor())); bEd->setValue(qBlue(currentColor())); + htEd->setText(c.name()); + + showCurrentColor(); + emit newCol(currentColor()); + updateQColor(); +} + +void QColorShower::htmlEd() +{ + QColor c; + QString t = htEd->text(); + c.setNamedColor(t); + if (!c.isValid()) + return; + curCol = qRgba(c.red(), c.green(), c.blue(), currentAlpha()); + rgb2hsv(curCol, hue, sat, val); + + hEd->setValue(hue); + sEd->setValue(sat); + vEd->setValue(val); + + rEd->setValue(qRed(currentColor())); + gEd->setValue(qGreen(currentColor())); + bEd->setValue(qBlue(currentColor())); + showCurrentColor(); emit newCol(currentColor()); updateQColor(); @@ -1313,6 +1360,8 @@ void QColorShower::setRgb(QRgb rgb) gEd->setValue(qGreen(currentColor())); bEd->setValue(qBlue(currentColor())); + htEd->setText(QColor(rgb).name()); + showCurrentColor(); updateQColor(); } @@ -1336,6 +1385,8 @@ void QColorShower::setHsv(int h, int s, int v) gEd->setValue(qGreen(currentColor())); bEd->setValue(qBlue(currentColor())); + htEd->setText(c.name()); + showCurrentColor(); updateQColor(); } @@ -1349,6 +1400,7 @@ void QColorShower::retranslateStrings() lblGreen->setText(QColorDialog::tr("&Green:")); lblBlue->setText(QColorDialog::tr("Bl&ue:")); alphaLab->setText(QColorDialog::tr("A&lpha channel:")); + lblHtml->setText(QColorDialog::tr("&HTML:")); } void QColorShower::updateQColor() @@ -1362,16 +1414,20 @@ void QColorShower::updateQColor() //sets all widgets to display h,s,v void QColorDialogPrivate::_q_newHsv(int h, int s, int v) { - cs->setHsv(h, s, v); - cp->setCol(h, s); - lp->setCol(h, s, v); + if (!nativeDialogInUse) { + cs->setHsv(h, s, v); + cp->setCol(h, s); + lp->setCol(h, s, v); + } } //sets all widgets to display rgb void QColorDialogPrivate::setCurrentColor(QRgb rgb) { - cs->setRgb(rgb); - _q_newColorTypedIn(rgb); + if (!nativeDialogInUse) { + cs->setRgb(rgb); + _q_newColorTypedIn(rgb); + } } // hack; doesn't keep curCol in sync, so use with care @@ -1421,13 +1477,24 @@ bool QColorDialogPrivate::selectColor(const QColor &col) return false; } +QColor QColorDialogPrivate::grabScreenColor(const QPoint &p) +{ + const QDesktopWidget *desktop = QApplication::desktop(); + const QPixmap pixmap = QGuiApplication::screens().at(desktop->screenNumber())->grabWindow(desktop->winId(), + p.x(), p.y(), 1, 1); + QImage i = pixmap.toImage(); + return i.pixel(0, 0); +} + //sets all widgets except cs to display rgb void QColorDialogPrivate::_q_newColorTypedIn(QRgb rgb) { - int h, s, v; - rgb2hsv(rgb, h, s, v); - cp->setCol(h, s); - lp->setCol(h, s, v); + if (!nativeDialogInUse) { + int h, s, v; + rgb2hsv(rgb, h, s, v); + cp->setCol(h, s); + lp->setCol(h, s, v); + } } void QColorDialogPrivate::_q_nextCustom(int r, int c) @@ -1450,6 +1517,48 @@ void QColorDialogPrivate::_q_newStandard(int r, int c) custom->setSelected(-1,-1); } +void QColorDialogPrivate::_q_pickScreenColor() +{ + Q_Q(QColorDialog); + screenColorPicking = true; + // If user pushes Escape, the last color before picking will be restored. + beforeScreenColorPicking = cs->currentColor(); + /*For some reason, q->grabMouse(Qt::CrossCursor) doesn't change + * the cursor, and therefore I have to change it manually. + */ + q->grabMouse(); + q->setCursor(Qt::CrossCursor); + q->grabKeyboard(); + /* With setMouseTracking(true) the desired color can be more precisedly picked up, + * and continuously pushing the mouse button is not necessary. + */ + q->setMouseTracking(true); + + addCusBt->setDisabled(true); + buttons->setDisabled(true); + screenColorPickerButton->setDisabled(true); + + q->setCurrentColor(grabScreenColor(QCursor::pos())); + lblScreenColorInfo->setText(QColorDialog::tr("Cursor at %1, %2, color: %3\nPress ESC to cancel") + .arg(QCursor::pos().x()) + .arg(QCursor::pos().y()) + .arg(q->currentColor().name())); +} + +void QColorDialogPrivate::releaseColorPicking() +{ + Q_Q(QColorDialog); + screenColorPicking = false; + q->releaseMouse(); + q->releaseKeyboard(); + q->setCursor(Qt::ArrowCursor); + q->setMouseTracking(false); + lblScreenColorInfo->setText(QLatin1String("\n")); + addCusBt->setDisabled(false); + buttons->setDisabled(false); + screenColorPickerButton->setDisabled(false); +} + void QColorDialogPrivate::init(const QColor &initial) { Q_Q(QColorDialog); @@ -1457,9 +1566,24 @@ void QColorDialogPrivate::init(const QColor &initial) q->setSizeGripEnabled(false); q->setWindowTitle(QColorDialog::tr("Select Color")); + // default: use the native dialog if possible. Can be overridden in setOptions() nativeDialogInUse = (platformColorDialogHelper() != 0); - + screenColorPicking = false; nextCust = 0; + + if (!nativeDialogInUse) + initWidgets(); + +#ifdef Q_WS_MAC + delegate = 0; +#endif + + q->setCurrentColor(initial); +} + +void QColorDialogPrivate::initWidgets() +{ + Q_Q(QColorDialog); QVBoxLayout *mainLay = new QVBoxLayout(q); // there's nothing in this dialog that benefits from sizing up mainLay->setSizeConstraint(QLayout::SetFixedSize); @@ -1494,6 +1618,15 @@ void QColorDialogPrivate::init(const QColor &initial) leftLay->addWidget(lblBasicColors); leftLay->addWidget(standard); +#if !defined(Q_OS_WINCE) && !defined(QT_SMALL_COLORDIALOG) + // The screen color picker button + screenColorPickerButton = new QPushButton(QColorDialog::tr("Pick Screen Color")); + leftLay->addWidget(screenColorPickerButton); + lblScreenColorInfo = new QLabel(QLatin1String("\n")); + leftLay->addWidget(lblScreenColorInfo); + q->connect(screenColorPickerButton, SIGNAL(clicked()), SLOT(_q_pickScreenColor())); +#endif + #if !defined(Q_OS_WINCE) leftLay->addStretch(); #endif @@ -1597,12 +1730,6 @@ void QColorDialogPrivate::init(const QColor &initial) QObject::connect(cancel, SIGNAL(clicked()), q, SLOT(reject())); retranslateStrings(); - -#ifdef Q_WS_MAC - delegate = 0; -#endif - - q->setCurrentColor(initial); } void QColorDialogPrivate::initHelper(QPlatformDialogHelper *h) @@ -1667,6 +1794,11 @@ static const Qt::WindowFlags DefaultWindowFlags = during the execution of the program. Use setCustomColor() to set the custom colors, and use customColor() to get them. + When pressing the "Pick Screen Color" button, the cursor changes to a haircross + and the colors on the screen are scanned. The user can pick up one by clicking + the mouse or the Enter button. Pressing Escape restores the last color selected + before entering this mode. + The \l{dialogs/standarddialogs}{Standard Dialogs} example shows how to use QColorDialog as well as other built-in Qt dialogs. @@ -1708,12 +1840,13 @@ QColorDialog::QColorDialog(const QColor &initial, QWidget *parent) void QColorDialog::setCurrentColor(const QColor &color) { Q_D(QColorDialog); - d->setCurrentColor(color.rgb()); - d->selectColor(color); - d->setCurrentAlpha(color.alpha()); - - if (!testOption(QColorDialog::DontUseNativeDialog) && d->nativeDialogInUse) + if (d->nativeDialogInUse) d->platformColorDialogHelper()->setCurrentColor(color); + else { + d->setCurrentColor(color.rgb()); + d->selectColor(color); + d->setCurrentAlpha(color.alpha()); + } } QColor QColorDialog::currentColor() const @@ -1783,10 +1916,14 @@ void QColorDialog::setOptions(ColorDialogOptions options) return; d->options->setOptions(QColorDialogOptions::ColorDialogOptions(int(options))); - d->buttons->setVisible(!(options & NoButtons)); - d->showAlpha(options & ShowAlphaChannel); - if (options & DontUseNativeDialog) + if ((options & DontUseNativeDialog) && d->nativeDialogInUse) { d->nativeDialogInUse = false; + d->initWidgets(); + } + if (!d->nativeDialogInUse) { + d->buttons->setVisible(!(options & NoButtons)); + d->showAlpha(options & ShowAlphaChannel); + } } QColorDialog::ColorDialogOptions QColorDialog::options() const @@ -1868,7 +2005,7 @@ void QColorDialog::setVisible(bool visible) } #else - if (!(options() & DontUseNativeDialog) && d->nativeDialogInUse) { + if (d->nativeDialogInUse) { d->setNativeDialogVisible(visible); // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below // updates the state correctly, but skips showing the non-native version: @@ -1983,6 +2120,57 @@ void QColorDialog::changeEvent(QEvent *e) } /*! + \reimp +*/ +void QColorDialog::mouseMoveEvent(QMouseEvent *e) +{ + Q_D(QColorDialog); + if (d->screenColorPicking) { + setCurrentColor(d->grabScreenColor(e->globalPos())); + d->lblScreenColorInfo->setText(QColorDialog::tr("Cursor at %1, %2, color: %3\nPress ESC to cancel") + .arg(e->globalPos().x()) + .arg(e->globalPos().y()) + .arg(currentColor().name())); + return; + } + QDialog::mouseMoveEvent(e); +} + +/*! + \reimp +*/ +void QColorDialog::mouseReleaseEvent(QMouseEvent *e) +{ + Q_D(QColorDialog); + if (d->screenColorPicking) { + setCurrentColor(d->grabScreenColor(e->globalPos())); + d->releaseColorPicking(); + return; + } + QDialog::mouseReleaseEvent(e); +} + +/*! + \reimp +*/ +void QColorDialog::keyPressEvent(QKeyEvent *e) +{ + Q_D(QColorDialog); + if (d->screenColorPicking) { + if (e->key() == Qt::Key_Escape) { + d->releaseColorPicking(); + d->setCurrentColor(d->beforeScreenColorPicking); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + setCurrentColor(d->grabScreenColor(QCursor::pos())); + d->releaseColorPicking(); + } + e->accept(); + return; + } + QDialog::keyPressEvent(e); +} + +/*! Closes the dialog and sets its result code to \a result. If this dialog is shown with exec(), done() causes the local event loop to finish, and exec() to return \a result. diff --git a/src/widgets/dialogs/qcolordialog.h b/src/widgets/dialogs/qcolordialog.h index f6dc627a05..c7a1d6f400 100644 --- a/src/widgets/dialogs/qcolordialog.h +++ b/src/widgets/dialogs/qcolordialog.h @@ -112,6 +112,9 @@ Q_SIGNALS: protected: void changeEvent(QEvent *event); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void keyPressEvent(QKeyEvent *); void done(int result); private: @@ -123,6 +126,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_nextCustom(int, int)) Q_PRIVATE_SLOT(d_func(), void _q_newCustom(int, int)) Q_PRIVATE_SLOT(d_func(), void _q_newStandard(int, int)) + Q_PRIVATE_SLOT(d_func(), void _q_pickScreenColor()) friend class QColorShower; }; diff --git a/src/widgets/dialogs/qcolordialog_p.h b/src/widgets/dialogs/qcolordialog_p.h index 695e95d26c..08199cc7c1 100644 --- a/src/widgets/dialogs/qcolordialog_p.h +++ b/src/widgets/dialogs/qcolordialog_p.h @@ -82,11 +82,13 @@ public: { return static_cast<QPlatformColorDialogHelper *>(platformHelper()); } void init(const QColor &initial); + void initWidgets(); QRgb currentColor() const; QColor currentQColor() const; void setCurrentColor(QRgb rgb); void setCurrentQColor(const QColor &color); bool selectColor(const QColor &color); + QColor grabScreenColor(const QPoint &p); int currentAlpha() const; void setCurrentAlpha(int a); @@ -101,6 +103,8 @@ public: void _q_nextCustom(int, int); void _q_newCustom(int, int); void _q_newStandard(int, int); + void _q_pickScreenColor(); + void releaseColorPicking(); QWellArray *custom; QWellArray *standard; @@ -112,12 +116,16 @@ public: QColorShower *cs; QLabel *lblBasicColors; QLabel *lblCustomColors; + QLabel *lblScreenColorInfo; QPushButton *ok; QPushButton *cancel; QPushButton *addCusBt; + QPushButton *screenColorPickerButton; QColor selectedQColor; int nextCust; bool smallDisplay; + bool screenColorPicking; + QRgb beforeScreenColorPicking; QSharedPointer<QColorDialogOptions> options; QPointer<QObject> receiverToDisconnectOnClose; diff --git a/src/widgets/dialogs/qdialog_p.h b/src/widgets/dialogs/qdialog_p.h index eb0cb2372b..5064efa35d 100644 --- a/src/widgets/dialogs/qdialog_p.h +++ b/src/widgets/dialogs/qdialog_p.h @@ -111,7 +111,7 @@ public: QPointer<QEventLoop> eventLoop; - bool nativeDialogInUse; // Assigned in setVisible_sys() in derived classes. + bool nativeDialogInUse; QPlatformDialogHelper *platformHelper() const; private: diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index c42752311f..9c4b99253a 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -86,15 +86,27 @@ Q_GLOBAL_STATIC(QString, lastVisitedDir) typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options); Q_WIDGETS_EXPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook = 0; +typedef QUrl (*_qt_filedialog_existing_directory_url_hook)(QWidget *parent, const QString &caption, const QUrl &dir, QFileDialog::Options options, const QStringList &supportedSchemes); +Q_WIDGETS_EXPORT _qt_filedialog_existing_directory_url_hook qt_filedialog_existing_directory_url_hook = 0; + typedef QString (*_qt_filedialog_open_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); Q_WIDGETS_EXPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook = 0; +typedef QUrl (*_qt_filedialog_open_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes); +Q_WIDGETS_EXPORT _qt_filedialog_open_file_url_hook qt_filedialog_open_file_url_hook = 0; + typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); Q_WIDGETS_EXPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook = 0; +typedef QList<QUrl> (*_qt_filedialog_open_file_urls_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes); +Q_WIDGETS_EXPORT _qt_filedialog_open_file_urls_hook qt_filedialog_open_file_urls_hook = 0; + typedef QString (*_qt_filedialog_save_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); Q_WIDGETS_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook = 0; +typedef QUrl (*_qt_filedialog_save_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes); +Q_WIDGETS_EXPORT _qt_filedialog_save_file_url_hook qt_filedialog_save_file_url_hook = 0; + /*! \class QFileDialog \brief The QFileDialog class provides a dialog that allow users to select files or directories. @@ -243,6 +255,11 @@ Q_WIDGETS_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_h static functions will always be an application modal dialog. If you want to use sheets, use QFileDialog::open() instead. + \value DontUseCustomDirectoryIcons Always use the default directory icon. + Some platforms allow the user to set a different icon. Custom icon lookup + cause a big performance impact over network or removable drives. + Setting this will enable the QFileIconProvider::DontUseCustomDirectoryIcons + option in the icon provider. This enum value was added in Qt 5.2. */ /*! @@ -258,37 +275,76 @@ Q_WIDGETS_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_h /*! \fn void QFileDialog::filesSelected(const QStringList &selected) - When the selection changes and the dialog is accepted, this signal is - emitted with the (possibly empty) list of \a selected files. + When the selection changes for local operations and the dialog is + accepted, this signal is emitted with the (possibly empty) list + of \a selected files. \sa currentChanged(), QDialog::Accepted */ +/*! + \fn void QFileDialog::urlsSelected(const QList<QUrl> &urls) + + When the selection changes and the dialog is accepted, this signal is + emitted with the (possibly empty) list of selected \a urls. + + \sa currentUrlChanged(), QDialog::Accepted + \since 5.2 +*/ /*! \fn void QFileDialog::fileSelected(const QString &file) - When the selection changes and the dialog is accepted, this signal is - emitted with the (possibly empty) selected \a file. + When the selection changes for local operations and the dialog is + accepted, this signal is emitted with the (possibly empty) + selected \a file. \sa currentChanged(), QDialog::Accepted */ +/*! + \fn void QFileDialog::urlSelected(const QUrl &url) + + When the selection changes and the dialog is accepted, this signal is + emitted with the (possibly empty) selected \a url. + + \sa currentUrlChanged(), QDialog::Accepted + \since 5.2 +*/ /*! \fn void QFileDialog::currentChanged(const QString &path) - When the current file changes, this signal is emitted with the - new file name as the \a path parameter. + When the current file changes for local operations, this signal is + emitted with the new file name as the \a path parameter. \sa filesSelected() */ /*! + \fn void QFileDialog::currentUrlChanged(const QUrl &url) + + When the current file changes, this signal is emitted with the + new file URL as the \a url parameter. + + \sa urlsSelected() + \since 5.2 +*/ + +/*! \fn void QFileDialog::directoryEntered(const QString &directory) \since 4.3 + This signal is emitted for local operations when the user enters + a \a directory. +*/ + +/*! + \fn void QFileDialog::directoryUrlEntered(const QUrl &directory) + This signal is emitted when the user enters a \a directory. + + \since 5.2 */ /*! @@ -532,11 +588,10 @@ QFileDialogPrivate::~QFileDialogPrivate() void QFileDialogPrivate::initHelper(QPlatformDialogHelper *h) { QFileDialog *d = q_func(); - QObject::connect(h, SIGNAL(fileSelected(QString)), d, SIGNAL(fileSelected(QString))); - QObject::connect(h, SIGNAL(filesSelected(QStringList)), d, SIGNAL(filesSelected(QStringList))); - QObject::connect(h, SIGNAL(currentChanged(QString)), d, SIGNAL(currentChanged(QString))); - QObject::connect(h, SIGNAL(directoryEntered(QString)), d, SIGNAL(directoryEntered(QString))); - QObject::connect(h, SIGNAL(directoryEntered(QString)), d, SLOT(_q_nativeEnterDirectory(QString))); + QObject::connect(h, SIGNAL(fileSelected(QUrl)), d, SLOT(_q_nativeFileSelected(QUrl))); + QObject::connect(h, SIGNAL(filesSelected(QList<QUrl>)), d, SLOT(_q_nativeFilesSelected(QList<QUrl>))); + QObject::connect(h, SIGNAL(currentChanged(QUrl)), d, SLOT(_q_nativeCurrentChanged(QUrl))); + QObject::connect(h, SIGNAL(directoryEntered(QUrl)), d, SLOT(_q_nativeEnterDirectory(QUrl))); QObject::connect(h, SIGNAL(filterSelected(QString)), d, SIGNAL(filterSelected(QString))); static_cast<QPlatformFileDialogHelper *>(h)->setOptions(options); } @@ -550,8 +605,8 @@ void QFileDialogPrivate::helperPrepareShow(QPlatformDialogHelper *) options->setSidebarUrls(qFileDialogUi->sidebar->urls()); const QDir directory = q->directory(); options->setInitialDirectory(directory.exists() ? - directory.absolutePath() : - QString()); + QUrl::fromLocalFile(directory.absolutePath()) : + QUrl()); options->setInitiallySelectedNameFilter(q->selectedNameFilter()); options->setInitiallySelectedFiles(userSelectedFiles()); } @@ -742,6 +797,15 @@ void QFileDialog::setOptions(Options options) if (changed & ShowDirsOnly) setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files); + + if (changed & DontUseCustomDirectoryIcons) { + QFileIconProvider::Options providerOptions = iconProvider()->options(); + if (options & DontUseCustomDirectoryIcons) + providerOptions |= QFileIconProvider::DontUseCustomDirectoryIcons; + else + providerOptions &= ~QFileIconProvider::DontUseCustomDirectoryIcons; + iconProvider()->setOptions(providerOptions); + } } QFileDialog::Options QFileDialog::options() const @@ -850,7 +914,7 @@ void QFileDialog::setDirectory(const QString &directory) d->setLastVisitedDirectory(newDirectory); if (d->nativeDialogInUse){ - d->setDirectory_sys(newDirectory); + d->setDirectory_sys(QUrl::fromLocalFile(newDirectory)); return; } if (d->rootPath() == newDirectory) @@ -875,7 +939,42 @@ void QFileDialog::setDirectory(const QString &directory) QDir QFileDialog::directory() const { Q_D(const QFileDialog); - return QDir(d->nativeDialogInUse ? d->directory_sys() : d->rootPath()); + return QDir(d->nativeDialogInUse ? d->directory_sys().toLocalFile() : d->rootPath()); +} + +/*! + Sets the file dialog's current \a directory url. + + \note The non-native QFileDialog supports only local files. + + \since 5.2 +*/ +void QFileDialog::setDirectoryUrl(const QUrl &directory) +{ + Q_D(QFileDialog); + if (!directory.isValid()) + return; + + if (d->nativeDialogInUse) + d->setDirectory_sys(directory); + else if (directory.isLocalFile()) + setDirectory(directory.toLocalFile()); + else + qWarning() << "Non-native QFileDialog supports only local files"; +} + +/*! + Returns the url of the directory currently being displayed in the dialog. + + \since 5.2 +*/ +QUrl QFileDialog::directoryUrl() const +{ + Q_D(const QFileDialog); + if (d->nativeDialogInUse) + return d->directory_sys(); + else + return QUrl::fromLocalFile(directory().absolutePath()); } /*! @@ -890,7 +989,7 @@ void QFileDialog::selectFile(const QString &filename) return; if (d->nativeDialogInUse){ - d->selectFile_sys(filename); + d->selectFile_sys(QUrl::fromLocalFile(filename)); return; } @@ -927,6 +1026,28 @@ void QFileDialog::selectFile(const QString &filename) d->lineEdit()->setText(file); } +/*! + Selects the given \a url in the file dialog. + + \note The non-native QFileDialog supports only local files. + + \sa selectedUrls() + \since 5.2 +*/ +void QFileDialog::selectUrl(const QUrl &url) +{ + Q_D(QFileDialog); + if (!url.isValid()) + return; + + if (d->nativeDialogInUse) + d->selectFile_sys(url); + else if (url.isLocalFile()) + selectFile(url.toLocalFile()); + else + qWarning() << "Non-native QFileDialog supports only local files"; +} + #ifdef Q_OS_UNIX Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0) { @@ -1015,17 +1136,19 @@ QStringList QFileDialogPrivate::typedFiles() const // Return selected files without defaulting to the root of the file system model // used for initializing QFileDialogOptions for native dialogs. The default is // not suitable for native dialogs since it mostly equals directory(). -QStringList QFileDialogPrivate::userSelectedFiles() const +QList<QUrl> QFileDialogPrivate::userSelectedFiles() const { + QList<QUrl> files; + if (nativeDialogInUse) - return addDefaultSuffixToFiles(selectedFiles_sys()); + return addDefaultSuffixToUrls(selectedFiles_sys()); - QStringList files; foreach (const QModelIndex &index, qFileDialogUi->listView->selectionModel()->selectedRows()) - files.append(index.data(QFileSystemModel::FilePathRole).toString()); + files.append(QUrl::fromLocalFile(index.data(QFileSystemModel::FilePathRole).toString())); if (files.isEmpty() && !lineEdit()->text().isEmpty()) - files = typedFiles(); + foreach (const QString &path, typedFiles()) + files.append(QUrl::fromLocalFile(path)); return files; } @@ -1056,6 +1179,20 @@ QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList filesT return files; } +QList<QUrl> QFileDialogPrivate::addDefaultSuffixToUrls(const QList<QUrl> &urlsToFix) const +{ + QList<QUrl> urls; + for (int i=0; i<urlsToFix.size(); ++i) { + QUrl url = urlsToFix.at(i); + // if the filename has no suffix, add the default suffix + const QString defaultSuffix = options->defaultSuffix(); + if (!defaultSuffix.isEmpty() && !url.path().endsWith(QLatin1Char('/')) && url.path().lastIndexOf(QLatin1Char('.')) == -1) + url.setPath(url.path() + QLatin1Char('.') + defaultSuffix); + urls.append(url); + } + return urls; +} + /*! Returns a list of strings containing the absolute paths of the @@ -1068,7 +1205,9 @@ QStringList QFileDialog::selectedFiles() const { Q_D(const QFileDialog); - QStringList files = d->userSelectedFiles(); + QStringList files; + foreach (const QUrl &file, d->userSelectedFiles()) + files.append(file.toLocalFile()); if (files.isEmpty()) { const FileMode fm = fileMode(); if (fm != ExistingFile && fm != ExistingFiles) @@ -1077,6 +1216,27 @@ QStringList QFileDialog::selectedFiles() const return files; } +/*! + Returns a list of urls containing the selected files in the dialog. + If no files are selected, or the mode is not ExistingFiles or + ExistingFile, selectedUrls() contains the current path in the viewport. + + \sa selectedNameFilter(), selectUrl() + \since 5.2 +*/ +QList<QUrl> QFileDialog::selectedUrls() const +{ + Q_D(const QFileDialog); + if (d->nativeDialogInUse) { + return d->userSelectedFiles(); + } else { + QList<QUrl> urls; + foreach (const QString &file, selectedFiles()) + urls.append(QUrl::fromLocalFile(file)); + return urls; + } +} + /* Makes a list of filters from ;;-separated text. Used by the mac and windows implementations @@ -1526,6 +1686,8 @@ bool QFileDialog::confirmOverwrite() const filename if it has no suffix already. The suffix is typically used to indicate the file type (e.g. "txt" indicates a text file). + + If the first character is a dot ('.'), it is removed. */ void QFileDialog::setDefaultSuffix(const QString &suffix) { @@ -1798,6 +1960,48 @@ QString QFileDialog::getOpenFileName(QWidget *parent, } /*! + This is a convenience static function that returns an existing file + selected by the user. If the user presses Cancel, it returns an + empty url. + + The function is used similarly to QFileDialog::getOpenFileName(). In + particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter + and \a options are used in the exact same way. + + The main difference with QFileDialog::getOpenFileName() comes from + the ability offered to the user to select a remote file. That's why + the return type and the type of \a dir is QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to fetch the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getOpenFileName(), getOpenFileUrls(), getSaveFileUrl(), getExistingDirectoryUrl() + \since 5.2 +*/ +QUrl QFileDialog::getOpenFileUrl(QWidget *parent, + const QString &caption, + const QUrl &dir, + const QString &filter, + QString *selectedFilter, + Options options, + const QStringList &supportedSchemes) +{ + if (qt_filedialog_open_file_url_hook && !(options & DontUseNativeDialog)) + return qt_filedialog_open_file_url_hook(parent, caption, dir, filter, selectedFilter, options, supportedSchemes); + + // Falls back to local file + return QUrl::fromLocalFile(getOpenFileName(parent, caption, dir.toLocalFile(), filter, selectedFilter, options)); +} + +/*! This is a convenience static function that will return one or more existing files selected by the user. @@ -1883,6 +2087,55 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent, } /*! + This is a convenience static function that will return or or more existing + files selected by the user. If the user presses Cancel, it returns an + empty list. + + The function is used similarly to QFileDialog::getOpenFileNames(). In + particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter + and \a options are used in the exact same way. + + The main difference with QFileDialog::getOpenFileNames() comes from + the ability offered to the user to select remote files. That's why + the return type and the type of \a dir are respectively QList<QUrl> + and QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to fetch the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getOpenFileNames(), getOpenFileUrl(), getSaveFileUrl(), getExistingDirectoryUrl() + \since 5.2 +*/ +QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent, + const QString &caption, + const QUrl &dir, + const QString &filter, + QString *selectedFilter, + Options options, + const QStringList &supportedSchemes) +{ + if (qt_filedialog_open_file_urls_hook && !(options & DontUseNativeDialog)) + return qt_filedialog_open_file_urls_hook(parent, caption, dir, filter, selectedFilter, options, supportedSchemes); + + // Falls back to local files + QList<QUrl> urls; + + const QStringList fileNames = getOpenFileNames(parent, caption, dir.toLocalFile(), filter, selectedFilter, options); + foreach (const QString &fileName, fileNames) + urls << QUrl::fromLocalFile(fileName); + + return urls; +} + +/*! This is a convenience static function that will return a file name selected by the user. The file does not have to exist. @@ -1971,6 +2224,48 @@ QString QFileDialog::getSaveFileName(QWidget *parent, } /*! + This is a convenience static function that returns a file selected by + the user. The file does not have to exist. If the user presses Cancel, + it returns an empty url. + + The function is used similarly to QFileDialog::getSaveFileName(). In + particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter + and \a options are used in the exact same way. + + The main difference with QFileDialog::getSaveFileName() comes from + the ability offered to the user to select a remote file. That's why + the return type and the type of \a dir is QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to save the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getSaveFileName(), getOpenFileUrl(), getOpenFileUrls(), getExistingDirectoryUrl() + \since 5.2 +*/ +QUrl QFileDialog::getSaveFileUrl(QWidget *parent, + const QString &caption, + const QUrl &dir, + const QString &filter, + QString *selectedFilter, + Options options, + const QStringList &supportedSchemes) +{ + if (qt_filedialog_save_file_url_hook && !(options & DontUseNativeDialog)) + return qt_filedialog_save_file_url_hook(parent, caption, dir, filter, selectedFilter, options, supportedSchemes); + + // Falls back to local file + return QUrl::fromLocalFile(getSaveFileName(parent, caption, dir.toLocalFile(), filter, selectedFilter, options)); +} + +/*! This is a convenience static function that will return an existing directory selected by the user. @@ -2041,6 +2336,46 @@ QString QFileDialog::getExistingDirectory(QWidget *parent, return QString(); } +/*! + This is a convenience static function that will return an existing + directory selected by the user. If the user presses Cancel, it + returns an empty url. + + The function is used similarly to QFileDialog::getExistingDirectory(). + In particular \a parent, \a caption, \a dir and \a options are used + in the exact same way. + + The main difference with QFileDialog::getExistingDirectory() comes from + the ability offered to the user to select a remote directory. That's why + the return type and the type of \a dir is QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to fetch the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getExistingDirectory(), getOpenFileUrl(), getOpenFileUrls(), getSaveFileUrl() + \since 5.2 +*/ +QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent, + const QString &caption, + const QUrl &dir, + Options options, + const QStringList &supportedSchemes) +{ + if (qt_filedialog_existing_directory_url_hook && !(options & DontUseNativeDialog)) + return qt_filedialog_existing_directory_url_hook(parent, caption, dir, options, supportedSchemes); + + // Falls back to local file + return QUrl::fromLocalFile(getExistingDirectory(parent, caption, dir.toLocalFile(), options)); +} + inline static QString _qt_get_directory(const QString &path) { QFileInfo info = QFileInfo(QDir::current(), path); @@ -3119,10 +3454,42 @@ void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString oldNa } } -void QFileDialogPrivate::_q_nativeEnterDirectory(const QString &directory) +void QFileDialogPrivate::_q_nativeFileSelected(const QUrl &file) +{ + Q_Q(QFileDialog); + emit q->urlSelected(file); + if (file.isLocalFile()) + emit q->fileSelected(file.toLocalFile()); +} + +void QFileDialogPrivate::_q_nativeFilesSelected(const QList<QUrl> &files) +{ + Q_Q(QFileDialog); + emit q->urlsSelected(files); + QStringList localFiles; + foreach (const QUrl &file, files) + if (file.isLocalFile()) + localFiles.append(file.toLocalFile()); + if (!localFiles.isEmpty()) + emit q->filesSelected(localFiles); +} + +void QFileDialogPrivate::_q_nativeCurrentChanged(const QUrl &file) { - if (!directory.isEmpty()) // Windows native dialogs occasionally emit signals with empty strings. - *lastVisitedDir() = directory; + Q_Q(QFileDialog); + emit q->currentUrlChanged(file); + if (file.isLocalFile()) + emit q->currentChanged(file.toLocalFile()); +} + +void QFileDialogPrivate::_q_nativeEnterDirectory(const QUrl &directory) +{ + Q_Q(QFileDialog); + emit q->directoryUrlEntered(directory); + if (!directory.isEmpty() && directory.isLocalFile()) { // Windows native dialogs occasionally emit signals with empty strings. + *lastVisitedDir() = directory.toLocalFile(); + emit q->directoryEntered(directory.toLocalFile()); + } } /*! diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h index 98d1fd5695..5413a42ea9 100644 --- a/src/widgets/dialogs/qfiledialog.h +++ b/src/widgets/dialogs/qfiledialog.h @@ -44,6 +44,7 @@ #include <QtCore/qdir.h> #include <QtCore/qstring.h> +#include <QtCore/qurl.h> #include <QtWidgets/qdialog.h> QT_BEGIN_NAMESPACE @@ -58,7 +59,6 @@ class QFileIconProvider; class QFileDialogPrivate; class QAbstractItemDelegate; class QAbstractProxyModel; -class QUrl; class Q_WIDGETS_EXPORT QFileDialog : public QDialog { @@ -84,13 +84,14 @@ public: enum Option { - ShowDirsOnly = 0x00000001, - DontResolveSymlinks = 0x00000002, - DontConfirmOverwrite = 0x00000004, - DontUseSheet = 0x00000008, - DontUseNativeDialog = 0x00000010, - ReadOnly = 0x00000020, - HideNameFilterDetails = 0x00000040 + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseSheet = 0x00000008, + DontUseNativeDialog = 0x00000010, + ReadOnly = 0x00000020, + HideNameFilterDetails = 0x00000040, + DontUseCustomDirectoryIcons = 0x00000080 }; Q_DECLARE_FLAGS(Options, Option) @@ -105,9 +106,15 @@ public: inline void setDirectory(const QDir &directory); QDir directory() const; + void setDirectoryUrl(const QUrl &directory); + QUrl directoryUrl() const; + void selectFile(const QString &filename); QStringList selectedFiles() const; + void selectUrl(const QUrl &url); + QList<QUrl> selectedUrls() const; + void setNameFilterDetailsVisible(bool enabled); bool isNameFilterDetailsVisible() const; @@ -184,6 +191,12 @@ Q_SIGNALS: void filesSelected(const QStringList &files); void currentChanged(const QString &path); void directoryEntered(const QString &directory); + + void urlSelected(const QUrl &url); + void urlsSelected(const QList<QUrl> &urls); + void currentUrlChanged(const QUrl &url); + void directoryUrlEntered(const QUrl &directory); + void filterSelected(const QString &filter); public: @@ -195,6 +208,14 @@ public: QString *selectedFilter = 0, Options options = 0); + static QUrl getOpenFileUrl(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0, + const QStringList &supportedSchemes = QStringList()); + static QString getSaveFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), @@ -202,11 +223,25 @@ public: QString *selectedFilter = 0, Options options = 0); + static QUrl getSaveFileUrl(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0, + const QStringList &supportedSchemes = QStringList()); + static QString getExistingDirectory(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), Options options = ShowDirsOnly); + static QUrl getExistingDirectoryUrl(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + Options options = ShowDirsOnly, + const QStringList &supportedSchemes = QStringList()); + static QStringList getOpenFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), @@ -214,6 +249,14 @@ public: QString *selectedFilter = 0, Options options = 0); + static QList<QUrl> getOpenFileUrls(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0, + const QStringList &supportedSchemes = QStringList()); + protected: QFileDialog(const QFileDialogArgs &args); @@ -240,7 +283,10 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_updateOkButton()) Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QModelIndex &index)) Q_PRIVATE_SLOT(d_func(), void _q_enterDirectory(const QModelIndex &index)) - Q_PRIVATE_SLOT(d_func(), void _q_nativeEnterDirectory(const QString&)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeFileSelected(const QUrl &)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeFilesSelected(const QList<QUrl> &)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeCurrentChanged(const QUrl &)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeEnterDirectory(const QUrl&)) Q_PRIVATE_SLOT(d_func(), void _q_goToDirectory(const QString &path)) Q_PRIVATE_SLOT(d_func(), void _q_useNameFilter(int index)) Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged()) diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h index f8f33eb18d..e5a558bb91 100644 --- a/src/widgets/dialogs/qfiledialog_p.h +++ b/src/widgets/dialogs/qfiledialog_p.h @@ -130,8 +130,9 @@ public: static QString workingDirectory(const QString &path); static QString initialSelection(const QString &path); QStringList typedFiles() const; - QStringList userSelectedFiles() const; + QList<QUrl> userSelectedFiles() const; QStringList addDefaultSuffixToFiles(const QStringList filesToFix) const; + QList<QUrl> addDefaultSuffixToUrls(const QList<QUrl> &urlsToFix) const; bool removeDirectory(const QString &path); void setLabelTextControl(QFileDialog::DialogLabel label, const QString &text); inline void updateFileNameLabel(); @@ -206,7 +207,10 @@ public: void _q_updateOkButton(); void _q_currentChanged(const QModelIndex &index); void _q_enterDirectory(const QModelIndex &index); - void _q_nativeEnterDirectory(const QString &directory); + void _q_nativeFileSelected(const QUrl &file); + void _q_nativeFilesSelected(const QList<QUrl> &files); + void _q_nativeCurrentChanged(const QUrl &file); + void _q_nativeEnterDirectory(const QUrl &directory); void _q_goToDirectory(const QString &); void _q_useNameFilter(int index); void _q_selectionChanged(); @@ -246,10 +250,10 @@ public: // used instead. bool canBeNativeDialog(); - void setDirectory_sys(const QString &directory); - QString directory_sys() const; - void selectFile_sys(const QString &filename); - QStringList selectedFiles_sys() const; + void setDirectory_sys(const QUrl &directory); + QUrl directory_sys() const; + void selectFile_sys(const QUrl &filename); + QList<QUrl> selectedFiles_sys() const; void setFilter_sys(); void selectNameFilter_sys(const QString &filter); QString selectedNameFilter_sys() const; @@ -346,30 +350,40 @@ inline QString QFileDialogPrivate::rootPath() const { return model->rootPath(); } -inline void QFileDialogPrivate::setDirectory_sys(const QString &directory) +inline void QFileDialogPrivate::setDirectory_sys(const QUrl &directory) { - if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + QPlatformFileDialogHelper *helper = platformFileDialogHelper(); + + if (!helper) + return; + + if (helper->isSupportedUrl(directory)) helper->setDirectory(directory); } -inline QString QFileDialogPrivate::directory_sys() const +inline QUrl QFileDialogPrivate::directory_sys() const { if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) return helper->directory(); return QString(); } -inline void QFileDialogPrivate::selectFile_sys(const QString &filename) +inline void QFileDialogPrivate::selectFile_sys(const QUrl &filename) { - if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + QPlatformFileDialogHelper *helper = platformFileDialogHelper(); + + if (!helper) + return; + + if (helper->isSupportedUrl(filename)) helper->selectFile(filename); } -inline QStringList QFileDialogPrivate::selectedFiles_sys() const +inline QList<QUrl> QFileDialogPrivate::selectedFiles_sys() const { if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) return helper->selectedFiles(); - return QStringList(); + return QList<QUrl>(); } inline void QFileDialogPrivate::setFilter_sys() diff --git a/src/widgets/dialogs/qfileinfogatherer.cpp b/src/widgets/dialogs/qfileinfogatherer.cpp index 213aefe5f5..0f12c2b80e 100644 --- a/src/widgets/dialogs/qfileinfogatherer.cpp +++ b/src/widgets/dialogs/qfileinfogatherer.cpp @@ -238,7 +238,7 @@ QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const #endif #ifdef Q_OS_WIN - if (m_resolveSymlinks && fileInfo.isSymLink()) { + if (m_resolveSymlinks && info.isSymLink(/* ignoreNtfsSymLinks = */ true)) { QFileInfo resolvedInfo(fileInfo.symLinkTarget()); resolvedInfo = resolvedInfo.canonicalFilePath(); if (resolvedInfo.exists()) { diff --git a/src/widgets/dialogs/qfileinfogatherer_p.h b/src/widgets/dialogs/qfileinfogatherer_p.h index 0c4e644e40..447ee78edc 100644 --- a/src/widgets/dialogs/qfileinfogatherer_p.h +++ b/src/widgets/dialogs/qfileinfogatherer_p.h @@ -108,7 +108,13 @@ public: return QExtendedInformation::System; } - bool isSymLink() const { + bool isSymLink(bool ignoreNtfsSymLinks = false) const + { + if (ignoreNtfsSymLinks) { +#ifdef Q_OS_WIN + return !mFileInfo.suffix().compare(QLatin1String("lnk"), Qt::CaseInsensitive); +#endif + } return mFileInfo.isSymLink(); } diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 8e3ecc3e0e..519c158f81 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -800,7 +800,7 @@ QString QFileSystemModelPrivate::name(const QModelIndex &index) const if (!index.isValid()) return QString(); QFileSystemNode *dirNode = node(index); - if (fileInfoGatherer.resolveSymlinks() && !resolvedSymLinks.isEmpty() && dirNode->isSymLink()) { + if (fileInfoGatherer.resolveSymlinks() && !resolvedSymLinks.isEmpty() && dirNode->isSymLink(/* ignoreNtfsSymLinks = */ true)) { QString fullPath = QDir::fromNativeSeparators(filePath(index)); if (resolvedSymLinks.contains(fullPath)) return resolvedSymLinks[fullPath]; diff --git a/src/widgets/dialogs/qfilesystemmodel_p.h b/src/widgets/dialogs/qfilesystemmodel_p.h index d61936d545..663be3d933 100644 --- a/src/widgets/dialogs/qfilesystemmodel_p.h +++ b/src/widgets/dialogs/qfilesystemmodel_p.h @@ -116,7 +116,7 @@ public: inline bool isFile() const { if (info) return info->isFile(); return true; } inline bool isSystem() const { if (info) return info->isSystem(); return true; } inline bool isHidden() const { if (info) return info->isHidden(); return false; } - inline bool isSymLink() const { if (info) return info->isSymLink(); return false; } + inline bool isSymLink(bool ignoreNtfsSymLinks = false) const { return info && info->isSymLink(ignoreNtfsSymLinks); } inline bool caseSensitive() const { if (info) return info->isCaseSensitive(); return false; } inline QIcon icon() const { if (info) return info->icon; return QIcon(); } diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp index 313b475f1f..b989ea7c86 100644 --- a/src/widgets/dialogs/qfontdialog.cpp +++ b/src/widgets/dialogs/qfontdialog.cpp @@ -479,7 +479,22 @@ void QFontDialogPrivate::updateFamilies() enum match_t { MATCH_NONE = 0, MATCH_LAST_RESORT = 1, MATCH_APP = 2, MATCH_FAMILY = 3 }; - QStringList familyNames = fdb.families(writingSystem); + const QFontDialog::FontDialogOptions scalableMask = (QFontDialog::ScalableFonts | QFontDialog::NonScalableFonts); + const QFontDialog::FontDialogOptions spacingMask = (QFontDialog::ProportionalFonts | QFontDialog::MonospacedFonts); + const QFontDialog::FontDialogOptions options = q->options(); + + QStringList familyNames; + foreach (const QString &family, fdb.families(writingSystem)) { + if ((options & scalableMask) && (options & scalableMask) != scalableMask) { + if (bool(options & QFontDialog::ScalableFonts) != fdb.isSmoothlyScalable(family)) + continue; + } + if ((options & spacingMask) && (options & spacingMask) != spacingMask) { + if (bool(options & QFontDialog::MonospacedFonts) != fdb.isFixedPitch(family)) + continue; + } + familyNames << family; + } familyList->model()->setStringList(familyNames); @@ -837,10 +852,21 @@ QFont QFontDialog::selectedFont() const This enum specifies various options that affect the look and feel of a font dialog. + For instance, it allows to specify which type of font should be + displayed. If none are specified all fonts available will be listed. + + Note that the font filtering options might not be supported on some + platforms (e.g. Mac). They are always supported by the non native + dialog (used on Windows or Linux). + \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".) \value DontUseNativeDialog Use Qt's standard font dialog on the Mac instead of Apple's native font panel. (Currently, the native dialog is never used, but this is likely to change in future Qt releases.) + \value ScalableFonts Show scalable fonts + \value NonScalableFonts Show non scalable fonts + \value MonospacedFonts Show monospaced fonts + \value ProportionalFonts Show proportional fonts \sa options, setOption(), testOption() */ diff --git a/src/widgets/dialogs/qfontdialog.h b/src/widgets/dialogs/qfontdialog.h index c2d930bc1e..9956987cfe 100644 --- a/src/widgets/dialogs/qfontdialog.h +++ b/src/widgets/dialogs/qfontdialog.h @@ -64,7 +64,11 @@ class Q_WIDGETS_EXPORT QFontDialog : public QDialog public: enum FontDialogOption { NoButtons = 0x00000001, - DontUseNativeDialog = 0x00000002 + DontUseNativeDialog = 0x00000002, + ScalableFonts = 0x00000004, + NonScalableFonts = 0x00000008, + MonospacedFonts = 0x00000010, + ProportionalFonts = 0x00000020 }; Q_DECLARE_FLAGS(FontDialogOptions, FontDialogOption) diff --git a/src/widgets/dialogs/qinputdialog.cpp b/src/widgets/dialogs/qinputdialog.cpp index 45aa49d552..c1f8deb4eb 100644 --- a/src/widgets/dialogs/qinputdialog.cpp +++ b/src/widgets/dialogs/qinputdialog.cpp @@ -49,6 +49,7 @@ #include "qlabel.h" #include "qlayout.h" #include "qlineedit.h" +#include "qplaintextedit.h" #include "qlistwidget.h" #include "qpushbutton.h" #include "qspinbox.h" @@ -167,6 +168,7 @@ public: void ensureLayout(); void ensureLineEdit(); + void ensurePlainTextEdit(); void ensureComboBox(); void ensureListView(); void ensureIntSpinBox(); @@ -180,11 +182,13 @@ public: void ensureLayout() const { const_cast<QInputDialogPrivate *>(this)->ensureLayout(); } bool useComboBoxOrListView() const { return comboBox && comboBox->count() > 0; } void _q_textChanged(const QString &text); + void _q_plainTextEditTextChanged(); void _q_currentRowChanged(const QModelIndex &newIndex, const QModelIndex &oldIndex); mutable QLabel *label; mutable QDialogButtonBox *buttonBox; mutable QLineEdit *lineEdit; + mutable QPlainTextEdit *plainTextEdit; mutable QSpinBox *intSpinBox; mutable QDoubleSpinBox *doubleSpinBox; mutable QComboBox *comboBox; @@ -198,8 +202,8 @@ public: }; QInputDialogPrivate::QInputDialogPrivate() - : label(0), buttonBox(0), lineEdit(0), intSpinBox(0), doubleSpinBox(0), comboBox(0), listView(0), - inputWidget(0), mainLayout(0) + : label(0), buttonBox(0), lineEdit(0), plainTextEdit(0), intSpinBox(0), doubleSpinBox(0), + comboBox(0), listView(0), inputWidget(0), mainLayout(0) { } @@ -250,6 +254,21 @@ void QInputDialogPrivate::ensureLineEdit() } } +void QInputDialogPrivate::ensurePlainTextEdit() +{ + Q_Q(QInputDialog); + if (!plainTextEdit) { + plainTextEdit = new QPlainTextEdit(q); + plainTextEdit->setLineWrapMode(QPlainTextEdit::NoWrap); +#ifndef QT_NO_IM + qt_widget_private(plainTextEdit)->inheritsInputMethodHints = 1; +#endif + plainTextEdit->hide(); + QObject::connect(plainTextEdit, SIGNAL(textChanged()), + q, SLOT(_q_plainTextEditTextChanged())); + } +} + void QInputDialogPrivate::ensureComboBox() { Q_Q(QInputDialog); @@ -344,6 +363,8 @@ void QInputDialogPrivate::setInputWidget(QWidget *widget) // textValue if (widget == lineEdit) { lineEdit->setText(textValue); + } else if (widget == plainTextEdit) { + plainTextEdit->setPlainText(textValue); } else if (widget == comboBox) { setComboBoxText(textValue); } else if (widget == listView) { @@ -364,6 +385,9 @@ void QInputDialogPrivate::chooseRightTextInputWidget() } else { widget = comboBox; } + } else if (opts & QInputDialog::UsePlainTextEditForTextInput) { + ensurePlainTextEdit(); + widget = plainTextEdit; } else { ensureLineEdit(); widget = lineEdit; @@ -417,6 +441,16 @@ void QInputDialogPrivate::_q_textChanged(const QString &text) } } +void QInputDialogPrivate::_q_plainTextEditTextChanged() +{ + Q_Q(QInputDialog); + QString text = plainTextEdit->toPlainText(); + if (textValue != text) { + textValue = text; + emit q->textValueChanged(text); + } +} + void QInputDialogPrivate::_q_currentRowChanged(const QModelIndex &newIndex, const QModelIndex & /* oldIndex */) { @@ -434,8 +468,8 @@ void QInputDialogPrivate::_q_currentRowChanged(const QModelIndex &newIndex, The input value can be a string, a number or an item from a list. A label must be set to tell the user what they should enter. - Four static convenience functions are provided: getText(), getInt(), - getDouble(), and getItem(). All the functions can be used in a similar way, + Five static convenience functions are provided: getText(), getMultiLineText(), + getInt(), getDouble(), and getItem(). All the functions can be used in a similar way, for example: \snippet dialogs/standarddialogs/dialog.cpp 3 @@ -575,6 +609,8 @@ QString QInputDialog::labelText() const \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons (useful for "live dialogs"). \value UseListViewForComboBoxItems Use a QListView rather than a non-editable QComboBox for displaying the items set with setComboBoxItems(). + \value UsePlainTextEditForTextInput Use a QPlainTextEdit for multiline text input. This value was + introduced in 5.2. \sa options, setOption(), testOption() */ @@ -628,6 +664,8 @@ void QInputDialog::setOptions(InputDialogOptions options) d->buttonBox->setVisible(!(options & NoButtons)); if ((changed & UseListViewForComboBoxItems) && inputMode() == TextInput) d->chooseRightTextInputWidget(); + if ((changed & UsePlainTextEditForTextInput) && inputMode() == TextInput) + d->chooseRightTextInputWidget(); } QInputDialog::InputDialogOptions QInputDialog::options() const @@ -653,6 +691,8 @@ void QInputDialog::setTextValue(const QString &text) setInputMode(TextInput); if (d->inputWidget == d->lineEdit) { d->lineEdit->setText(text); + } else if (d->inputWidget == d->plainTextEdit) { + d->plainTextEdit->setPlainText(text); } else if (d->inputWidget == d->comboBox) { d->setComboBoxText(text); } else { @@ -1075,6 +1115,8 @@ void QInputDialog::setVisible(bool visible) d->inputWidget->setFocus(); if (d->inputWidget == d->lineEdit) { d->lineEdit->selectAll(); + } else if (d->inputWidget == d->plainTextEdit) { + d->plainTextEdit->selectAll(); } else if (d->inputWidget == d->intSpinBox) { d->intSpinBox->selectAll(); } else if (d->inputWidget == d->doubleSpinBox) { @@ -1144,7 +1186,7 @@ void QInputDialog::done(int result) want to do this, you should create the dialog yourself using one of the QInputDialog constructors. - \sa getInt(), getDouble(), getItem() + \sa getInt(), getDouble(), getItem(), getMultiLineText() */ QString QInputDialog::getText(QWidget *parent, const QString &title, const QString &label, @@ -1169,6 +1211,58 @@ QString QInputDialog::getText(QWidget *parent, const QString &title, const QStri } /*! + \since 5.2 + + Static convenience function to get a multiline string from the user. + + \a title is the text which is displayed in the title bar of the dialog. + \a label is the text which is shown to the user (it should say what should + be entered). + \a text is the default text which is placed in the plain text edit. + \a inputMethodHints is the input method hints that will be used in the + edit widget if an input method is active. + + If \a ok is nonnull \e *\a ok will be set to true if the user pressed + \uicontrol OK and to false if the user pressed \uicontrol Cancel. The dialog's parent + is \a parent. The dialog will be modal and uses the specified widget + \a flags. + + If the dialog is accepted, this function returns the text in the dialog's + plain text edit. If the dialog is rejected, a null QString is returned. + + Use this static function like this: + + \snippet dialogs/standarddialogs/dialog.cpp 4 + + \warning Do not delete \a parent during the execution of the dialog. If you + want to do this, you should create the dialog yourself using one of the + QInputDialog constructors. + + \sa getInt(), getDouble(), getItem(), getText() +*/ + +QString QInputDialog::getMultiLineText(QWidget *parent, const QString &title, const QString &label, + const QString &text, bool *ok, Qt::WindowFlags flags, + Qt::InputMethodHints inputMethodHints) +{ + QInputDialog dialog(parent, flags); + dialog.setOptions(QInputDialog::UsePlainTextEditForTextInput); + dialog.setWindowTitle(title); + dialog.setLabelText(label); + dialog.setTextValue(text); + dialog.setInputMethodHints(inputMethodHints); + + int ret = dialog.exec(); + if (ok) + *ok = !!ret; + if (ret) { + return dialog.textValue(); + } else { + return QString(); + } +} + +/*! \since 4.5 Static convenience function to get an integer input from the user. @@ -1196,7 +1290,7 @@ QString QInputDialog::getText(QWidget *parent, const QString &title, const QStri want to do this, you should create the dialog yourself using one of the QInputDialog constructors. - \sa getText(), getDouble(), getItem() + \sa getText(), getDouble(), getItem(), getMultiLineText() */ int QInputDialog::getInt(QWidget *parent, const QString &title, const QString &label, int value, @@ -1248,7 +1342,7 @@ int QInputDialog::getInt(QWidget *parent, const QString &title, const QString &l want to do this, you should create the dialog yourself using one of the QInputDialog constructors. - \sa getText(), getDouble(), getItem() + \sa getText(), getDouble(), getItem(), getMultiLineText() */ /*! @@ -1277,7 +1371,7 @@ int QInputDialog::getInt(QWidget *parent, const QString &title, const QString &l want to do this, you should create the dialog yourself using one of the QInputDialog constructors. - \sa getText(), getInt(), getItem() + \sa getText(), getInt(), getItem(), getMultiLineText() */ double QInputDialog::getDouble(QWidget *parent, const QString &title, const QString &label, @@ -1331,7 +1425,7 @@ double QInputDialog::getDouble(QWidget *parent, const QString &title, const QStr want to do this, you should create the dialog yourself using one of the QInputDialog constructors. - \sa getText(), getInt(), getDouble() + \sa getText(), getInt(), getDouble(), getMultiLineText() */ QString QInputDialog::getItem(QWidget *parent, const QString &title, const QString &label, diff --git a/src/widgets/dialogs/qinputdialog.h b/src/widgets/dialogs/qinputdialog.h index 41dca1f94f..c2c85835c8 100644 --- a/src/widgets/dialogs/qinputdialog.h +++ b/src/widgets/dialogs/qinputdialog.h @@ -78,8 +78,9 @@ class Q_WIDGETS_EXPORT QInputDialog : public QDialog public: enum InputDialogOption { - NoButtons = 0x00000001, - UseListViewForComboBoxItems = 0x00000002 + NoButtons = 0x00000001, + UseListViewForComboBoxItems = 0x00000002, + UsePlainTextEditForTextInput = 0x00000004 }; Q_DECLARE_FLAGS(InputDialogOptions, InputDialogOption) @@ -168,6 +169,9 @@ public: QLineEdit::EchoMode echo = QLineEdit::Normal, const QString &text = QString(), bool *ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone); + static QString getMultiLineText(QWidget *parent, const QString &title, const QString &label, + const QString &text = QString(), bool *ok = 0, Qt::WindowFlags flags = 0, + Qt::InputMethodHints inputMethodHints = Qt::ImhNone); static QString getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current = 0, bool editable = true, bool *ok = 0, Qt::WindowFlags flags = 0, @@ -204,6 +208,7 @@ public: private: Q_DISABLE_COPY(QInputDialog) Q_PRIVATE_SLOT(d_func(), void _q_textChanged(const QString&)) + Q_PRIVATE_SLOT(d_func(), void _q_plainTextEditTextChanged()) Q_PRIVATE_SLOT(d_func(), void _q_currentRowChanged(const QModelIndex&, const QModelIndex&)) }; diff --git a/src/widgets/doc/qtwidgets.qdocconf b/src/widgets/doc/qtwidgets.qdocconf index a989ef9363..d3c7825bc0 100644 --- a/src/widgets/doc/qtwidgets.qdocconf +++ b/src/widgets/doc/qtwidgets.qdocconf @@ -54,3 +54,6 @@ imagedirs += images \ ../../../doc/src/images \ ../../../examples/widgets/doc/images \ ../../../examples/widgets + +navigation.landingpage = "Qt Widgets" +navigation.cppclassespage = "Qt Widgets C++ Classes" diff --git a/src/widgets/doc/src/qtwidgets.qdoc b/src/widgets/doc/src/qtwidgets.qdoc index 2e3403e9d9..e6145ea17e 100644 --- a/src/widgets/doc/src/qtwidgets.qdoc +++ b/src/widgets/doc/src/qtwidgets.qdoc @@ -29,6 +29,7 @@ \module QtWidgets \title Qt Widgets C++ Classes \ingroup modules + \qtvariable widgets \brief The Qt Widgets module extends Qt GUI with C++ widget functionality. diff --git a/src/widgets/graphicsview/qgridlayoutengine.cpp b/src/widgets/graphicsview/qgridlayoutengine.cpp index 4f43a0a4ac..f741962264 100644 --- a/src/widgets/graphicsview/qgridlayoutengine.cpp +++ b/src/widgets/graphicsview/qgridlayoutengine.cpp @@ -432,6 +432,8 @@ QGridLayoutBox QGridLayoutRowData::totalBox(int start, int end) const result.q_maximumSize = 0.0; qreal nextSpacing = 0.0; for (int i = start; i < end; ++i) { + if (ignore.testBit(i)) + continue; result.add(boxes.at(i), stretches.at(i), nextSpacing); nextSpacing = spacings.at(i); } @@ -1475,7 +1477,7 @@ void QGridLayoutEngine::fillRowData(QGridLayoutRowData *rowData, const QLayoutSt int effectiveRowSpan = 1; for (int i = 1; i < itemRowSpan; ++i) { - if (!rowData->ignore.testBit(i)) + if (!rowData->ignore.testBit(i + itemRow)) ++effectiveRowSpan; } @@ -1713,7 +1715,8 @@ void QGridLayoutEngine::ensureGeometries(const QLayoutStyleInfo &styleInfo, q_descents.resize(rowCount()); if (constraintOrientation() != Qt::Horizontal) { - //We might have items whose width depends on their height + // We might have items whose height depends on their width, + // or none of the items has a dynamic constraint. ensureColumnAndRowData(&q_columnData, &q_totalBoxes[Hor], styleInfo, NULL, NULL, Qt::Horizontal); //Calculate column widths and positions, and put results in q_xx.data() and q_widths.data() so that we can use this information as //constraints to find the row heights @@ -1724,7 +1727,7 @@ void QGridLayoutEngine::ensureGeometries(const QLayoutStyleInfo &styleInfo, q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(), q_descents.data(), q_totalBoxes[Ver], q_infos[Ver]); } else { - //We have items whose height depends on their width + // We have items whose width depends on their height ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], styleInfo, NULL, NULL, Qt::Vertical); //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() so that we can use this information as //constraints to find the column widths diff --git a/src/widgets/itemviews/itemviews.pri b/src/widgets/itemviews/itemviews.pri index 0bc0309271..4e152d18bb 100644 --- a/src/widgets/itemviews/itemviews.pri +++ b/src/widgets/itemviews/itemviews.pri @@ -26,6 +26,7 @@ HEADERS += \ itemviews/qtreewidgetitemiterator.h \ itemviews/qdatawidgetmapper.h \ itemviews/qfileiconprovider.h \ + itemviews/qfileiconprovider_p.h \ itemviews/qcolumnviewgrip_p.h \ itemviews/qcolumnview.h \ itemviews/qcolumnview_p.h \ diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 70c8f44a73..b79525b9df 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -1108,6 +1108,7 @@ void QAbstractItemView::reset() QAccessible::updateAccessibility(&accessibleEvent); } #endif + d->updateGeometry(); } /*! @@ -1124,6 +1125,7 @@ void QAbstractItemView::setRootIndex(const QModelIndex &index) } d->root = index; d->doDelayedItemsLayout(); + d->updateGeometry(); } /*! @@ -2668,8 +2670,10 @@ void QAbstractItemView::updateEditorGeometries() */ void QAbstractItemView::updateGeometries() { + Q_D(QAbstractItemView); updateEditorGeometries(); - d_func()->fetchMoreTimer.start(0, this); //fetch more later + d->fetchMoreTimer.start(0, this); //fetch more later + d->updateGeometry(); } /*! @@ -3231,6 +3235,7 @@ void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelInde QAccessible::updateAccessibility(&accessibleEvent); } #endif + d->updateGeometry(); } /*! @@ -3332,6 +3337,7 @@ void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &index, int star QAccessible::updateAccessibility(&accessibleEvent); } #endif + updateGeometry(); } /*! @@ -3412,6 +3418,7 @@ void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &index, int s QAccessible::updateAccessibility(&accessibleEvent); } #endif + updateGeometry(); } @@ -3435,6 +3442,7 @@ void QAbstractItemViewPrivate::_q_rowsInserted(const QModelIndex &index, int sta QAccessible::updateAccessibility(&accessibleEvent); } #endif + updateGeometry(); } /*! @@ -3459,6 +3467,7 @@ void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int QAccessible::updateAccessibility(&accessibleEvent); } #endif + updateGeometry(); } /*! @@ -4084,7 +4093,14 @@ void QAbstractItemViewPrivate::interruptDelayedItemsLayout() const delayedPendingLayout = false; } - +void QAbstractItemViewPrivate::updateGeometry() +{ + Q_Q(QAbstractItemView); + if (sizeAdjustPolicy == QAbstractScrollArea::AdjustIgnored) + return; + if (sizeAdjustPolicy == QAbstractScrollArea::AdjustToContents || !shownOnce) + q->updateGeometry(); +} QWidget *QAbstractItemViewPrivate::editor(const QModelIndex &index, const QStyleOptionViewItem &options) diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index 86eab174ed..5da22615e2 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -127,6 +127,8 @@ public: void doDelayedItemsLayout(int delay = 0); void interruptDelayedItemsLayout() const; + void updateGeometry(); + void startAutoScroll() { // ### it would be nice to make this into a style hint one day int scrollInterval = (verticalScrollMode == QAbstractItemView::ScrollPerItem) ? 150 : 50; diff --git a/src/widgets/itemviews/qcolumnview.cpp b/src/widgets/itemviews/qcolumnview.cpp index 5aee78fab4..32a3dddca1 100644 --- a/src/widgets/itemviews/qcolumnview.cpp +++ b/src/widgets/itemviews/qcolumnview.cpp @@ -332,11 +332,14 @@ void QColumnView::scrollTo(const QModelIndex &index, ScrollHint hint) } #ifndef QT_NO_ANIMATION - d->currentAnimation.setEndValue(newScrollbarValue); - d->currentAnimation.start(); -#else - horizontalScrollBar()->setValue(newScrollbarValue); + if (style()->styleHint(QStyle::SH_Widget_Animate, 0, this)) { + d->currentAnimation.setEndValue(newScrollbarValue); + d->currentAnimation.start(); + } else #endif //QT_NO_ANIMATION + { + horizontalScrollBar()->setValue(newScrollbarValue); + } } /*! diff --git a/src/widgets/itemviews/qfileiconprovider.cpp b/src/widgets/itemviews/qfileiconprovider.cpp index 8a0736ec70..71697ddc40 100644 --- a/src/widgets/itemviews/qfileiconprovider.cpp +++ b/src/widgets/itemviews/qfileiconprovider.cpp @@ -40,9 +40,8 @@ ****************************************************************************/ #include "qfileiconprovider.h" +#include "qfileiconprovider_p.h" -#ifndef QT_NO_FILEICONPROVIDER -#include <qstyle.h> #include <qapplication.h> #include <qdir.h> #include <qpixmapcache.h> @@ -83,34 +82,15 @@ QT_BEGIN_NAMESPACE \value File */ -class QFileIconProviderPrivate -{ - Q_DECLARE_PUBLIC(QFileIconProvider) - -public: - QFileIconProviderPrivate(); - QIcon getIcon(QStyle::StandardPixmap name) const; - QIcon getIcon(const QFileInfo &fi) const; - - QFileIconProvider *q_ptr; - const QString homePath; - -private: - mutable QIcon file; - mutable QIcon fileLink; - mutable QIcon directory; - mutable QIcon directoryLink; - mutable QIcon harddisk; - mutable QIcon floppy; - mutable QIcon cdrom; - mutable QIcon ram; - mutable QIcon network; - mutable QIcon computer; - mutable QIcon desktop; - mutable QIcon trashcan; - mutable QIcon generic; - mutable QIcon home; -}; + +/*! + \enum QFileIconProvider::Option + \since 5.2 + + \value DontUseCustomDirectoryIcons Always use the default directory icon. + Some platforms allow the user to set a different icon. Custom icon lookup + cause a big performance impact over network or removable drives. +*/ QFileIconProviderPrivate::QFileIconProviderPrivate() : homePath(QDir::home().absolutePath()) @@ -193,6 +173,31 @@ QFileIconProvider::~QFileIconProvider() } /*! + \since 5.2 + Sets \a options that affect the icon provider. + \sa options() +*/ + +void QFileIconProvider::setOptions(QFileIconProvider::Options options) +{ + Q_D(QFileIconProvider); + d->options = options; +} + +/*! + \since 5.2 + Returns all the options that affect the icon provider. + By default, all options are disabled. + \sa setOptions() +*/ + +QFileIconProvider::Options QFileIconProvider::options() const +{ + Q_D(const QFileIconProvider); + return d->options; +} + +/*! Returns an icon set for the given \a type. */ @@ -220,6 +225,23 @@ QIcon QFileIconProvider::icon(IconType type) const return QIcon(); } +static bool isCacheable(const QFileInfo &fi) +{ + if (!fi.isFile()) + return false; + +#ifdef Q_OS_WIN + // On windows it's faster to just look at the file extensions. QTBUG-13182 + const QString fileExtension = fi.suffix(); + // Will return false for .exe, .lnk and .ico extensions + return fileExtension.compare(QLatin1String("exe"), Qt::CaseInsensitive) && + fileExtension.compare(QLatin1String("lnk"), Qt::CaseInsensitive) && + fileExtension.compare(QLatin1String("ico"), Qt::CaseInsensitive); +#else + return !fi.isExecutable() && !fi.isSymLink(); +#endif +} + QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const { QIcon retIcon; @@ -231,10 +253,9 @@ QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const if (sizes.isEmpty()) return retIcon; - const QString fileExtension = fi.suffix().toUpper(); const QString keyBase = QLatin1String("qt_.") + fi.suffix().toUpper(); - bool cacheable = fi.isFile() && !fi.isExecutable() && !fi.isSymLink() && fileExtension != QLatin1String("ICO"); + bool cacheable = isCacheable(fi); if (cacheable) { QPixmap pixmap; QPixmapCache::find(keyBase + QString::number(sizes.at(0)), pixmap); @@ -253,8 +274,12 @@ QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const } } + QPlatformTheme::IconOptions iconOptions; + if (options & QFileIconProvider::DontUseCustomDirectoryIcons) + iconOptions |= QPlatformTheme::DontUseCustomDirectoryIcons; + Q_FOREACH (int size, sizes) { - QPixmap pixmap = theme->fileIconPixmap(fi, QSizeF(size, size)); + QPixmap pixmap = theme->fileIconPixmap(fi, QSizeF(size, size), iconOptions); if (!pixmap.isNull()) { retIcon.addPixmap(pixmap); if (cacheable) @@ -372,5 +397,3 @@ QString QFileIconProvider::type(const QFileInfo &info) const } QT_END_NAMESPACE - -#endif diff --git a/src/widgets/itemviews/qfileiconprovider.h b/src/widgets/itemviews/qfileiconprovider.h index cac135fe71..6f7e28395b 100644 --- a/src/widgets/itemviews/qfileiconprovider.h +++ b/src/widgets/itemviews/qfileiconprovider.h @@ -49,8 +49,6 @@ QT_BEGIN_NAMESPACE -#ifndef QT_NO_FILEICONPROVIDER - class QFileIconProviderPrivate; class Q_WIDGETS_EXPORT QFileIconProvider @@ -59,19 +57,27 @@ public: QFileIconProvider(); virtual ~QFileIconProvider(); enum IconType { Computer, Desktop, Trashcan, Network, Drive, Folder, File }; + + enum Option { + DontUseCustomDirectoryIcons = 0x00000001 + }; + Q_DECLARE_FLAGS(Options, Option) + virtual QIcon icon(IconType type) const; virtual QIcon icon(const QFileInfo &info) const; virtual QString type(const QFileInfo &info) const; + void setOptions(Options options); + Options options() const; + private: Q_DECLARE_PRIVATE(QFileIconProvider) QScopedPointer<QFileIconProviderPrivate> d_ptr; Q_DISABLE_COPY(QFileIconProvider) }; -#endif // QT_NO_FILEICONPROVIDER +Q_DECLARE_OPERATORS_FOR_FLAGS(QFileIconProvider::Options) QT_END_NAMESPACE #endif // QFILEICONPROVIDER_H - diff --git a/src/widgets/itemviews/qfileiconprovider_p.h b/src/widgets/itemviews/qfileiconprovider_p.h new file mode 100644 index 0000000000..9b2d536258 --- /dev/null +++ b/src/widgets/itemviews/qfileiconprovider_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILEICONPROVIDER_P_H +#define QFILEICONPROVIDER_P_H + +#include "qfileiconprovider.h" + +#include <QtCore/qstring.h> +#include <QtGui/qicon.h> +#include <QtWidgets/qstyle.h> + +QT_BEGIN_NAMESPACE + +class QFileInfo; + +class QFileIconProviderPrivate +{ + Q_DECLARE_PUBLIC(QFileIconProvider) + +public: + QFileIconProviderPrivate(); + QIcon getIcon(QStyle::StandardPixmap name) const; + QIcon getIcon(const QFileInfo &fi) const; + + QFileIconProvider *q_ptr; + const QString homePath; + QFileIconProvider::Options options; + +private: + mutable QIcon file; + mutable QIcon fileLink; + mutable QIcon directory; + mutable QIcon directoryLink; + mutable QIcon harddisk; + mutable QIcon floppy; + mutable QIcon cdrom; + mutable QIcon ram; + mutable QIcon network; + mutable QIcon computer; + mutable QIcon desktop; + mutable QIcon trashcan; + mutable QIcon generic; + mutable QIcon home; +}; + +QT_END_NAMESPACE + +#endif // QFILEICONPROVIDER_P_H diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index edfbc5c8f1..c9a845fc7b 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -550,6 +550,22 @@ QSize QHeaderView::sizeHint() const } /*! + \reimp +*/ + +void QHeaderView::setVisible(bool v) +{ + bool actualChange = (v != isVisible()); + QAbstractItemView::setVisible(v); + if (actualChange) { + QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea*>(parentWidget()); + if (parent) + parent->updateGeometry(); + } +} + + +/*! Returns a suitable size hint for the section specified by \a logicalIndex. \sa sizeHint(), defaultSectionSize(), minimumSectionSize(), @@ -918,6 +934,18 @@ void QHeaderView::resizeSection(int logical, int size) d->doDelayedResizeSections(); r = d->viewport->rect(); } + + // If the parent is a QAbstractScrollArea with QAbstractScrollArea::AdjustToContents + // then we want to change the geometry on that widget. Not doing it at once can/will + // cause scrollbars flicker as they would be shown at first but then removed. + // In the same situation it will also allow shrinking the whole view when stretchLastSection is set + // (It is default on QTreeViews - and it wouldn't shrink since the last stretch was made before the + // viewport was resized) + + QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea *>(parentWidget()); + if (parent && parent->sizeAdjustPolicy() == QAbstractScrollArea::AdjustToContents) + parent->updateGeometry(); + d->viewport->update(r.normalized()); emit sectionResized(logical, oldSize, size); } @@ -1225,7 +1253,7 @@ void QHeaderView::setSectionResizeMode(ResizeMode mode) property is set to true. This is the default for the horizontal headers provided by QTreeView. - \sa setStretchLastSection() + \sa setStretchLastSection(), resizeContentsPrecision() */ void QHeaderView::setSectionResizeMode(int logicalIndex, ResizeMode mode) @@ -1288,6 +1316,53 @@ QHeaderView::ResizeMode QHeaderView::sectionResizeMode(int logicalIndex) const return d->headerSectionResizeMode(visual); } +/*! + \since 5.2 + Sets how precise QHeaderView should calculate the size when ResizeToContents is used. + A low value will provide a less accurate but fast auto resize while a higher + value will provide a more accurate resize that however can be slow. + + The number \a precision specifies how many sections that should be consider + when calculating the preferred size. + + The default value is 1000 meaning that a horizontal column with auto-resize will look + at maximum 1000 rows on calculating when doing an auto resize. + + Special value 0 means that it will look at only the visible area. + Special value -1 will imply looking at all elements. + + This value is used in QTableView::sizeHintForColumn(), QTableView::sizeHintForRow() + and QTreeView::sizeHintForColumn(). Reimplementing these functions can make this + function not having an effect. + + If \a resizeSectionsNow is set to true (default) it will do adjustment of sections by calling + resizeSections(). (regardless if the precision was changed). + + \sa resizeContentsPrecision(), setSectionResizeMode(), resizeSections(), QTableView::sizeHintForColumn(), QTableView::sizeHintForRow(), QTreeView::sizeHintForColumn() +*/ + +void QHeaderView::setResizeContentsPrecision(int precision, bool resizeSectionsNow) +{ + Q_D(QHeaderView); + d->resizeContentsPrecision = precision; + if (resizeSectionsNow) + resizeSections(); +} + +/*! + \since 5.2 + Returns how precise QHeaderView will calculate on ResizeToContents. + + \sa setResizeContentsPrecision(), setSectionResizeMode() + +*/ + +int QHeaderView::resizeContentsPrecision() const +{ + Q_D(const QHeaderView); + return d->resizeContentsPrecision; +} + // ### Qt 6 - remove this obsolete function /*! \obsolete @@ -3512,6 +3587,19 @@ int QHeaderViewPrivate::adjustedVisualIndex(int visualIndex) const return visualIndex; } +void QHeaderViewPrivate::setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode) +{ + Q_Q(QHeaderView); + if (scrollMode == QAbstractItemView::ScrollPerItem) { + if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum()) + q->setOffsetToLastSection(); + else + q->setOffsetToSectionPosition(scrollBar->value()); + } else { + q->setOffset(scrollBar->value()); + } +} + #ifndef QT_NO_DATASTREAM void QHeaderViewPrivate::write(QDataStream &out) const { @@ -3542,6 +3630,8 @@ void QHeaderViewPrivate::write(QDataStream &out) const out << int(globalResizeMode); out << sectionItems; + if (out.version() >= QDataStream::Qt_5_2) + out << resizeContentsPrecision; } bool QHeaderViewPrivate::read(QDataStream &in) @@ -3593,6 +3683,10 @@ bool QHeaderViewPrivate::read(QDataStream &in) } sectionItems = newSectionItems; recalcSectionStartPos(); + + if (in.version() >= QDataStream::Qt_5_2) + in >> resizeContentsPrecision; + return true; } diff --git a/src/widgets/itemviews/qheaderview.h b/src/widgets/itemviews/qheaderview.h index 8fcd8d7a36..3de3d320bf 100644 --- a/src/widgets/itemviews/qheaderview.h +++ b/src/widgets/itemviews/qheaderview.h @@ -84,6 +84,7 @@ public: int offset() const; int length() const; QSize sizeHint() const; + void setVisible(bool v); int sectionSizeHint(int logicalIndex) const; int visualIndexAt(int position) const; @@ -132,6 +133,10 @@ public: ResizeMode sectionResizeMode(int logicalIndex) const; void setSectionResizeMode(ResizeMode mode); void setSectionResizeMode(int logicalIndex, ResizeMode mode); + + void setResizeContentsPrecision(int precision, bool resizeNow = true); + int resizeContentsPrecision() const; + #if QT_DEPRECATED_SINCE(5, 0) inline QT_DEPRECATED void setResizeMode(ResizeMode mode) { setSectionResizeMode(mode); } diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h index 7fda0c8873..c56e0d6196 100644 --- a/src/widgets/itemviews/qheaderview_p.h +++ b/src/widgets/itemviews/qheaderview_p.h @@ -99,7 +99,8 @@ public: sectionIndicatorOffset(0), sectionIndicator(0), globalResizeMode(QHeaderView::Interactive), - sectionStartposRecalc(true) + sectionStartposRecalc(true), + resizeContentsPrecision(1000) {} @@ -291,6 +292,7 @@ public: QHeaderView::ResizeMode globalResizeMode; QList<QPersistentModelIndex> persistentHiddenSections; mutable bool sectionStartposRecalc; + int resizeContentsPrecision; // header sections struct SectionItem { @@ -341,6 +343,7 @@ public: // other int viewSectionSizeHint(int logical) const; int adjustedVisualIndex(int visualIndex) const; + void setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode); #ifndef QT_NO_DATASTREAM void write(QDataStream &out) const; diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index 39d03124ce..1573e97981 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -347,7 +347,11 @@ void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int en bool changed = false; for (int i = 0; i < count; ++i) { int oldRow = sorting.at(i).second; + int tmpitepos = lit - tmp.begin(); QListWidgetItem *item = tmp.takeAt(oldRow); + if (tmpitepos > tmp.size()) + --tmpitepos; + lit = tmp.begin() + tmpitepos; lit = sortedInsertionIterator(lit, tmp.end(), order, item); int newRow = qMax(lit - tmp.begin(), 0); lit = tmp.insert(lit, item); diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index a6623b9462..d282397c1b 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -931,6 +931,59 @@ void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItem & } /*! + \internal + Get sizeHint width for single Index (providing existing hint and style option) +*/ +int QTableViewPrivate::widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option) const +{ + Q_Q(const QTableView); + QWidget *editor = editorForIndex(index).widget.data(); + if (editor && persistent.contains(editor)) { + hint = qMax(hint, editor->sizeHint().width()); + int min = editor->minimumSize().width(); + int max = editor->maximumSize().width(); + hint = qBound(min, hint, max); + } + hint = qMax(hint, q->itemDelegate(index)->sizeHint(option, index).width()); + return hint; +} + +/*! + \internal + Get sizeHint height for single Index (providing existing hint and style option) +*/ +int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QStyleOptionViewItem &option) const +{ + Q_Q(const QTableView); + QWidget *editor = editorForIndex(index).widget.data(); + if (editor && persistent.contains(editor)) { + hint = qMax(hint, editor->sizeHint().height()); + int min = editor->minimumSize().height(); + int max = editor->maximumSize().height(); + hint = qBound(min, hint, max); + } + + if (wrapItemText) {// for wrapping boundaries + option.rect.setY(q->rowViewportPosition(index.row())); + int height = q->rowHeight(index.row()); + // if the option.height == 0 then q->itemDelegate(index)->sizeHint(option, index) will be wrong. + // The option.height == 0 is used to conclude that the text is not wrapped, and hence it will + // (exactly like widthHintForIndex) return a QSize with a long width (that we don't use) - + // and the height of the text if it was/is on one line. + // What we want is a height hint for the current width (and we know that this section is not hidden) + // Therefore we catch this special situation with: + if (height == 0) + height = 1; + option.rect.setHeight(height); + option.rect.setX(q->columnViewportPosition(index.column())); + option.rect.setWidth(q->columnWidth(index.column())); + } + hint = qMax(hint, q->itemDelegate(index)->sizeHint(option, index).height()); + return hint; +} + + +/*! \class QTableView \brief The QTableView class provides a default model/view @@ -1056,6 +1109,19 @@ QTableView::~QTableView() /*! \reimp */ +QSize QTableView::viewportSizeHint() const +{ + Q_D(const QTableView); + QSize result( (d->verticalHeader->isHidden() ? 0 : d->verticalHeader->width()) + d->horizontalHeader->length(), + (d->horizontalHeader->isHidden() ? 0 : d->horizontalHeader->height()) + d->verticalHeader->length()); + result += QSize(verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0, + horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0); + return result; +} + +/*! + \reimp +*/ void QTableView::setModel(QAbstractItemModel *model) { Q_D(QTableView); @@ -1113,15 +1179,7 @@ void QTableView::doItemsLayout() { Q_D(QTableView); QAbstractItemView::doItemsLayout(); - if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { - const int max = verticalScrollBar()->maximum(); - if (max > 0 && verticalScrollBar()->value() == max) - d->verticalHeader->setOffsetToLastSection(); - else - d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value()); - } else { - d->verticalHeader->setOffset(verticalScrollBar()->value()); - } + d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode()); if (!d->verticalHeader->updatesEnabled()) d->verticalHeader->setUpdatesEnabled(true); } @@ -1258,29 +1316,19 @@ void QTableView::scrollContentsBy(int dx, int dy) dx = isRightToLeft() ? -dx : dx; if (dx) { + int oldOffset = d->horizontalHeader->offset(); + d->horizontalHeader->d_func()->setScrollOffset(horizontalScrollBar(), horizontalScrollMode()); if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) { - int oldOffset = d->horizontalHeader->offset(); - if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum()) - d->horizontalHeader->setOffsetToLastSection(); - else - d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value()); int newOffset = d->horizontalHeader->offset(); dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset; - } else { - d->horizontalHeader->setOffset(horizontalScrollBar()->value()); } } if (dy) { + int oldOffset = d->verticalHeader->offset(); + d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode()); if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { - int oldOffset = d->verticalHeader->offset(); - if (verticalScrollBar()->value() == verticalScrollBar()->maximum()) - d->verticalHeader->setOffsetToLastSection(); - else - d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value()); int newOffset = d->verticalHeader->offset(); dy = oldOffset - newOffset; - } else { - d->verticalHeader->setOffset(verticalScrollBar()->value()); } } d->scrollContentsBy(dx, dy); @@ -1760,13 +1808,13 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi visualRow = bottom; break; case MovePageUp: { - int newRow = rowAt(visualRect(current).top() - d->viewport->height()); + int newRow = rowAt(visualRect(current).bottom() - d->viewport->height()); if (newRow == -1) newRow = d->logicalRow(0); return d->model->index(newRow, current.column(), d->root); } case MovePageDown: { - int newRow = rowAt(visualRect(current).bottom() + d->viewport->height()); + int newRow = rowAt(visualRect(current).top() + d->viewport->height()); if (newRow == -1) newRow = d->logicalRow(bottom); return d->model->index(newRow, current.column(), d->root); @@ -2175,7 +2223,7 @@ void QTableView::updateGeometries() if a larger row height is required by either the vertical header or the item delegate, that width will be used instead. - \sa QWidget::sizeHint, verticalHeader() + \sa QWidget::sizeHint, verticalHeader(), QHeaderView::resizeContentsPrecision() */ int QTableView::sizeHintForRow(int row) const { @@ -2185,6 +2233,8 @@ int QTableView::sizeHintForRow(int row) const return -1; ensurePolished(); + const int maximumProcessCols = d->verticalHeader->resizeContentsPrecision(); + int left = qMax(0, d->horizontalHeader->visualIndexAt(0)); int right = d->horizontalHeader->visualIndexAt(d->viewport->width()); @@ -2195,27 +2245,55 @@ int QTableView::sizeHintForRow(int row) const int hint = 0; QModelIndex index; - for (int column = left; column <= right; ++column) { + int columnsProcessed = 0; + int column = left; + for (; column <= right; ++column) { int logicalColumn = d->horizontalHeader->logicalIndex(column); if (d->horizontalHeader->isSectionHidden(logicalColumn)) continue; index = d->model->index(row, logicalColumn, d->root); - if (d->wrapItemText) {// for wrapping boundaries - option.rect.setY(rowViewportPosition(index.row())); - option.rect.setHeight(rowHeight(index.row())); - option.rect.setX(columnViewportPosition(index.column())); - option.rect.setWidth(columnWidth(index.column())); - } + hint = d->heightHintForIndex(index, hint, option); + + ++columnsProcessed; + if (columnsProcessed == maximumProcessCols) + break; + } - QWidget *editor = d->editorForIndex(index).widget.data(); - if (editor && d->persistent.contains(editor)) { - hint = qMax(hint, editor->sizeHint().height()); - int min = editor->minimumSize().height(); - int max = editor->maximumSize().height(); - hint = qBound(min, hint, max); + int actualRight = d->model->columnCount(d->root) - 1; + int idxLeft = left; + int idxRight = column - 1; + + if (maximumProcessCols == 0) + columnsProcessed = 0; // skip the while loop + + while (columnsProcessed != maximumProcessCols && (idxLeft > 0 || idxRight < actualRight)) { + int logicalIdx = -1; + + if ((columnsProcessed % 2 && idxLeft > 0) || idxRight == actualRight) { + while (idxLeft > 0) { + --idxLeft; + int logcol = d->horizontalHeader->logicalIndex(idxLeft); + if (d->horizontalHeader->isSectionHidden(logcol)) + continue; + logicalIdx = logcol; + break; + } + } else { + while (idxRight < actualRight) { + ++idxRight; + int logcol = d->horizontalHeader->logicalIndex(idxRight); + if (d->horizontalHeader->isSectionHidden(logcol)) + continue; + logicalIdx = logcol; + break; + } } + if (logicalIdx < 0) + continue; - hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).height()); + index = d->model->index(row, logicalIdx, d->root); + hint = d->heightHintForIndex(index, hint, option); + ++columnsProcessed; } return d->showGrid ? hint + 1 : hint; @@ -2234,7 +2312,7 @@ int QTableView::sizeHintForRow(int row) const required by either the horizontal header or the item delegate, the larger width will be used instead. - \sa QWidget::sizeHint, horizontalHeader() + \sa QWidget::sizeHint, horizontalHeader(), QHeaderView::resizeContentsPrecision() */ int QTableView::sizeHintForColumn(int column) const { @@ -2244,6 +2322,7 @@ int QTableView::sizeHintForColumn(int column) const return -1; ensurePolished(); + const int maximumProcessRows = d->horizontalHeader->resizeContentsPrecision(); int top = qMax(0, d->verticalHeader->visualIndexAt(0)); int bottom = d->verticalHeader->visualIndexAt(d->viewport->height()); @@ -2253,22 +2332,56 @@ int QTableView::sizeHintForColumn(int column) const QStyleOptionViewItem option = d->viewOptions(); int hint = 0; + int rowsProcessed = 0; QModelIndex index; - for (int row = top; row <= bottom; ++row) { + int row = top; + for (; row <= bottom; ++row) { int logicalRow = d->verticalHeader->logicalIndex(row); if (d->verticalHeader->isSectionHidden(logicalRow)) continue; index = d->model->index(logicalRow, column, d->root); - QWidget *editor = d->editorForIndex(index).widget.data(); - if (editor && d->persistent.contains(editor)) { - hint = qMax(hint, editor->sizeHint().width()); - int min = editor->minimumSize().width(); - int max = editor->maximumSize().width(); - hint = qBound(min, hint, max); + hint = d->widthHintForIndex(index, hint, option); + ++rowsProcessed; + if (rowsProcessed == maximumProcessRows) + break; + } + + int actualBottom = d->model->rowCount(d->root) - 1; + int idxTop = top; + int idxBottom = row - 1; + + if (maximumProcessRows == 0) + rowsProcessed = 0; // skip the while loop + + while (rowsProcessed != maximumProcessRows && (idxTop > 0 || idxBottom < actualBottom)) { + int logicalIdx = -1; + + if ((rowsProcessed % 2 && idxTop > 0) || idxBottom == actualBottom) { + while (idxTop > 0) { + --idxTop; + int logrow = d->verticalHeader->logicalIndex(idxTop); + if (d->verticalHeader->isSectionHidden(logrow)) + continue; + logicalIdx = logrow; + break; + } + } else { + while (idxBottom < actualBottom) { + ++idxBottom; + int logrow = d->verticalHeader->logicalIndex(idxBottom); + if (d->verticalHeader->isSectionHidden(logrow)) + continue; + logicalIdx = logrow; + break; + } } + if (logicalIdx < 0) + continue; - hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).width()); + index = d->model->index(logicalIdx, column, d->root); + hint = d->widthHintForIndex(index, hint, option); + ++rowsProcessed; } return d->showGrid ? hint + 1 : hint; @@ -2934,6 +3047,8 @@ void QTableView::showColumn(int column) /*! Resizes the given \a row based on the size hints of the delegate used to render each item in the row. + + \sa resizeRowsToContents(), sizeHintForRow(), QHeaderView::resizeContentsPrecision() */ void QTableView::resizeRowToContents(int row) { @@ -2946,6 +3061,8 @@ void QTableView::resizeRowToContents(int row) /*! Resizes all rows based on the size hints of the delegate used to render each item in the rows. + + \sa resizeRowToContents(), sizeHintForRow(), QHeaderView::resizeContentsPrecision() */ void QTableView::resizeRowsToContents() { @@ -2959,6 +3076,8 @@ void QTableView::resizeRowsToContents() \note Only visible columns will be resized. Reimplement sizeHintForColumn() to resize hidden columns as well. + + \sa resizeColumnsToContents(), sizeHintForColumn(), QHeaderView::resizeContentsPrecision() */ void QTableView::resizeColumnToContents(int column) { @@ -2971,6 +3090,8 @@ void QTableView::resizeColumnToContents(int column) /*! Resizes all columns based on the size hints of the delegate used to render each item in the columns. + + \sa resizeColumnToContents(), sizeHintForColumn(), QHeaderView::resizeContentsPrecision() */ void QTableView::resizeColumnsToContents() { diff --git a/src/widgets/itemviews/qtableview.h b/src/widgets/itemviews/qtableview.h index 824348dbe8..db956480d6 100644 --- a/src/widgets/itemviews/qtableview.h +++ b/src/widgets/itemviews/qtableview.h @@ -118,6 +118,8 @@ public: void sortByColumn(int column, Qt::SortOrder order); + QSize viewportSizeHint() const; + public Q_SLOTS: void selectRow(int row); void selectColumn(int column); diff --git a/src/widgets/itemviews/qtableview_p.h b/src/widgets/itemviews/qtableview_p.h index 923beec253..d36dcd2c3a 100644 --- a/src/widgets/itemviews/qtableview_p.h +++ b/src/widgets/itemviews/qtableview_p.h @@ -181,6 +181,8 @@ public: const QStyleOptionViewItem &option, QBitArray *drawn, int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn); void drawCell(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index); + int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option) const; + int heightHintForIndex(const QModelIndex &index, int hint, QStyleOptionViewItem &option) const; bool showGrid; Qt::PenStyle gridStyle; diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 6aefbb5367..b1ac4eba7b 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -335,6 +335,7 @@ void QTreeView::setHeader(QHeaderView *header) this, SLOT(updateGeometries())); setSortingEnabled(d->sortingEnabled); + d->updateGeometry(); } /*! @@ -952,6 +953,36 @@ bool QTreeView::wordWrap() const return d->wrapItemText; } +/*! + \since 5.2 + + This specifies that the tree structure should be placed at logical index \a index. + If \index is set to -1 then the tree will always follow visual index 0. + + \sa treePosition(), QHeaderView::swapSections(), QHeaderView::moveSection() +*/ + +void QTreeView::setTreePosition(int index) +{ + Q_D(QTreeView); + d->treePosition = index; + update(); +} + +/*! + \since 5.2 + + Return the logical index the tree is set on. If the return value is -1 then the + tree is placed on the visual index 0. + + \sa setTreePosition() +*/ + +int QTreeView::treePosition() const +{ + Q_D(const QTreeView); + return d->treePosition; +} /*! \reimp @@ -1067,7 +1098,7 @@ QRect QTreeView::visualRect(const QModelIndex &index) const int x = (spanning ? 0 : columnViewportPosition(index.column())); int w = (spanning ? d->header->length() : columnWidth(index.column())); // handle indentation - if (index.column() == 0) { + if (d->isTreePosition(index.column())) { int i = d->indentationForItem(vi); w -= i; if (!isRightToLeft()) @@ -1284,6 +1315,14 @@ void QTreeView::paintEvent(QPaintEvent *event) } } +int QTreeViewPrivate::logicalIndexForTree() const +{ + int index = treePosition; + if (index < 0) + index = header->logicalIndex(0); + return index; +} + void QTreeViewPrivate::paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItem *option, int y, int bottom) const { Q_Q(const QTreeView); @@ -1516,7 +1555,7 @@ void QTreeViewPrivate::calcLogicalIndices(QVector<int> *logicalIndices, QVector< if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1) || (headerSection == 0 && nextLogicalSection == -1) || spanning) pos = QStyleOptionViewItem::OnlyOne; - else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1)) + else if (isTreePosition(headerSection) || (nextLogicalSection != 0 && prevLogicalSection == -1)) pos = QStyleOptionViewItem::Beginning; else if (nextLogicalSection == 0 || nextLogicalSection == -1) pos = QStyleOptionViewItem::End; @@ -1526,6 +1565,23 @@ void QTreeViewPrivate::calcLogicalIndices(QVector<int> *logicalIndices, QVector< } } +/*! + \internal + Get sizeHint width for single index (providing existing hint and style option) and index in viewIndex i. +*/ +int QTreeViewPrivate::widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const +{ + QWidget *editor = editorForIndex(index).widget.data(); + if (editor && persistent.contains(editor)) { + hint = qMax(hint, editor->sizeHint().width()); + int min = editor->minimumSize().width(); + int max = editor->maximumSize().width(); + hint = qBound(min, hint, max); + } + int xhint = delegateForIndex(index)->sizeHint(option, index).width(); + hint = qMax(hint, xhint + (isTreePosition(index.column()) ? indentationForItem(i) : 0)); + return hint; +} /*! Draws the row in the tree view that contains the model item \a index, @@ -1668,7 +1724,7 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, alternate row color was provided by the view. For backward compatibility, this is now delegated to the style using PE_PanelViewItemRow which does the appropriate fill */ - if (headerSection == 0) { + if (d->isTreePosition(headerSection)) { const int i = d->indentationForItem(d->current); QRect branches(reverse ? position + width - i : position, y, i, height); const bool setClipRect = branches.width() > width; @@ -2400,16 +2456,11 @@ void QTreeView::scrollContentsBy(int dx, int dy) dx = isRightToLeft() ? -dx : dx; if (dx) { + int oldOffset = d->header->offset(); + d->header->d_func()->setScrollOffset(horizontalScrollBar(), horizontalScrollMode()); if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) { - int oldOffset = d->header->offset(); - if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum()) - d->header->setOffsetToLastSection(); - else - d->header->setOffsetToSectionPosition(horizontalScrollBar()->value()); int newOffset = d->header->offset(); dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset; - } else { - d->header->setOffset(horizontalScrollBar()->value()); } } @@ -2552,7 +2603,7 @@ void QTreeView::columnCountChanged(int oldCount, int newCount) /*! Resizes the \a column given to the size of its contents. - \sa columnWidth(), setColumnWidth() + \sa columnWidth(), setColumnWidth(), sizeHintForColumn(), QHeaderView::resizeContentsPrecision() */ void QTreeView::resizeColumnToContents(int column) { @@ -2619,6 +2670,35 @@ void QTreeView::selectAll() } /*! + \reimp +*/ +QSize QTreeView::viewportSizeHint() const +{ + Q_D(const QTreeView); + d->executePostedLayout(); // Make sure that viewItems are up to date. + + if (d->viewItems.size() == 0) + return QAbstractItemView::viewportSizeHint(); + + // Get rect for last item + const QRect deepestRect = visualRect(d->viewItems.last().index); + + if (!deepestRect.isValid()) + return QAbstractItemView::viewportSizeHint(); + + QSize result = QSize(d->header->length(), deepestRect.bottom() + 1); + + // add size for header + result += QSize(0, d->header->isVisible() ? d->header->height() : 0); + + // add size for scrollbars + result += QSize(verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0, + horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0); + + return result; +} + +/*! \since 4.2 Expands all expandable items. @@ -2740,7 +2820,6 @@ void QTreeView::updateGeometries() QRect vg = d->viewport->geometry(); QRect geometryRect(vg.left(), vg.top() - hint.height(), vg.width(), hint.height()); d->header->setGeometry(geometryRect); - //d->header->setOffset(horizontalScrollBar()->value()); // ### bug ??? QMetaObject::invokeMethod(d->header, "updateGeometries"); d->updateScrollBars(); d->geometryRecursionBlock = false; @@ -2760,7 +2839,7 @@ void QTreeView::updateGeometries() if a larger column width is required by either the view's header or the item delegate, that width will be used instead. - \sa QWidget::sizeHint, header() + \sa QWidget::sizeHint, header(), QHeaderView::resizeContentsPrecision() */ int QTreeView::sizeHintForColumn(int column) const { @@ -2773,28 +2852,58 @@ int QTreeView::sizeHintForColumn(int column) const QStyleOptionViewItem option = d->viewOptions(); const QVector<QTreeViewItem> viewItems = d->viewItems; - int start = 0; - int end = viewItems.count(); - if(end > 1000) { //if we have too many item this function would be too slow. - //we get a good approximation by only iterate over 1000 items. - start = qMax(0, d->firstVisibleItem() - 100); - end = qMin(end, start + 900); - } + const int maximumProcessRows = d->header->resizeContentsPrecision(); // To avoid this to take forever. + + int offset = 0; + int start = d->firstVisibleItem(&offset); + int end = d->lastVisibleItem(start, offset); - for (int i = start; i < end; ++i) { + int rowsProcessed = 0; + + for (int i = start; i <= end; ++i) { if (viewItems.at(i).spanning) continue; // we have no good size hint QModelIndex index = viewItems.at(i).index; index = index.sibling(index.row(), column); - QWidget *editor = d->editorForIndex(index).widget.data(); - if (editor && d->persistent.contains(editor)) { - w = qMax(w, editor->sizeHint().width()); - int min = editor->minimumSize().width(); - int max = editor->maximumSize().width(); - w = qBound(min, w, max); + w = d->widthHintForIndex(index, w, option, i); + ++rowsProcessed; + if (rowsProcessed == maximumProcessRows) + break; + } + + --end; + int actualBottom = viewItems.size() - 1; + + if (maximumProcessRows == 0) + rowsProcessed = 0; // skip the while loop + + while (rowsProcessed != maximumProcessRows && (start > 0 || end < actualBottom)) { + int idx = -1; + + if ((rowsProcessed % 2 && start > 0) || end == actualBottom) { + while (start > 0) { + --start; + if (viewItems.at(start).spanning) + continue; + idx = start; + break; + } + } else { + while (end < actualBottom) { + ++end; + if (viewItems.at(end).spanning) + continue; + idx = end; + break; + } } - int hint = d->delegateForIndex(index)->sizeHint(option, index).width(); - w = qMax(w, hint + (column == 0 ? d->indentationForItem(i) : 0)); + if (idx < 0) + continue; + + QModelIndex index = viewItems.at(idx).index; + index = index.sibling(index.row(), column); + w = d->widthHintForIndex(index, w, option, idx); + ++rowsProcessed; } return w; } @@ -2915,6 +3024,7 @@ void QTreeViewPrivate::initialize() header->setDefaultAlignment(Qt::AlignLeft|Qt::AlignVCenter); q->setHeader(header); #ifndef QT_NO_ANIMATION + animationsEnabled = q->style()->styleHint(QStyle::SH_Widget_Animate, 0, q); QObject::connect(&animatedOperation, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation())); #endif //QT_NO_ANIMATION } @@ -3314,7 +3424,7 @@ int QTreeViewPrivate::coordinateForItem(int item) const if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) { if (uniformRowHeights) return (item * defaultItemHeight) - vbar->value(); - // ### optimize (spans or caching) + // ### optimize (maybe do like QHeaderView by letting items have startposition) int y = 0; for (int i = 0; i < viewItems.count(); ++i) { if (i == item) @@ -3481,7 +3591,7 @@ int QTreeViewPrivate::firstVisibleItem(int *offset) const *offset = -(value % defaultItemHeight); return value / defaultItemHeight; } - int y = 0; // ### optimize (use spans ?) + int y = 0; // ### (maybe do like QHeaderView by letting items have startposition) for (int i = 0; i < viewItems.count(); ++i) { y += itemHeight(i); // the height value is cached if (y > value) { @@ -3493,6 +3603,21 @@ int QTreeViewPrivate::firstVisibleItem(int *offset) const return -1; } +int QTreeViewPrivate::lastVisibleItem(int firstVisual, int offset) const +{ + if (firstVisual < 0 || offset < 0) + firstVisual = firstVisibleItem(&offset); + int y = - offset; + int value = viewport->height(); + + for (int i = firstVisual; i < viewItems.count(); ++i) { + y += itemHeight(i); // the height value is cached + if (y > value) + return i; + } + return viewItems.size() - 1; +} + int QTreeViewPrivate::columnAt(int x) const { return header->logicalIndexAt(x); @@ -3535,7 +3660,7 @@ void QTreeViewPrivate::updateScrollBars() int contentsHeight = 0; if (uniformRowHeights) { contentsHeight = defaultItemHeight * viewItems.count(); - } else { // ### optimize (spans or caching) + } else { // ### (maybe do like QHeaderView by letting items have startposition) for (int i = 0; i < viewItems.count(); ++i) contentsHeight += itemHeight(i); } @@ -3576,7 +3701,7 @@ int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const executePostedLayout(); int x = pos.x(); int column = header->logicalIndexAt(x); - if (column != 0) + if (!isTreePosition(column)) return -1; // no logical index at x int viewItemIndex = itemAtCoordinate(pos.y()); @@ -3598,8 +3723,8 @@ QRect QTreeViewPrivate::itemDecorationRect(const QModelIndex &index) const return QRect(); int itemIndentation = indentationForItem(viewItemIndex); - int position = header->sectionViewportPosition(0); - int size = header->sectionSize(0); + int position = header->sectionViewportPosition(logicalIndexForTree()); + int size = header->sectionSize(logicalIndexForTree()); QRect rect; if (q->isRightToLeft()) diff --git a/src/widgets/itemviews/qtreeview.h b/src/widgets/itemviews/qtreeview.h index 73f11f1a48..d9c6cd9269 100644 --- a/src/widgets/itemviews/qtreeview.h +++ b/src/widgets/itemviews/qtreeview.h @@ -128,6 +128,9 @@ public: void setWordWrap(bool on); bool wordWrap() const; + void setTreePosition(int logicalIndex); + int treePosition() const; + void keyboardSearch(const QString &search); QRect visualRect(const QModelIndex &index) const; @@ -144,6 +147,8 @@ public: void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>()); void selectAll(); + QSize viewportSizeHint() const; + Q_SIGNALS: void expanded(const QModelIndex &index); void collapsed(const QModelIndex &index); diff --git a/src/widgets/itemviews/qtreeview_p.h b/src/widgets/itemviews/qtreeview_p.h index 90e83cb58c..89de435606 100644 --- a/src/widgets/itemviews/qtreeview_p.h +++ b/src/widgets/itemviews/qtreeview_p.h @@ -91,10 +91,16 @@ public: expandsOnDoubleClick(true), allColumnsShowFocus(false), current(0), spanning(false), animationsEnabled(false), columnResizeTimerID(0), - autoExpandDelay(-1), hoverBranch(-1), geometryRecursionBlock(false), hasRemovedItems(false) {} + autoExpandDelay(-1), hoverBranch(-1), geometryRecursionBlock(false), hasRemovedItems(false), + treePosition(0) {} ~QTreeViewPrivate() {} void initialize(); + int logicalIndexForTree() const; + inline bool isTreePosition(int logicalIndex) const + { + return logicalIndex == logicalIndexForTree(); + } QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const; void adjustViewOptionsForIndex(QStyleOptionViewItem *option, const QModelIndex ¤t) const; @@ -148,6 +154,7 @@ public: #endif int firstVisibleItem(int *offset = 0) const; + int lastVisibleItem(int firstVisual = -1, int offset = -1) const; int columnAt(int x) const; bool hasVisibleChildren( const QModelIndex& parent) const; @@ -171,7 +178,7 @@ public: // logicalIndices: vector of currently visibly logical indices // itemPositions: vector of view item positions (beginning/middle/end/onlyone) void calcLogicalIndices(QVector<int> *logicalIndices, QVector<QStyleOptionViewItem::ViewItemPosition> *itemPositions, int left, int right) const; - + int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const; QHeaderView *header; int indent; @@ -251,6 +258,9 @@ public: // If we should clean the set bool hasRemovedItems; + + // tree position + int treePosition; }; QT_END_NAMESPACE diff --git a/src/widgets/itemviews/qtreewidget.cpp b/src/widgets/itemviews/qtreewidget.cpp index f72abd20ab..2de7830c6a 100644 --- a/src/widgets/itemviews/qtreewidget.cpp +++ b/src/widgets/itemviews/qtreewidget.cpp @@ -623,7 +623,13 @@ void QTreeModel::ensureSorted(int column, Qt::SortOrder order, for (int i = 0; i < count; ++i) { int oldRow = sorting.at(i).second; + + int tmpitepos = lit - lst.begin(); QTreeWidgetItem *item = lst.takeAt(oldRow); + if (tmpitepos > lst.size()) + --tmpitepos; + lit = lst.begin() + tmpitepos; + lit = sortedInsertionIterator(lit, lst.end(), order, item); int newRow = qMax(lit - lst.begin(), 0); diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index b918bdb9e9..af3d134a5a 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1852,8 +1852,11 @@ bool QApplication::event(QEvent *e) if (showToolTip) { QHelpEvent e(QEvent::ToolTip, d->toolTipPos, d->toolTipGlobalPos); QApplication::sendEvent(d->toolTipWidget, &e); - if (e.isAccepted()) - d->toolTipFallAsleep.start(2000, this); + if (e.isAccepted()) { + QStyle *s = d->toolTipWidget->style(); + int sleepDelay = s->styleHint(QStyle::SH_ToolTip_FallAsleepDelay, 0, d->toolTipWidget, 0); + d->toolTipFallAsleep.start(sleepDelay, this); + } } } } else if (te->timerId() == d->toolTipFallAsleep.timerId()) { @@ -2949,12 +2952,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPoint relpos = mouse->pos(); if (e->spontaneous()) { - - if (e->type() == QEvent::MouseButtonPress) { - QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, - Qt::ClickFocus, - Qt::MouseFocusReason); - } + if (e->type() != QEvent::MouseMove) + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos); // ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms // like Mac OS X (probably others too), can optimize their views by not @@ -2967,7 +2966,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e) d->toolTipWidget = w; d->toolTipPos = relpos; d->toolTipGlobalPos = mouse->globalPos(); - d->toolTipWakeUp.start(d->toolTipFallAsleep.isActive()?20:700, this); + QStyle *s = d->toolTipWidget->style(); + int wakeDelay = s->styleHint(QStyle::SH_ToolTip_WakeUpDelay, 0, d->toolTipWidget, 0); + d->toolTipWakeUp.start(d->toolTipFallAsleep.isActive() ? 20 : wakeDelay, this); } } @@ -3042,11 +3043,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPoint relpos = wheel->pos(); bool eventAccepted = wheel->isAccepted(); - if (e->spontaneous()) { - QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, - Qt::WheelFocus, - Qt::MouseFocusReason); - } + if (e->spontaneous()) + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos); while (w) { QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(), @@ -3234,6 +3232,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e); const bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); + if (e->type() != QEvent::TouchUpdate && acceptTouchEvents && e->spontaneous()) { + const QPoint localPos = touchEvent->touchPoints()[0].pos().toPoint(); + QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos); + } + touchEvent->setTarget(widget); touchEvent->setAccepted(acceptTouchEvents); @@ -3251,16 +3254,16 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QWidget *widget = static_cast<QWidget *>(receiver); QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e); bool eventAccepted = touchEvent->isAccepted(); - if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) { - // give the widget focus if the focus policy allows it - QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, - Qt::ClickFocus, - Qt::MouseFocusReason); + bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); + + if (acceptTouchEvents && e->spontaneous()) { + const QPoint localPos = touchEvent->touchPoints()[0].pos().toPoint(); + QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos); } while (widget) { // first, try to deliver the touch event - bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); + acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); touchEvent->setTarget(widget); touchEvent->setAccepted(acceptTouchEvents); QPointer<QWidget> p = widget; @@ -3725,20 +3728,40 @@ bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event) return QGuiApplication::sendSpontaneousEvent(receiver, event); } - -void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, - Qt::FocusPolicy focusPolicy, - Qt::FocusReason focusReason) +void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, QEvent *event, QPoint localPos) { + const bool setFocusOnRelease = QGuiApplication::styleHints()->setFocusOnTouchRelease(); + Qt::FocusPolicy focusPolicy = Qt::ClickFocus; + + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::TouchBegin: + if (setFocusOnRelease) + return; + break; + case QEvent::MouseButtonRelease: + case QEvent::TouchEnd: + if (!setFocusOnRelease) + return; + break; + case QEvent::Wheel: + focusPolicy = Qt::WheelFocus; + break; + default: + return; + } + QWidget *focusWidget = widget; while (focusWidget) { if (focusWidget->isEnabled() + && focusWidget->rect().contains(localPos) && QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) { - focusWidget->setFocus(focusReason); + focusWidget->setFocus(Qt::MouseFocusReason); break; } if (focusWidget->isWindow()) break; + localPos += focusWidget->pos(); focusWidget = focusWidget->parentWidget(); } } diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 87cf259ba5..29c6902c78 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -294,9 +294,7 @@ public: private: static QApplicationPrivate *self; - static void giveFocusAccordingToFocusPolicy(QWidget *w, - Qt::FocusPolicy focusPolicy, - Qt::FocusReason focusReason); + static void giveFocusAccordingToFocusPolicy(QWidget *w, QEvent *event, QPoint localPos); static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp index 852b6b9697..0fc065e74b 100644 --- a/src/widgets/kernel/qapplication_qpa.cpp +++ b/src/widgets/kernel/qapplication_qpa.cpp @@ -198,7 +198,6 @@ void QApplicationPrivate::closePopup(QWidget *popup) // mouse release event or inside qt_replay_popup_mouse_event = false; } else { // mouse press event - QGuiApplicationPrivate::mousePressTime -= 10000; // avoid double click qt_replay_popup_mouse_event = true; } diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index a65c34adf5..8541dd984d 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -1443,7 +1443,7 @@ QDataStream &operator<<(QDataStream &stream, const QSizePolicy &policy) policy.bits.hfw << 8 | // [8] policy.bits.ctype << 9 | // [9, 13] policy.bits.wfh << 14 | // [14] - //policy.bits.padding << 15 | // [15] + policy.bits.retainSizeWhenHidden << 15 | // [15] policy.bits.verStretch << 16 | // [16, 23] policy.bits.horStretch << 24); // [24, 31] return stream << data; @@ -1468,7 +1468,7 @@ QDataStream &operator>>(QDataStream &stream, QSizePolicy &policy) policy.bits.hfw = VALUE_OF_BITS(data, 8, 1); policy.bits.ctype = VALUE_OF_BITS(data, 9, 5); policy.bits.wfh = VALUE_OF_BITS(data, 14, 1); - policy.bits.padding = 0; + policy.bits.retainSizeWhenHidden = VALUE_OF_BITS(data, 15, 1); policy.bits.verStretch = VALUE_OF_BITS(data, 16, 8); policy.bits.horStretch = VALUE_OF_BITS(data, 24, 8); return stream; diff --git a/src/widgets/kernel/qlayoutitem.cpp b/src/widgets/kernel/qlayoutitem.cpp index 223bcf1d9b..a99ea77ce2 100644 --- a/src/widgets/kernel/qlayoutitem.cpp +++ b/src/widgets/kernel/qlayoutitem.cpp @@ -682,7 +682,7 @@ bool QSpacerItem::isEmpty() const */ bool QWidgetItem::isEmpty() const { - return wid->isHidden() || wid->isWindow(); + return (wid->isHidden() && !wid->sizePolicy().retainSizeWhenHidden()) || wid->isWindow(); } /*! diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h index 2fe85cbe0c..9c6d67410a 100644 --- a/src/widgets/kernel/qsizepolicy.h +++ b/src/widgets/kernel/qsizepolicy.h @@ -131,6 +131,9 @@ public: void setHorizontalStretch(int stretchFactor) { bits.horStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); } void setVerticalStretch(int stretchFactor) { bits.verStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); } + bool retainSizeWhenHidden() const { return bits.retainSizeWhenHidden; } + void setRetainSizeWhenHidden(bool retainSize) { bits.retainSizeWhenHidden = retainSize; } + void transpose(); @@ -150,7 +153,7 @@ private: quint32 ctype : 5; quint32 hfw : 1; quint32 wfh : 1; - quint32 padding : 1; // feel free to use + quint32 retainSizeWhenHidden : 1; } bits; quint32 data; }; diff --git a/src/widgets/kernel/qsizepolicy.qdoc b/src/widgets/kernel/qsizepolicy.qdoc index 6af694d999..2c088113e1 100644 --- a/src/widgets/kernel/qsizepolicy.qdoc +++ b/src/widgets/kernel/qsizepolicy.qdoc @@ -341,6 +341,23 @@ */ /*! + \fn void QSizePolicy::retainSizeWhenHidden() const + + Returns if the layout should retain the widgets size when it is hidden. This is by default false. + + \sa setRetainSizeWhenHidden() +*/ + +/*! + \fn void QSizePolicy::setRetainSizeWhenHidden(bool retainSize) + + Set if a layout should retain the widgets size when it is hidden. + If \a retainSize is true the layout will not be changed by hiding the widget. + + \sa retainSizeWhenHidden() +*/ + +/*! \enum QSizePolicy::ControlType \since 4.3 diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index 864ed6a555..8399f94976 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -120,7 +120,7 @@ class QTipLabel : public QLabel { Q_OBJECT public: - QTipLabel(const QString &text, QWidget *w); + QTipLabel(const QString &text, QWidget *w, int msecDisplayTime); ~QTipLabel(); static QTipLabel *instance; @@ -130,11 +130,11 @@ public: bool fadingOut; - void reuseTip(const QString &text); + void reuseTip(const QString &text, int msecDisplayTime); void hideTip(); void hideTipImmediately(); void setTipRect(QWidget *w, const QRect &r); - void restartExpireTimer(); + void restartExpireTimer(int msecDisplayTime); bool tipChanged(const QPoint &pos, const QString &text, QObject *o); void placeTip(const QPoint &pos, QWidget *w); @@ -166,7 +166,7 @@ private: QTipLabel *QTipLabel::instance = 0; -QTipLabel::QTipLabel(const QString &text, QWidget *w) +QTipLabel::QTipLabel(const QString &text, QWidget *w, int msecDisplayTime) #ifndef QT_NO_STYLE_STYLESHEET : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), styleSheetParent(0), widget(0) #else @@ -187,17 +187,19 @@ QTipLabel::QTipLabel(const QString &text, QWidget *w) setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0); setMouseTracking(true); fadingOut = false; - reuseTip(text); + reuseTip(text, msecDisplayTime); } -void QTipLabel::restartExpireTimer() +void QTipLabel::restartExpireTimer(int msecDisplayTime) { int time = 10000 + 40 * qMax(0, text().length()-100); + if (msecDisplayTime > 0) + time = msecDisplayTime; expireTimer.start(time, this); hideTimer.stop(); } -void QTipLabel::reuseTip(const QString &text) +void QTipLabel::reuseTip(const QString &text, int msecDisplayTime) { #ifndef QT_NO_STYLE_STYLESHEET if (styleSheetParent){ @@ -215,7 +217,7 @@ void QTipLabel::reuseTip(const QString &text) if (fm.descent() == 2 && fm.ascent() >= 11) ++extra.rheight(); resize(sizeHint() + extra); - restartExpireTimer(); + restartExpireTimer(msecDisplayTime); } void QTipLabel::paintEvent(QPaintEvent *ev) @@ -440,6 +442,18 @@ bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o) void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect) { + showText(pos, text, w, rect, -1); +} + +/*! + \since 5.2 + \overload + This is similar to QToolTip::showText(\a pos, \a text, \a w, \a rect) but with an extra parameter \a msecDisplayTime + that specifies how long the tool tip will be displayed, in milliseconds. +*/ + +void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime) +{ if (QTipLabel::instance && QTipLabel::instance->isVisible()){ // a tip does already exist if (text.isEmpty()){ // empty text means hide current tip QTipLabel::instance->hideTip(); @@ -452,7 +466,7 @@ void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, cons if (w) localPos = w->mapFromGlobal(pos); if (QTipLabel::instance->tipChanged(localPos, text, w)){ - QTipLabel::instance->reuseTip(text); + QTipLabel::instance->reuseTip(text, msecDisplayTime); QTipLabel::instance->setTipRect(w, rect); QTipLabel::instance->placeTip(pos, w); } @@ -462,11 +476,11 @@ void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, cons if (!text.isEmpty()){ // no tip can be reused, create new tip: #ifndef Q_WS_WIN - new QTipLabel(text, w); // sets QTipLabel::instance to itself + new QTipLabel(text, w, msecDisplayTime); // sets QTipLabel::instance to itself #else // On windows, we can't use the widget as parent otherwise the window will be // raised when the tooltip will be shown - new QTipLabel(text, QApplication::desktop()->screen(QTipLabel::getTipScreen(pos, w))); + new QTipLabel(text, QApplication::desktop()->screen(QTipLabel::getTipScreen(pos, w)), msecDisplayTime); #endif QTipLabel::instance->setTipRect(w, rect); QTipLabel::instance->placeTip(pos, w); diff --git a/src/widgets/kernel/qtooltip.h b/src/widgets/kernel/qtooltip.h index 25b138b855..ccde405342 100644 --- a/src/widgets/kernel/qtooltip.h +++ b/src/widgets/kernel/qtooltip.h @@ -53,8 +53,10 @@ class Q_WIDGETS_EXPORT QToolTip { QToolTip() Q_DECL_EQ_DELETE; public: + // ### Qt 6 - merge the three showText functions below static void showText(const QPoint &pos, const QString &text, QWidget *w = 0); static void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect); + static void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecShowTime); static inline void hideText() { showText(QPoint(), QString()); } static bool isVisible(); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 49d64c5cd8..5532b04b22 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -245,6 +245,9 @@ QWidgetPrivate::QWidgetPrivate(int version) #if !defined(QT_NO_IM) , imHints(Qt::ImhNone) #endif +#ifndef QT_NO_TOOLTIP + , toolTipDuration(-1) +#endif , inheritedFontResolveMask(0) , inheritedPaletteResolveMask(0) , leftmargin(0) @@ -261,6 +264,7 @@ QWidgetPrivate::QWidgetPrivate(int version) , bg_role(QPalette::NoRole) , dirtyOpaqueChildren(1) , isOpaque(0) + , retainSizeWhenHiddenChanged(0) , inDirtyList(0) , isScrolled(0) , isMoved(0) @@ -7264,10 +7268,19 @@ void QWidget::setVisible(bool visible) create(); } -#if defined(Q_WS_X11) - if (windowType() == Qt::Window) - QApplicationPrivate::applyX11SpecificCommandLineArguments(this); -#endif + // Handling of the -qwindowgeometry, -geometry command line arguments + if (windowType() == Qt::Window && windowHandle()) { + static bool done = false; + if (!done) { + done = true; + const QRect oldGeometry = frameGeometry(); + const QRect geometry = QGuiApplicationPrivate::applyWindowGeometrySpecification(oldGeometry, windowHandle()); + if (oldGeometry.size() != geometry.size()) + resize(geometry.size()); + if (geometry.topLeft() != oldGeometry.topLeft()) + move(geometry.topLeft()); + } // done + } bool wasResized = testAttribute(Qt::WA_Resized); Qt::WindowStates initialWindowState = windowState(); @@ -8207,7 +8220,7 @@ bool QWidget::event(QEvent *event) #ifndef QT_NO_TOOLTIP case QEvent::ToolTip: if (!d->toolTip.isEmpty()) - QToolTip::showText(static_cast<QHelpEvent*>(event)->globalPos(), d->toolTip, this); + QToolTip::showText(static_cast<QHelpEvent*>(event)->globalPos(), d->toolTip, this, QRect(), d->toolTipDuration); else event->ignore(); break; @@ -9251,6 +9264,10 @@ void QWidget::setSizePolicy(QSizePolicy policy) setAttribute(Qt::WA_WState_OwnSizePolicy); if (policy == d->size_policy) return; + + if (d->size_policy.retainSizeWhenHidden() != policy.retainSizeWhenHidden()) + d->retainSizeWhenHiddenChanged = 1; + d->size_policy = policy; #ifndef QT_NO_GRAPHICSVIEW @@ -9261,6 +9278,7 @@ void QWidget::setSizePolicy(QSizePolicy policy) #endif updateGeometry(); + d->retainSizeWhenHiddenChanged = 0; if (isWindow() && d->maybeTopData()) d->topData()->sizeAdjusted = false; @@ -9389,7 +9407,9 @@ void QWidgetPrivate::updateGeometry_helper(bool forceUpdate) widgetItem->invalidateSizeCache(); QWidget *parent; if (forceUpdate || !extra || extra->minw != extra->maxw || extra->minh != extra->maxh) { - if (!q->isWindow() && !q->isHidden() && (parent = q->parentWidget())) { + const int isHidden = q->isHidden() && !size_policy.retainSizeWhenHidden() && !retainSizeWhenHiddenChanged; + + if (!q->isWindow() && !isHidden && (parent = q->parentWidget())) { if (parent->d_func()->layout) parent->d_func()->layout->invalidate(); else if (parent->isVisible()) @@ -10019,6 +10039,13 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) } #endif + // Don't set WA_NativeWindow on platforms that don't support it + if (attribute == Qt::WA_NativeWindow) { + QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); + if (!platformIntegration->hasCapability(QPlatformIntegration::NativeWidgets)) + return; + } + setAttribute_internal(attribute, on, data, d); switch (attribute) { @@ -10426,6 +10453,30 @@ QString QWidget::toolTip() const Q_D(const QWidget); return d->toolTip; } + +/*! + \property QWidget::toolTipDuration + \brief the widget's tooltip duration + \since 5.2 + + Specifies how long time the tooltip will be displayed, in milliseconds. + If the value is -1 (default) the duration is calculated depending on the length of the tooltip. + + \sa toolTip +*/ + +void QWidget::setToolTipDuration(int msec) +{ + Q_D(QWidget); + d->toolTipDuration = msec; +} + +int QWidget::toolTipDuration() const +{ + Q_D(const QWidget); + return d->toolTipDuration; +} + #endif // QT_NO_TOOLTIP diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h index f90f2ee5f5..f579dbb9cd 100644 --- a/src/widgets/kernel/qwidget.h +++ b/src/widgets/kernel/qwidget.h @@ -178,6 +178,7 @@ class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice Q_PROPERTY(bool windowModified READ isWindowModified WRITE setWindowModified DESIGNABLE isWindow) #ifndef QT_NO_TOOLTIP Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip) + Q_PROPERTY(int toolTipDuration READ toolTipDuration WRITE setToolTipDuration) #endif #ifndef QT_NO_STATUSTIP Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip) @@ -376,6 +377,8 @@ public: #ifndef QT_NO_TOOLTIP void setToolTip(const QString &); QString toolTip() const; + void setToolTipDuration(int msec); + int toolTipDuration() const; #endif #ifndef QT_NO_STATUSTIP void setStatusTip(const QString &); diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 50f32af8b0..0580f72e11 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -644,6 +644,7 @@ public: QRegion dirty; #ifndef QT_NO_TOOLTIP QString toolTip; + int toolTipDuration; #endif #ifndef QT_NO_STATUSTIP QString statusTip; @@ -687,6 +688,7 @@ public: QPalette::ColorRole bg_role : 8; uint dirtyOpaqueChildren : 1; uint isOpaque : 1; + uint retainSizeWhenHiddenChanged : 1; uint inDirtyList : 1; uint isScrolled : 1; uint isMoved : 1; diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 675ea77b30..f2bd389769 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -559,7 +559,7 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event) QPoint mapped = widget->mapFrom(m_widget, event->pos()); - QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers()); + QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers(), event->phase()); QGuiApplication::sendSpontaneousEvent(widget, &translated); } diff --git a/src/widgets/styles/images/cleartext-16.png b/src/widgets/styles/images/cleartext-16.png Binary files differnew file mode 100644 index 0000000000..74133bafff --- /dev/null +++ b/src/widgets/styles/images/cleartext-16.png diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 936eb76dad..f5b61ea6f3 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -65,6 +65,7 @@ #include <qtoolbar.h> #include <qtoolbutton.h> #include <qrubberband.h> +#include "qtreeview.h" #include <private/qcommonstylepixmaps_p.h> #include <private/qmath_p.h> #include <qdebug.h> @@ -5097,11 +5098,7 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget ret = theme->themeHint(QPlatformTheme::ToolButtonStyle).toInt(); break; case SH_RequestSoftwareInputPanel: -#ifdef Q_OS_ANDROID ret = RSIP_OnMouseClick; -#else - ret = RSIP_OnMouseClickAndAlreadyFocused; -#endif break; case SH_ScrollBar_Transient: ret = false; @@ -5109,6 +5106,24 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget case SH_Menu_SupportsSections: ret = false; break; +#ifndef QT_NO_TOOLTIP + case SH_ToolTip_WakeUpDelay: + ret = 700; + break; + case SH_ToolTip_FallAsleepDelay: + ret = 2000; + break; +#endif + case SH_Widget_Animate: +#ifndef QT_NO_TREEVIEW + if (qobject_cast<const QTreeView*>(widget)) { + ret = false; + } else +#endif + { + ret = true; + } + break; default: ret = 0; break; @@ -5289,6 +5304,13 @@ QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *opti } } break; + case SP_LineEditClearButton: { + QString themeName = rtl ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl"); + if (!QIcon::hasThemeIcon(themeName)) + themeName = QStringLiteral("edit-clear"); + pixmap = QIcon::fromTheme(themeName).pixmap(16); + } + break; default: break; } @@ -5417,6 +5439,8 @@ QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *opti return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-volume-16.png")); case SP_MediaVolumeMuted: return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-volume-muted-16.png")); + case SP_LineEditClearButton: + return QPixmap(QStringLiteral(":/qt-project.org/styles/commonstyle/images/cleartext-16.png")); #endif // QT_NO_IMAGEFORMAT_PNG default: break; diff --git a/src/widgets/styles/qgtkstyle_p.cpp b/src/widgets/styles/qgtkstyle_p.cpp index 769d822108..c53a21e59a 100644 --- a/src/widgets/styles/qgtkstyle_p.cpp +++ b/src/widgets/styles/qgtkstyle_p.cpp @@ -756,8 +756,9 @@ void QGtkStylePrivate::removeWidgetFromMap(const QHashableLatin1Literal &path) WidgetMap *map = gtkWidgetMap(); WidgetMap::iterator it = map->find(path); if (it != map->end()) { - free(const_cast<char *>(it.key().data())); + char* keyData = const_cast<char *>(it.key().data()); map->erase(it); + free(keyData); } } diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index dccc9ff3ce..8d8eb3aa46 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -1894,6 +1894,16 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SH_Menu_SupportsSections Determines if the style displays sections in menus or treat them as plain separators. Sections are separators with a text and icon hint. + \value SH_ToolTip_WakeUpDelay Determines the delay before a tooltip is shown, in milliseconds. + + \value SH_ToolTip_FallAsleepDelay Determines the delay (in milliseconds) before a new wake time is needed when + a tooltip is shown (notice: shown, not hidden). When a new wake isn't needed, a user-requested tooltip + will be shown nearly instantly. + + \value SH_Widget_Animate Determines if the widget should show animations or not, for example + a transition between checked and unchecked statuses in a checkbox. + This enum value has been introduced in Qt 5.2. + \sa styleHint() */ @@ -1986,6 +1996,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SP_MediaSeekBackward Icon indicating that media should seek backward. \value SP_MediaVolume Icon indicating a volume control. \value SP_MediaVolumeMuted Icon indicating a muted volume control. + \value SP_LineEditClearButton Icon for a standard clear button in a QLineEdit. This enum value was added in Qt 5.2. \value SP_CustomBase Base value for custom standard pixmaps; custom values must be greater than this value. diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h index beafad326e..fffd423c8a 100644 --- a/src/widgets/styles/qstyle.h +++ b/src/widgets/styles/qstyle.h @@ -698,6 +698,9 @@ public: SH_RequestSoftwareInputPanel, SH_ScrollBar_Transient, SH_Menu_SupportsSections, + SH_ToolTip_WakeUpDelay, + SH_ToolTip_FallAsleepDelay, + SH_Widget_Animate, // Add new style hint values here SH_CustomBase = 0xf0000000 @@ -777,6 +780,7 @@ public: SP_MediaSeekBackward, SP_MediaVolume, SP_MediaVolumeMuted, + SP_LineEditClearButton, // do not add any values below/greater than this SP_CustomBase = 0xf0000000 }; diff --git a/src/widgets/styles/qstyle.qrc b/src/widgets/styles/qstyle.qrc index 28ad484032..c063ec5036 100644 --- a/src/widgets/styles/qstyle.qrc +++ b/src/widgets/styles/qstyle.qrc @@ -1,5 +1,6 @@ <RCC> <qresource prefix="/qt-project.org/styles/commonstyle"> + <file>images/cleartext-16.png</file> <file>images/filelink-16.png</file> <file>images/filelink-32.png</file> <file>images/filelink-128.png</file> diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp index 5204b85a9a..347e5701c0 100644 --- a/src/widgets/util/qsystemtrayicon_x11.cpp +++ b/src/widgets/util/qsystemtrayicon_x11.cpp @@ -57,84 +57,19 @@ #include <qpa/qplatformnativeinterface.h> #include <qdebug.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xos.h> -#include <X11/Xatom.h> - #ifndef QT_NO_SYSTEMTRAYICON QT_BEGIN_NAMESPACE -enum { - SYSTEM_TRAY_REQUEST_DOCK = 0, - SYSTEM_TRAY_BEGIN_MESSAGE = 1, - SYSTEM_TRAY_CANCEL_MESSAGE =2 -}; - -// ### fixme (15.3.2012): The following issues need to be resolved: -// - Tracking of the actual tray window for DestroyNotify and re-creation -// of the icons on the new window should it change (see Qt 4.X). - -// Global context for the X11 system tray containing a display for the primary -// screen and a selection atom from which the tray window can be determined. -class QX11SystemTrayContext -{ -public: - QX11SystemTrayContext(); - ~QX11SystemTrayContext(); - - bool isValid() const { return m_systemTraySelection != 0; } - - inline Display *display() const { return m_display; } - inline int screenNumber() const { return m_screenNumber; } - Window locateSystemTray() const; - -private: - Display *m_display; - int m_screenNumber; - Atom m_systemTraySelection; -}; - -QX11SystemTrayContext::QX11SystemTrayContext() : m_display(0), m_screenNumber(0), m_systemTraySelection(0) -{ - QScreen *screen = QGuiApplication::primaryScreen(); - if (!screen) { - qWarning("%s: No screen.", Q_FUNC_INFO); - return; - } - void *displayV = QGuiApplication::platformNativeInterface()->nativeResourceForScreen(QByteArrayLiteral("display"), screen); - if (!displayV) { - qWarning("%s: Unable to obtain X11 display of primary screen.", Q_FUNC_INFO); - return; - } - - m_display = static_cast<Display *>(displayV); - - const QByteArray netSysTray = "_NET_SYSTEM_TRAY_S" + QByteArray::number(m_screenNumber); - m_systemTraySelection = XInternAtom(m_display, netSysTray.constData(), False); - if (!m_systemTraySelection) { - qWarning("%s: Unable to retrieve atom '%s'.", Q_FUNC_INFO, netSysTray.constData()); - return; - } -} - -Window QX11SystemTrayContext::locateSystemTray() const +static inline unsigned long locateSystemTray() { - if (isValid()) - return XGetSelectionOwner(m_display, m_systemTraySelection); - return 0; + return (unsigned long)QGuiApplication::platformNativeInterface()->nativeResourceForScreen(QByteArrayLiteral("traywindow"), QGuiApplication::primaryScreen()); } -QX11SystemTrayContext::~QX11SystemTrayContext() -{ -} - -Q_GLOBAL_STATIC(QX11SystemTrayContext, qX11SystemTrayContext) - // System tray widget. Could be replaced by a QWindow with // a backing store if it did not need tooltip handling. class QSystemTrayIconSys : public QWidget { + Q_OBJECT public: explicit QSystemTrayIconSys(QSystemTrayIcon *q); @@ -149,7 +84,12 @@ protected: virtual bool event(QEvent *); virtual void paintEvent(QPaintEvent *); +private slots: + void systemTrayWindowChanged(QScreen *screen); + private: + bool addToTray(); + QSystemTrayIcon *q; }; @@ -159,47 +99,59 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn) { setObjectName(QStringLiteral("QSystemTrayIconSys")); setToolTip(q->toolTip()); - QX11SystemTrayContext *context = qX11SystemTrayContext(); - Q_ASSERT(context->isValid()); setAttribute(Qt::WA_AlwaysShowToolTips, true); setAttribute(Qt::WA_TranslucentBackground, true); setAttribute(Qt::WA_QuitOnClose, false); const QSize size(22, 22); // Gnome, standard size setGeometry(QRect(QPoint(0, 0), size)); setMinimumSize(size); + addToTray(); +} + +bool QSystemTrayIconSys::addToTray() +{ + if (!locateSystemTray()) + return false; + createWinId(); setMouseTracking(true); - Display *display = context->display(); - - // Request to be a tray window according to GNOME, NET WM Specification - static Atom netwm_tray_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False); - long l[5] = { CurrentTime, SYSTEM_TRAY_REQUEST_DOCK, static_cast<long>(winId()), 0, 0 }; - XEvent ev; - memset(&ev, 0, sizeof(ev)); - ev.xclient.type = ClientMessage; - ev.xclient.window = context->locateSystemTray(); - ev.xclient.message_type = netwm_tray_atom; - ev.xclient.format = 32; - memcpy((char *)&ev.xclient.data, (const char *) l, sizeof(l)); - XSendEvent(display, ev.xclient.window, False, 0, &ev); + bool requestResult = false; + if (!QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(), + "requestSystemTrayWindowDock", Qt::DirectConnection, + Q_RETURN_ARG(bool, requestResult), + Q_ARG(const QWindow *, windowHandle())) + || !requestResult) { + qWarning("requestSystemTrayWindowDock failed."); + return false; + } show(); + return true; } -QRect QSystemTrayIconSys::globalGeometry() const +void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *) { - QX11SystemTrayContext *context = qX11SystemTrayContext(); - ::Window dummy; - int x, y, rootX, rootY; - unsigned int width, height, border, depth; - // Use X11 API since we are parented on the tray, about which the QWindow does not know. - XGetGeometry(context->display(), winId(), &dummy, &x, &y, &width, &height, &border, &depth); - XTranslateCoordinates(context->display(), winId(), - XRootWindow(context->display(), context->screenNumber()), - x, y, &rootX, &rootY, &dummy); - return QRect(QPoint(rootX, rootY), QSize(width, height)); + if (locateSystemTray()) { + addToTray(); + } else { + QBalloonTip::hideBalloon(); + hide(); // still no luck + destroy(); + } } +QRect QSystemTrayIconSys::globalGeometry() const +{ + QRect result; + if (!QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(), + "systemTrayWindowGlobalGeometry", Qt::DirectConnection, + Q_RETURN_ARG(QRect, result), + Q_ARG(const QWindow *, windowHandle())) + || !result.isValid()) { + qWarning("systemTrayWindowGlobalGeometry failed."); + } + return result; +} void QSystemTrayIconSys::mousePressEvent(QMouseEvent *ev) { @@ -268,8 +220,11 @@ QSystemTrayIconPrivate::~QSystemTrayIconPrivate() void QSystemTrayIconPrivate::install_sys() { Q_Q(QSystemTrayIcon); - if (!sys && qX11SystemTrayContext()->isValid()) + if (!sys && locateSystemTray()) { sys = new QSystemTrayIconSys(q); + QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), + sys, SLOT(systemTrayWindowChanged(QScreen*))); + } } QRect QSystemTrayIconPrivate::geometry_sys() const @@ -313,7 +268,7 @@ bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys() { const QString platform = QGuiApplication::platformName(); if (platform.compare(QStringLiteral("xcb"), Qt::CaseInsensitive) == 0) - return qX11SystemTrayContext()->locateSystemTray() != None; + return locateSystemTray(); return false; } @@ -334,4 +289,7 @@ void QSystemTrayIconPrivate::showMessage_sys(const QString &message, const QStri } QT_END_NAMESPACE + +#include "qsystemtrayicon_x11.moc" + #endif //QT_NO_SYSTEMTRAYICON diff --git a/src/widgets/util/util.pri b/src/widgets/util/util.pri index 598a3082c0..072c736f71 100644 --- a/src/widgets/util/util.pri +++ b/src/widgets/util/util.pri @@ -31,7 +31,6 @@ win32:!wince* { SOURCES += util/qsystemtrayicon_win.cpp } else:contains(QT_CONFIG, xcb) { SOURCES += util/qsystemtrayicon_x11.cpp - CONFIG += x11 } else { SOURCES += util/qsystemtrayicon_qpa.cpp } diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp index 900e95f4da..e7827055fb 100644 --- a/src/widgets/widgets/qabstractscrollarea.cpp +++ b/src/widgets/widgets/qabstractscrollarea.cpp @@ -167,6 +167,7 @@ QT_BEGIN_NAMESPACE QAbstractScrollAreaPrivate::QAbstractScrollAreaPrivate() :hbar(0), vbar(0), vbarpolicy(Qt::ScrollBarAsNeeded), hbarpolicy(Qt::ScrollBarAsNeeded), + shownOnce(false), sizeAdjustPolicy(QAbstractScrollArea::AdjustIgnored), viewport(0), cornerWidget(0), left(0), top(0), right(0), bottom(0), xoffset(0), yoffset(0), viewportFilter(0) #ifdef Q_WS_WIN @@ -527,6 +528,19 @@ void QAbstractScrollAreaPrivate::layoutChildren() } /*! + \enum QAbstractScrollArea::SizeAdjustPolicy + \since 5.2 + + This enum specifies how the size hint of the QAbstractScrollArea should + adjust when the size of the viewport changes. + + \value AdjustIgnored The scroll area will behave like before - and not do any adjust. + \value AdjustToContents The scroll area will always adjust to the viewport + \value AdjustToContentsOnFirstShow The scroll area will adjust to its viewport the first time it is shown. +*/ + + +/*! \internal Creates a new QAbstractScrollAreaPrivate, \a dd with the given \a parent. @@ -983,6 +997,13 @@ bool QAbstractScrollArea::event(QEvent *e) case QEvent::Resize: d->layoutChildren(); break; + case QEvent::Show: + if (!d->shownOnce && d->sizeAdjustPolicy == QAbstractScrollArea::AdjustToContentsOnFirstShow) { + d->sizeHint = QSize(); + updateGeometry(); + } + d->shownOnce = true; + return QFrame::event(e); case QEvent::Paint: { QStyleOption option; option.initFrom(this); @@ -1533,17 +1554,70 @@ QSize QAbstractScrollArea::minimumSizeHint() const } /*! + Returns the sizeHint property of the scroll area. The size is determined by using + viewportSizeHint() plus some extra space for scroll bars, if needed. \reimp */ QSize QAbstractScrollArea::sizeHint() const { - return QSize(256, 192); -#if 0 Q_D(const QAbstractScrollArea); - int h = qMax(10, fontMetrics().height()); - int f = 2 * d->frameWidth; - return QSize((6 * h) + f, (4 * h) + f); -#endif + if (d->sizeAdjustPolicy == QAbstractScrollArea::AdjustIgnored) + return QSize(256, 192); + + if (!d->sizeHint.isValid() || d->sizeAdjustPolicy == QAbstractScrollArea::AdjustToContents) { + const int f = 2 * d->frameWidth; + const QSize frame( f, f ); + const QSize scrollbars(d->vbarpolicy == Qt::ScrollBarAlwaysOn ? d->vbar->sizeHint().width() : 0, + d->hbarpolicy == Qt::ScrollBarAlwaysOn ? d->hbar->sizeHint().height() : 0); + d->sizeHint = frame + scrollbars + viewportSizeHint(); + } + return d->sizeHint; +} + +/*! + \since 5.2 + Returns the recommended size for the viewport. + The default implementation returns viewport()->sizeHint(). + Note that the size is just the viewport's size, without any scroll bars visible. + */ +QSize QAbstractScrollArea::viewportSizeHint() const +{ + Q_D(const QAbstractScrollArea); + if (d->viewport) { + const QSize sh = d->viewport->sizeHint(); + if (sh.isValid()) { + return sh; + } + } + const int h = qMax(10, fontMetrics().height()); + return QSize(6 * h, 4 * h); +} + +/*! + \since 5.2 + \property QAbstractScrollArea::sizeAdjustPolicy + This property holds the policy describing how the size of the scroll area changes when the + size of the viewport changes. + + The default policy is QAbstractScrollArea::AdjustIgnored. + Changing this property might actually resize the scrollarea. +*/ + +QAbstractScrollArea::SizeAdjustPolicy QAbstractScrollArea::sizeAdjustPolicy() const +{ + Q_D(const QAbstractScrollArea); + return d->sizeAdjustPolicy; +} + +void QAbstractScrollArea::setSizeAdjustPolicy(SizeAdjustPolicy policy) +{ + Q_D(QAbstractScrollArea); + if (d->sizeAdjustPolicy == policy) + return; + + d->sizeAdjustPolicy = policy; + d->sizeHint = QSize(); + updateGeometry(); } /*! @@ -1559,16 +1633,6 @@ void QAbstractScrollArea::setupViewport(QWidget *viewport) Q_UNUSED(viewport); } -/*! - \internal - - This method is reserved for future use. -*/ -QSize QAbstractScrollArea::viewportSizeHint() const -{ - return QSize(); -} - QT_END_NAMESPACE #include "moc_qabstractscrollarea.cpp" diff --git a/src/widgets/widgets/qabstractscrollarea.h b/src/widgets/widgets/qabstractscrollarea.h index ccf16b5e5c..fb9562db1b 100644 --- a/src/widgets/widgets/qabstractscrollarea.h +++ b/src/widgets/widgets/qabstractscrollarea.h @@ -56,13 +56,22 @@ class QAbstractScrollAreaPrivate; class Q_WIDGETS_EXPORT QAbstractScrollArea : public QFrame { Q_OBJECT + + Q_ENUMS(SizeAdjustPolicy) Q_PROPERTY(Qt::ScrollBarPolicy verticalScrollBarPolicy READ verticalScrollBarPolicy WRITE setVerticalScrollBarPolicy) Q_PROPERTY(Qt::ScrollBarPolicy horizontalScrollBarPolicy READ horizontalScrollBarPolicy WRITE setHorizontalScrollBarPolicy) + Q_PROPERTY(SizeAdjustPolicy sizeAdjustPolicy READ sizeAdjustPolicy WRITE setSizeAdjustPolicy) public: explicit QAbstractScrollArea(QWidget* parent=0); ~QAbstractScrollArea(); + enum SizeAdjustPolicy { + AdjustIgnored, + AdjustToContentsOnFirstShow, + AdjustToContents + }; + Qt::ScrollBarPolicy verticalScrollBarPolicy() const; void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy); QScrollBar *verticalScrollBar() const; @@ -89,6 +98,9 @@ public: virtual void setupViewport(QWidget *viewport); + SizeAdjustPolicy sizeAdjustPolicy() const; + void setSizeAdjustPolicy(SizeAdjustPolicy policy); + protected: QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget *parent = 0); void setViewportMargins(int left, int top, int right, int bottom); diff --git a/src/widgets/widgets/qabstractscrollarea_p.h b/src/widgets/widgets/qabstractscrollarea_p.h index 34d767fe29..3093c2f812 100644 --- a/src/widgets/widgets/qabstractscrollarea_p.h +++ b/src/widgets/widgets/qabstractscrollarea_p.h @@ -75,6 +75,10 @@ public: QScrollBar *hbar, *vbar; Qt::ScrollBarPolicy vbarpolicy, hbarpolicy; + bool shownOnce; + mutable QSize sizeHint; + QAbstractScrollArea::SizeAdjustPolicy sizeAdjustPolicy; + QWidget *viewport; QWidget *cornerWidget; QRect cornerPaintingRect; diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index afe8f1c3f4..bdd06da7fc 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -2086,6 +2086,20 @@ QString QComboBox::currentText() const } /*! + \property QComboBox::currentData + \brief the data for the current item + \since 5.2 + + By default, for an empty combo box or a combo box in which no current + item is set, this property contains an invalid QVariant. +*/ +QVariant QComboBox::currentData(int role) const +{ + Q_D(const QComboBox); + return d->currentIndex.data(role); +} + +/*! Returns the text for the given \a index in the combobox. */ QString QComboBox::itemText(int index) const diff --git a/src/widgets/widgets/qcombobox.h b/src/widgets/widgets/qcombobox.h index 2fafe79f7a..0002cd08cb 100644 --- a/src/widgets/widgets/qcombobox.h +++ b/src/widgets/widgets/qcombobox.h @@ -66,6 +66,7 @@ class Q_WIDGETS_EXPORT QComboBox : public QWidget Q_PROPERTY(int count READ count) Q_PROPERTY(QString currentText READ currentText WRITE setCurrentText NOTIFY currentTextChanged USER true) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + Q_PROPERTY(QVariant currentData READ currentData) Q_PROPERTY(int maxVisibleItems READ maxVisibleItems WRITE setMaxVisibleItems) Q_PROPERTY(int maxCount READ maxCount WRITE setMaxCount) Q_PROPERTY(InsertPolicy insertPolicy READ insertPolicy WRITE setInsertPolicy) @@ -167,8 +168,8 @@ public: void setModelColumn(int visibleColumn); int currentIndex() const; - QString currentText() const; + QVariant currentData(int role = Qt::UserRole) const; QString itemText(int index) const; QIcon itemIcon(int index) const; diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp index bc5d84e259..226969cdd1 100644 --- a/src/widgets/widgets/qdialogbuttonbox.cpp +++ b/src/widgets/widgets/qdialogbuttonbox.cpp @@ -669,6 +669,21 @@ QDialogButtonBox::QDialogButtonBox(Qt::Orientation orientation, QWidget *parent) } /*! + \since 5.2 + + Constructs a horizontal button box with the given \a parent, containing + the standard buttons specified by \a buttons. + + \sa orientation, addButton() +*/ +QDialogButtonBox::QDialogButtonBox(StandardButtons buttons, QWidget *parent) + : QWidget(*new QDialogButtonBoxPrivate(Qt::Horizontal), parent, 0) +{ + d_func()->initLayout(); + d_func()->createStandardButtons(buttons); +} + +/*! Constructs a button box with the given \a orientation and \a parent, containing the standard buttons specified by \a buttons. diff --git a/src/widgets/widgets/qdialogbuttonbox.h b/src/widgets/widgets/qdialogbuttonbox.h index 6715c590e2..d8e1a997d4 100644 --- a/src/widgets/widgets/qdialogbuttonbox.h +++ b/src/widgets/widgets/qdialogbuttonbox.h @@ -115,7 +115,8 @@ public: QDialogButtonBox(QWidget *parent = 0); QDialogButtonBox(Qt::Orientation orientation, QWidget *parent = 0); - QDialogButtonBox(StandardButtons buttons, Qt::Orientation orientation = Qt::Horizontal, + explicit QDialogButtonBox(StandardButtons buttons, QWidget *parent = 0); + QDialogButtonBox(StandardButtons buttons, Qt::Orientation orientation, QWidget *parent = 0); ~QDialogButtonBox(); diff --git a/src/widgets/widgets/qfontcombobox.cpp b/src/widgets/widgets/qfontcombobox.cpp index 5f929caf03..0b0efa2bdf 100644 --- a/src/widgets/widgets/qfontcombobox.cpp +++ b/src/widgets/widgets/qfontcombobox.cpp @@ -54,6 +54,88 @@ QT_BEGIN_NAMESPACE +static QFontDatabase::WritingSystem writingSystemFromScript(QLocale::Script script) +{ + switch (script) { + case QLocale::ArabicScript: + return QFontDatabase::Arabic; + case QLocale::CyrillicScript: + return QFontDatabase::Cyrillic; + case QLocale::GurmukhiScript: + return QFontDatabase::Gurmukhi; + case QLocale::SimplifiedHanScript: + return QFontDatabase::SimplifiedChinese; + case QLocale::TraditionalHanScript: + return QFontDatabase::TraditionalChinese; + case QLocale::LatinScript: + return QFontDatabase::Latin; + case QLocale::ArmenianScript: + return QFontDatabase::Armenian; + case QLocale::BengaliScript: + return QFontDatabase::Bengali; + case QLocale::DevanagariScript: + return QFontDatabase::Devanagari; + case QLocale::GeorgianScript: + return QFontDatabase::Georgian; + case QLocale::GreekScript: + return QFontDatabase::Greek; + case QLocale::GujaratiScript: + return QFontDatabase::Gujarati; + case QLocale::HebrewScript: + return QFontDatabase::Hebrew; + case QLocale::JapaneseScript: + return QFontDatabase::Japanese; + case QLocale::KhmerScript: + return QFontDatabase::Khmer; + case QLocale::KannadaScript: + return QFontDatabase::Kannada; + case QLocale::KoreanScript: + return QFontDatabase::Korean; + case QLocale::LaoScript: + return QFontDatabase::Lao; + case QLocale::MalayalamScript: + return QFontDatabase::Malayalam; + case QLocale::MyanmarScript: + return QFontDatabase::Myanmar; + case QLocale::TamilScript: + return QFontDatabase::Tamil; + case QLocale::TeluguScript: + return QFontDatabase::Telugu; + case QLocale::ThaanaScript: + return QFontDatabase::Thaana; + case QLocale::ThaiScript: + return QFontDatabase::Thai; + case QLocale::TibetanScript: + return QFontDatabase::Tibetan; + case QLocale::SinhalaScript: + return QFontDatabase::Sinhala; + case QLocale::SyriacScript: + return QFontDatabase::Syriac; + case QLocale::OriyaScript: + return QFontDatabase::Oriya; + case QLocale::OghamScript: + return QFontDatabase::Ogham; + case QLocale::RunicScript: + return QFontDatabase::Runic; + case QLocale::NkoScript: + return QFontDatabase::Nko; + default: + return QFontDatabase::Any; + } +} + +static QFontDatabase::WritingSystem writingSystemFromLocale() +{ + QStringList uiLanguages = QLocale::system().uiLanguages(); + QLocale::Script script; + if (!uiLanguages.isEmpty()) + script = QLocale(uiLanguages.at(0)).script(); + else + script = QLocale::system().script(); + + return writingSystemFromScript(script); +} + static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool *hasLatin) { QList<QFontDatabase::WritingSystem> writingSystems = QFontDatabase().writingSystems(font.family()); @@ -66,7 +148,22 @@ static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool if (writingSystems.isEmpty()) return QFontDatabase::Any; - QFontDatabase::WritingSystem system = writingSystems.last(); + QFontDatabase::WritingSystem system = writingSystemFromLocale(); + + if (writingSystems.contains(system)) + return system; + + if (system == QFontDatabase::TraditionalChinese + && writingSystems.contains(QFontDatabase::SimplifiedChinese)) { + return QFontDatabase::SimplifiedChinese; + } + + if (system == QFontDatabase::SimplifiedChinese + && writingSystems.contains(QFontDatabase::TraditionalChinese)) { + return QFontDatabase::TraditionalChinese; + } + + system = writingSystems.last(); if (!*hasLatin) { // we need to show something diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index 70083d7267..a8b6b1a10c 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -351,7 +351,7 @@ void QLineEdit::setPlaceholderText(const QString& placeholderText) Q_D(QLineEdit); if (d->placeholderText != placeholderText) { d->placeholderText = placeholderText; - if (!hasFocus()) + if (d->control->text().isEmpty()) update(); } } @@ -420,6 +420,96 @@ bool QLineEdit::hasFrame() const return d->frame; } +/*! + \enum QLineEdit::ActionPosition + + This enum type describes how a line edit should display the action widgets to be + added. + + \value LeadingPosition The widget is displayed to the left of the text + when using layout direction \c Qt::LeftToRight or to + the right when using \c Qt::RightToLeft, respectively. + + \value TrailingPosition The widget is displayed to the right of the text + when using layout direction \c Qt::LeftToRight or to + the left when using \c Qt::RightToLeft, respectively. + + \sa addAction(), removeAction(), QWidget::layoutDirection + + \since 5.2 +*/ + +/*! + \fn void QLineEdit::addAction(QAction *action) + \overload + \internal +*/ + +/*! + \overload + + Adds the \a action to the list of actions at the \a position. + + \since 5.2 +*/ + +void QLineEdit::addAction(QAction *action, ActionPosition position) +{ + Q_D(QLineEdit); + QWidget::addAction(action); + d->addAction(action, 0, position); +} + +/*! + \overload + + Creates a new action with the given \a icon at the \a position. + + \since 5.2 +*/ + +QAction *QLineEdit::addAction(const QIcon &icon, ActionPosition position) +{ + QAction *result = new QAction(icon, QString(), this); + addAction(result, position); + return result; +} + +/*! + \property QLineEdit::clearButtonEnabled + \brief Whether the line edit displays a clear button when it is not empty. + + If enabled, the line edit displays a trailing \e clear button when it contains + some text, otherwise the line edit does not show a clear button (the + default). + + \sa addAction(), removeAction() + \since 5.2 +*/ + +static const char clearButtonActionNameC[] = "_q_qlineeditclearaction"; + +void QLineEdit::setClearButtonEnabled(bool enable) +{ + Q_D(QLineEdit); + if (enable == isClearButtonEnabled()) + return; + if (enable) { + QAction *clearAction = new QAction(d->clearButtonIcon(), QString(), this); + clearAction->setObjectName(QLatin1String(clearButtonActionNameC)); + d->addAction(clearAction, 0, QLineEdit::TrailingPosition, QLineEditPrivate::SideWidgetClearButton | QLineEditPrivate::SideWidgetFadeInWithText); + } else { + QAction *clearAction = findChild<QAction *>(QLatin1String(clearButtonActionNameC)); + Q_ASSERT(clearAction); + removeAction(clearAction); + delete clearAction; + } +} + +bool QLineEdit::isClearButtonEnabled() const +{ + return findChild<QAction *>(QLatin1String(clearButtonActionNameC)); +} void QLineEdit::setFrame(bool enable) { @@ -606,7 +696,7 @@ QSize QLineEdit::sizeHint() const + d->topTextMargin + d->bottomTextMargin + d->topmargin + d->bottommargin; int w = fm.width(QLatin1Char('x')) * 17 + 2*d->horizontalMargin - + d->leftTextMargin + d->rightTextMargin + + d->effectiveLeftTextMargin() + d->effectiveRightTextMargin() + d->leftmargin + d->rightmargin; // "some" QStyleOptionFrameV2 opt; initStyleOption(&opt); @@ -967,7 +1057,6 @@ void QLineEdit::setDragEnabled(bool b) d->dragEnabled = b; } - /*! \property QLineEdit::cursorMoveStyle \brief the movement style of cursor in this line edit @@ -1350,8 +1439,11 @@ bool QLineEdit::event(QEvent * e) || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) d->setCursorVisible(true); } + } else if (e->type() == QEvent::ActionRemoved) { + d->removeAction(static_cast<QActionEvent *>(e)); + } else if (e->type() == QEvent::Resize) { + d->positionSideWidgets(); } - #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled()) { if (e->type() == QEvent::EnterEditFocus) { @@ -1777,9 +1869,9 @@ void QLineEdit::paintEvent(QPaintEvent *) initStyleOption(&panel); style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this); r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this); - r.setX(r.x() + d->leftTextMargin); + r.setX(r.x() + d->effectiveLeftTextMargin()); r.setY(r.y() + d->topTextMargin); - r.setRight(r.right() - d->rightTextMargin); + r.setRight(r.right() - d->effectiveRightTextMargin()); r.setBottom(r.bottom() - d->bottomTextMargin); p.setClipRect(r); @@ -1983,6 +2075,13 @@ void QLineEdit::contextMenuEvent(QContextMenuEvent *event) } } +static inline void setActionIcon(QAction *action, const QString &name) +{ + const QIcon icon = QIcon::fromTheme(name); + if (!icon.isNull()) + action->setIcon(icon); +} + /*! This function creates the standard context menu which is shown when the user clicks on the line edit with the right mouse button. It is called from the default contextMenuEvent() handler. @@ -1999,10 +2098,12 @@ QMenu *QLineEdit::createStandardContextMenu() if (!isReadOnly()) { action = popup->addAction(QLineEdit::tr("&Undo") + ACCEL_KEY(QKeySequence::Undo)); action->setEnabled(d->control->isUndoAvailable()); + setActionIcon(action, QStringLiteral("edit-undo")); connect(action, SIGNAL(triggered()), SLOT(undo())); action = popup->addAction(QLineEdit::tr("&Redo") + ACCEL_KEY(QKeySequence::Redo)); action->setEnabled(d->control->isRedoAvailable()); + setActionIcon(action, QStringLiteral("edit-redo")); connect(action, SIGNAL(triggered()), SLOT(redo())); popup->addSeparator(); @@ -2013,17 +2114,20 @@ 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); + setActionIcon(action, QStringLiteral("edit-cut")); connect(action, SIGNAL(triggered()), SLOT(cut())); } action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy)); action->setEnabled(d->control->hasSelectedText() && d->control->echoMode() == QLineEdit::Normal); + setActionIcon(action, QStringLiteral("edit-copy")); connect(action, SIGNAL(triggered()), SLOT(copy())); if (!isReadOnly()) { action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste)); action->setEnabled(!d->control->isReadOnly() && !QApplication::clipboard()->text().isEmpty()); + setActionIcon(action, QStringLiteral("edit-paste")); connect(action, SIGNAL(triggered()), SLOT(paste())); } #endif @@ -2031,6 +2135,7 @@ QMenu *QLineEdit::createStandardContextMenu() if (!isReadOnly()) { action = popup->addAction(QLineEdit::tr("Delete")); action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText()); + setActionIcon(action, QStringLiteral("edit-delete")); connect(action, SIGNAL(triggered()), d->control, SLOT(_q_deleteSelected())); } @@ -2070,8 +2175,15 @@ void QLineEdit::changeEvent(QEvent *ev) initStyleOption(&opt); d->control->setPasswordCharacter(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, this)); } + d->m_iconSize = QSize(); update(); break; + case QEvent::LayoutDirectionChange: + foreach (const QLineEditPrivate::SideWidgetEntry &e, d->trailingSideWidgets) // Refresh icon to show arrow in right direction. + if (e.flags & QLineEditPrivate::SideWidgetClearButton) + static_cast<QLineEditIconButton *>(e.widget)->setIcon(d->clearButtonIcon()); + d->positionSideWidgets(); + break; default: break; } diff --git a/src/widgets/widgets/qlineedit.h b/src/widgets/widgets/qlineedit.h index e2b944314b..3d52863db2 100644 --- a/src/widgets/widgets/qlineedit.h +++ b/src/widgets/widgets/qlineedit.h @@ -59,12 +59,14 @@ class QCompleter; class QStyleOptionFrame; class QAbstractSpinBox; class QDateTimeEdit; +class QIcon; +class QToolButton; class Q_WIDGETS_EXPORT QLineEdit : public QWidget { Q_OBJECT - Q_ENUMS(EchoMode) + Q_ENUMS(ActionPosition EchoMode) Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true) Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength) @@ -83,8 +85,13 @@ class Q_WIDGETS_EXPORT QLineEdit : public QWidget Q_PROPERTY(bool acceptableInput READ hasAcceptableInput) Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText) Q_PROPERTY(Qt::CursorMoveStyle cursorMoveStyle READ cursorMoveStyle WRITE setCursorMoveStyle) - + Q_PROPERTY(bool clearButtonEnabled READ isClearButtonEnabled WRITE setClearButtonEnabled) public: + enum ActionPosition { + LeadingPosition, + TrailingPosition + }; + explicit QLineEdit(QWidget* parent=0); explicit QLineEdit(const QString &, QWidget* parent=0); ~QLineEdit(); @@ -102,6 +109,9 @@ public: void setFrame(bool); bool hasFrame() const; + void setClearButtonEnabled(bool enable); + bool isClearButtonEnabled() const; + enum EchoMode { Normal, NoEcho, Password, PasswordEchoOnEdit }; EchoMode echoMode() const; void setEchoMode(EchoMode); @@ -164,6 +174,16 @@ public: void getTextMargins(int *left, int *top, int *right, int *bottom) const; QMargins textMargins() const; +#ifdef Q_NO_USING_KEYWORD + inline void addAction(QAction *action) + { QWidget::addAction(action); } +#else + using QWidget::addAction; +#endif + + void addAction(QAction *action, ActionPosition position); + QAction *addAction(const QIcon &icon, ActionPosition position); + public Q_SLOTS: void setText(const QString &); void clear(); @@ -240,6 +260,7 @@ private: #endif Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged()) Q_PRIVATE_SLOT(d_func(), void _q_updateNeeded(const QRect &)) + Q_PRIVATE_SLOT(d_func(), void _q_textChanged(const QString &)) }; #endif // QT_NO_LINEEDIT diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index 1999216e65..99d6d0b8d9 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -44,8 +44,10 @@ #ifndef QT_NO_LINEEDIT +#include "qvariant.h" #include "qabstractitemview.h" #include "qdrag.h" +#include "qwidgetaction.h" #include "qclipboard.h" #ifndef QT_NO_ACCESSIBILITY #include "qaccessible.h" @@ -53,6 +55,7 @@ #ifndef QT_NO_IM #include "qinputmethod.h" #include "qlist.h" +#include <qpropertyanimation.h> #endif QT_BEGIN_NAMESPACE @@ -219,9 +222,9 @@ QRect QLineEditPrivate::adjustedContentsRect() const QStyleOptionFrameV2 opt; q->initStyleOption(&opt); QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q); - r.setX(r.x() + leftTextMargin); + r.setX(r.x() + effectiveLeftTextMargin()); r.setY(r.y() + topTextMargin); - r.setRight(r.right() - rightTextMargin); + r.setRight(r.right() - effectiveRightTextMargin()); r.setBottom(r.bottom() - bottomTextMargin); return r; } @@ -297,6 +300,170 @@ void QLineEditPrivate::drag() #endif // QT_NO_DRAGANDDROP +QLineEditIconButton::QLineEditIconButton(QWidget *parent) + : QToolButton(parent) + , m_opacity(0) +{ +#ifndef QT_NO_CURSOR + setCursor(Qt::ArrowCursor); +#endif + setFocusPolicy(Qt::NoFocus); +} + +void QLineEditIconButton::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + // Note isDown should really use the active state but in most styles + // this has no proper feedback + QIcon::Mode state = QIcon::Disabled; + if (isEnabled()) + state = isDown() ? QIcon::Selected : QIcon::Normal; + const QPixmap iconPixmap = icon().pixmap(QSize(IconButtonSize, IconButtonSize), + state, QIcon::Off); + QRect pixmapRect = QRect(0, 0, iconPixmap.width(), iconPixmap.height()); + pixmapRect.moveCenter(rect().center()); + painter.setOpacity(m_opacity); + painter.drawPixmap(pixmapRect, iconPixmap); +} + +void QLineEditIconButton::setOpacity(qreal value) +{ + if (!qFuzzyCompare(m_opacity, value)) { + m_opacity = value; + update(); + } +} + +void QLineEditIconButton::startOpacityAnimation(qreal endValue) +{ + QPropertyAnimation *animation = new QPropertyAnimation(this, QByteArrayLiteral("opacity")); + animation->setDuration(160); + animation->setEndValue(endValue); + animation->start(QAbstractAnimation::DeleteWhenStopped); +} + +void QLineEditPrivate::_q_textChanged(const QString &text) +{ + if (hasSideWidgets()) { + const int newTextSize = text.size(); + if (!newTextSize || !lastTextSize) { + lastTextSize = newTextSize; + const bool fadeIn = newTextSize > 0; + foreach (const SideWidgetEntry &e, leadingSideWidgets) { + if (e.flags & SideWidgetFadeInWithText) + static_cast<QLineEditIconButton *>(e.widget)->animateShow(fadeIn); + } + foreach (const SideWidgetEntry &e, trailingSideWidgets) { + if (e.flags & SideWidgetFadeInWithText) + static_cast<QLineEditIconButton *>(e.widget)->animateShow(fadeIn); + } + } + } +} + +QSize QLineEditPrivate::iconSize() const +{ + if (!m_iconSize.isValid()) // This might require style-specific handling (pixel metric). + m_iconSize = QSize(QLineEditIconButton::IconButtonSize + 6, QLineEditIconButton::IconButtonSize + 2); + return m_iconSize; +} + +QIcon QLineEditPrivate::clearButtonIcon() const +{ + Q_Q(const QLineEdit); + QStyleOptionFrameV2 styleOption; + q->initStyleOption(&styleOption); + return QIcon(q->style()->standardPixmap(QStyle::SP_LineEditClearButton, &styleOption, q)); +} + +void QLineEditPrivate::positionSideWidgets() +{ + Q_Q(QLineEdit); + if (hasSideWidgets()) { + const QRect contentRect = q->rect(); + const QSize iconSize = QLineEditPrivate::iconSize(); + const int delta = QLineEditIconButton::IconMargin + iconSize.width(); + QRect widgetGeometry(QPoint(QLineEditIconButton::IconMargin, (contentRect.height() - iconSize.height()) / 2), iconSize); + foreach (const SideWidgetEntry &e, leftSideWidgetList()) { + e.widget->setGeometry(widgetGeometry); + widgetGeometry.moveLeft(widgetGeometry.left() + delta); + } + widgetGeometry.moveLeft(contentRect.width() - iconSize.width() - QLineEditIconButton::IconMargin); + foreach (const SideWidgetEntry &e, rightSideWidgetList()) { + e.widget->setGeometry(widgetGeometry); + widgetGeometry.moveLeft(widgetGeometry.left() - delta); + } + } +} + +QLineEditPrivate::PositionIndexPair QLineEditPrivate::findSideWidget(const QAction *a) const +{ + for (int i = 0; i < leadingSideWidgets.size(); ++i) { + if (a == leadingSideWidgets.at(i).action) + return PositionIndexPair(QLineEdit::LeadingPosition, i); + } + for (int i = 0; i < trailingSideWidgets.size(); ++i) { + if (a == trailingSideWidgets.at(i).action) + return PositionIndexPair(QLineEdit::TrailingPosition, i); + } + return PositionIndexPair(QLineEdit::LeadingPosition, -1); +} + +QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineEdit::ActionPosition position, int flags) +{ + Q_Q(QLineEdit); + if (!newAction) + return 0; + QWidget *w = 0; + // Store flags about QWidgetAction here since removeAction() may be called from ~QAction, + // in which a qobject_cast<> no longer works. + if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(newAction)) { + if ((w = widgetAction->requestWidget(q))) + flags |= SideWidgetCreatedByWidgetAction; + } + if (!w) { + QLineEditIconButton *toolButton = new QLineEditIconButton(q); + toolButton->setIcon(newAction->icon()); + toolButton->setOpacity(lastTextSize > 0 || !(flags & SideWidgetFadeInWithText) ? 1 : 0); + if (flags & SideWidgetClearButton) + QObject::connect(toolButton, SIGNAL(clicked()), q, SLOT(clear())); + toolButton->setDefaultAction(newAction); + w = toolButton; + } + if (!hasSideWidgets()) { // initial setup. + QObject::connect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString))); + lastTextSize = q->text().size(); + } + // If there is a 'before' action, it takes preference + PositionIndexPair positionIndex = before ? findSideWidget(before) : PositionIndexPair(position, -1); + SideWidgetEntryList &list = positionIndex.first == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets; + if (positionIndex.second < 0) + positionIndex.second = list.size(); + list.insert(positionIndex.second, SideWidgetEntry(w, newAction, flags)); + positionSideWidgets(); + w->show(); + return w; +} + +void QLineEditPrivate::removeAction(const QActionEvent *e) +{ + Q_Q(QLineEdit); + QAction *action = e->action(); + const PositionIndexPair positionIndex = findSideWidget(action); + if (positionIndex.second == -1) + return; + SideWidgetEntryList &list = positionIndex.first == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets; + SideWidgetEntry entry = list.takeAt(positionIndex.second); + if (entry.flags & SideWidgetCreatedByWidgetAction) + static_cast<QWidgetAction *>(entry.action)->releaseWidget(entry.widget); + else + delete entry.widget; + positionSideWidgets(); + if (!hasSideWidgets()) // Last widget, remove connection + QObject::disconnect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString))); + q->update(); +} + QT_END_NAMESPACE #endif diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h index 4eb35b7dc6..8fe45972ff 100644 --- a/src/widgets/widgets/qlineedit_p.h +++ b/src/widgets/widgets/qlineedit_p.h @@ -58,7 +58,9 @@ #ifndef QT_NO_LINEEDIT #include "private/qwidget_p.h" #include "QtWidgets/qlineedit.h" +#include "QtWidgets/qtoolbutton.h" #include "QtGui/qtextlayout.h" +#include "QtGui/qicon.h" #include "QtWidgets/qstyleoption.h" #include "QtCore/qbasictimer.h" #include "QtWidgets/qcompleter.h" @@ -69,16 +71,55 @@ QT_BEGIN_NAMESPACE +// QLineEditIconButton: This is a simple helper class that represents clickable icons that fade in with text + +class QLineEditIconButton : public QToolButton +{ + Q_OBJECT + Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) +public: + enum { IconMargin = 4, IconButtonSize = 16 }; + + explicit QLineEditIconButton(QWidget *parent = 0); + + qreal opacity() const { return m_opacity; } + void setOpacity(qreal value); + void animateShow(bool visible) { startOpacityAnimation(visible ? 1.0 : 0.0); } + +protected: + void paintEvent(QPaintEvent *event); + +private: + void startOpacityAnimation(qreal endValue); + + qreal m_opacity; +}; + class Q_AUTOTEST_EXPORT QLineEditPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QLineEdit) public: + enum SideWidgetFlag { + SideWidgetFadeInWithText = 0x1, + SideWidgetCreatedByWidgetAction = 0x2, + SideWidgetClearButton = 0x4 + }; + + struct SideWidgetEntry { + SideWidgetEntry(QWidget *w = 0, QAction *a = 0, int _flags = 0) : widget(w), action(a), flags(_flags) {} + + QWidget *widget; + QAction *action; + int flags; + }; + typedef QList<SideWidgetEntry> SideWidgetEntryList; QLineEditPrivate() : control(0), frame(1), contextMenuEnabled(1), cursorVisible(0), dragEnabled(0), clickCausedFocus(0), hscroll(0), vscroll(0), alignment(Qt::AlignLeading | Qt::AlignVCenter), - leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0) + leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0), + lastTextSize(0) { } @@ -145,15 +186,50 @@ public: QBasicTimer dndTimer; void drag(); #endif + void _q_textChanged(const QString &); - int leftTextMargin; + int leftTextMargin; // use effectiveLeftTextMargin() in case of icon. int topTextMargin; - int rightTextMargin; + int rightTextMargin; // use effectiveRightTextMargin() in case of icon. int bottomTextMargin; QString placeholderText; + + QWidget *addAction(QAction *newAction, QAction *before, QLineEdit::ActionPosition, int flags = 0); + void removeAction(const QActionEvent *e); + QSize iconSize() const; + QIcon clearButtonIcon() const; + void positionSideWidgets(); + inline bool hasSideWidgets() const { return !leadingSideWidgets.isEmpty() || !trailingSideWidgets.isEmpty(); } + inline const SideWidgetEntryList &leftSideWidgetList() const + { return q_func()->layoutDirection() == Qt::LeftToRight ? leadingSideWidgets : trailingSideWidgets; } + inline const SideWidgetEntryList &rightSideWidgetList() const + { return q_func()->layoutDirection() == Qt::LeftToRight ? trailingSideWidgets : leadingSideWidgets; } + + int effectiveLeftTextMargin() const; + int effectiveRightTextMargin() const; + +private: + typedef QPair<QLineEdit::ActionPosition, int> PositionIndexPair; + + PositionIndexPair findSideWidget(const QAction *a) const; + + SideWidgetEntryList leadingSideWidgets; + SideWidgetEntryList trailingSideWidgets; + int lastTextSize; + mutable QSize m_iconSize; }; +inline int QLineEditPrivate::effectiveLeftTextMargin() const +{ + return leftTextMargin + leftSideWidgetList().size() * (QLineEditIconButton::IconMargin + iconSize().width()); +} + +inline int QLineEditPrivate::effectiveRightTextMargin() const +{ + return rightTextMargin + rightSideWidgetList().size() * (QLineEditIconButton::IconMargin + iconSize().width()); +} + #endif // QT_NO_LINEEDIT QT_END_NAMESPACE diff --git a/src/widgets/widgets/qscrollarea.cpp b/src/widgets/widgets/qscrollarea.cpp index 93c335c56b..2a6d4620d7 100644 --- a/src/widgets/widgets/qscrollarea.cpp +++ b/src/widgets/widgets/qscrollarea.cpp @@ -407,6 +407,18 @@ QSize QScrollArea::sizeHint() const return sz.boundedTo(QSize(36 * h, 24 * h)); } +/*! + \reimp + */ +QSize QScrollArea::viewportSizeHint() const +{ + Q_D(const QScrollArea); + if (d->widget) { + return d->resizable ? d->widget->sizeHint() : d->widget->size(); + } + const int h = fontMetrics().height(); + return QSize(6 * h, 4 * h); +} /*! diff --git a/src/widgets/widgets/qscrollarea.h b/src/widgets/widgets/qscrollarea.h index 576c9bc9e0..70af5fbbd7 100644 --- a/src/widgets/widgets/qscrollarea.h +++ b/src/widgets/widgets/qscrollarea.h @@ -69,6 +69,8 @@ public: void setWidgetResizable(bool resizable); QSize sizeHint() const; + QSize viewportSizeHint() const; + bool focusNextPrevChild(bool next); Qt::Alignment alignment() const; diff --git a/src/widgets/widgets/qscrollbar.cpp b/src/widgets/widgets/qscrollbar.cpp index e1e2723a2d..4ed91204cd 100644 --- a/src/widgets/widgets/qscrollbar.cpp +++ b/src/widgets/widgets/qscrollbar.cpp @@ -510,6 +510,11 @@ void QScrollBar::wheelEvent(QWheelEvent *event) Q_D(QScrollBar); if (d->scrollByDelta(event->orientation(), event->modifiers(), delta)) event->accept(); + + if (event->phase() == QWheelEvent::Started) + d->setTransient(false); + else if (event->phase() == QWheelEvent::Ended) + d->setTransient(true); } #endif diff --git a/src/widgets/widgets/qspinbox.cpp b/src/widgets/widgets/qspinbox.cpp index 0ce5473ad8..bf4e130d4e 100644 --- a/src/widgets/widgets/qspinbox.cpp +++ b/src/widgets/widgets/qspinbox.cpp @@ -78,6 +78,8 @@ public: q->setInputMethodHints(Qt::ImhDigitsOnly); setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem); } + + int displayIntegerBase; }; class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate @@ -425,6 +427,38 @@ void QSpinBox::setRange(int minimum, int maximum) } /*! + \property QSpinBox::displayIntegerBase + + \brief the base used to display the value of the spin box + + The default displayIntegerBase value is 10. + + \sa textFromValue(), valueFromText() + \since 5.2 +*/ + +int QSpinBox::displayIntegerBase() const +{ + Q_D(const QSpinBox); + return d->displayIntegerBase; +} + +void QSpinBox::setDisplayIntegerBase(int base) +{ + Q_D(QSpinBox); + // Falls back to base 10 on invalid bases (like QString) + if (base < 2 || base > 36) { + qWarning("QSpinBox::setDisplayIntegerBase: Invalid base (%d)", base); + base = 10; + } + + if (base != d->displayIntegerBase) { + d->displayIntegerBase = base; + d->updateEdit(); + } +} + +/*! This virtual function is used by the spin box whenever it needs to display the given \a value. The default implementation returns a string containing \a value printed in the standard way using @@ -444,9 +478,18 @@ void QSpinBox::setRange(int minimum, int maximum) QString QSpinBox::textFromValue(int value) const { - QString str = locale().toString(value); - if (qAbs(value) >= 1000 || value == INT_MIN) { - str.remove(locale().groupSeparator()); + Q_D(const QSpinBox); + QString str; + + if (d->displayIntegerBase != 10) { + str = QString::number(qAbs(value), d->displayIntegerBase); + if (value < 0) + str.prepend('-'); + } else { + str = locale().toString(value); + if (qAbs(value) >= 1000 || value == INT_MIN) { + str.remove(locale().groupSeparator()); + } } return str; @@ -926,6 +969,7 @@ QSpinBoxPrivate::QSpinBoxPrivate() minimum = QVariant((int)0); maximum = QVariant((int)99); value = minimum; + displayIntegerBase = 10; singleStep = QVariant((int)1); type = QVariant::Int; } @@ -1003,11 +1047,15 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100 } else { bool ok = false; - num = locale.toInt(copy, &ok); - if (!ok && copy.contains(locale.groupSeparator()) && (max >= 1000 || min <= -1000)) { - QString copy2 = copy; - copy2.remove(locale.groupSeparator()); - num = locale.toInt(copy2, &ok); + if (displayIntegerBase != 10) { + num = copy.toInt(&ok, displayIntegerBase); + } else { + num = locale.toInt(copy, &ok); + if (!ok && copy.contains(locale.groupSeparator()) && (max >= 1000 || min <= -1000)) { + QString copy2 = copy; + copy2.remove(locale.groupSeparator()); + num = locale.toInt(copy2, &ok); + } } QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num; if (!ok) { diff --git a/src/widgets/widgets/qspinbox.h b/src/widgets/widgets/qspinbox.h index 4963f87a1a..98e809e141 100644 --- a/src/widgets/widgets/qspinbox.h +++ b/src/widgets/widgets/qspinbox.h @@ -61,6 +61,7 @@ class Q_WIDGETS_EXPORT QSpinBox : public QAbstractSpinBox Q_PROPERTY(int maximum READ maximum WRITE setMaximum) Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep) Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged USER true) + Q_PROPERTY(int displayIntegerBase READ displayIntegerBase WRITE setDisplayIntegerBase) public: explicit QSpinBox(QWidget *parent = 0); @@ -87,6 +88,8 @@ public: void setRange(int min, int max); + int displayIntegerBase() const; + void setDisplayIntegerBase(int base); protected: bool event(QEvent *event); diff --git a/src/widgets/widgets/qsplashscreen.cpp b/src/widgets/widgets/qsplashscreen.cpp index 746c02e4e2..b2a0d3f8b8 100644 --- a/src/widgets/widgets/qsplashscreen.cpp +++ b/src/widgets/widgets/qsplashscreen.cpp @@ -200,7 +200,7 @@ void QSplashScreen::repaint() is kept up to date with what your application is doing (e.g., loading files). - \sa Qt::Alignment, clearMessage() + \sa Qt::Alignment, clearMessage(), message() */ void QSplashScreen::showMessage(const QString &message, int alignment, const QColor &color) @@ -214,6 +214,20 @@ void QSplashScreen::showMessage(const QString &message, int alignment, } /*! + \since 5.2 + + Returns the message that is currently displayed on the splash screen. + + \sa showMessage(), clearMessage() +*/ + +QString QSplashScreen::message() const +{ + Q_D(const QSplashScreen); + return d->currStatus; +} + +/*! Removes the message being displayed on the splash screen \sa showMessage() diff --git a/src/widgets/widgets/qsplashscreen.h b/src/widgets/widgets/qsplashscreen.h index a1af8e45ef..e675c2e7af 100644 --- a/src/widgets/widgets/qsplashscreen.h +++ b/src/widgets/widgets/qsplashscreen.h @@ -63,6 +63,7 @@ public: const QPixmap pixmap() const; void finish(QWidget *w); void repaint(); + QString message() const; public Q_SLOTS: void showMessage(const QString &message, int alignment = Qt::AlignLeft, diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp index b975035dcf..aa7677869c 100644 --- a/src/widgets/widgets/qtabbar.cpp +++ b/src/widgets/widgets/qtabbar.cpp @@ -329,6 +329,26 @@ void QTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const \sa moveTab() */ +/*! + \fn void QTabBar::tabBarClicked(int index) + + This signal is emitted when user clicks on a tab at an \a index. + + \a index is the index of a clicked tab, or -1 if no tab is under the cursor. + + \since 5.2 +*/ + +/*! + \fn void QTabBar::tabBarDoubleClicked(int index) + + This signal is emitted when the user double clicks on a tab at \a index. + + \a index refers to the tab clicked, or -1 if no tab is under the cursor. + + \since 5.2 +*/ + int QTabBarPrivate::extraWidth() const { Q_Q(const QTabBar); @@ -1703,11 +1723,37 @@ void QTabBarPrivate::moveTab(int index, int offset) q_func()->update(); } + +/*! + \reimp +*/ +void QTabBar::mouseDoubleClickEvent(QMouseEvent *event) +{ + Q_D(QTabBar); + + const QPoint pos = event->pos(); + const bool isEventInCornerButtons = (!d->leftB->isHidden() && d->leftB->geometry().contains(pos)) + || (!d->rightB->isHidden() && d->rightB->geometry().contains(pos)); + if (!isEventInCornerButtons) { + const int index = tabAt(pos); + emit tabBarDoubleClicked(index); + } +} + /*!\reimp */ void QTabBar::mousePressEvent(QMouseEvent *event) { Q_D(QTabBar); + + const QPoint pos = event->pos(); + const bool isEventInCornerButtons = (!d->leftB->isHidden() && d->leftB->geometry().contains(pos)) + || (!d->rightB->isHidden() && d->rightB->geometry().contains(pos)); + if (!isEventInCornerButtons) { + const int index = d->indexAtPos(pos); + emit tabBarClicked(index); + } + if (event->button() != Qt::LeftButton) { event->ignore(); return; diff --git a/src/widgets/widgets/qtabbar.h b/src/widgets/widgets/qtabbar.h index 72c19ab520..1f7b8f6b03 100644 --- a/src/widgets/widgets/qtabbar.h +++ b/src/widgets/widgets/qtabbar.h @@ -173,6 +173,8 @@ Q_SIGNALS: void currentChanged(int index); void tabCloseRequested(int index); void tabMoved(int from, int to); + void tabBarClicked(int index); + void tabBarDoubleClicked(int index); protected: virtual QSize tabSizeHint(int index) const; @@ -186,6 +188,7 @@ protected: void showEvent(QShowEvent *); void hideEvent(QHideEvent *); void paintEvent(QPaintEvent *); + void mouseDoubleClickEvent(QMouseEvent *); void mousePressEvent (QMouseEvent *); void mouseMoveEvent (QMouseEvent *); void mouseReleaseEvent (QMouseEvent *); diff --git a/src/widgets/widgets/qtabbar_p.h b/src/widgets/widgets/qtabbar_p.h index 7468144146..8c6e70b8d7 100644 --- a/src/widgets/widgets/qtabbar_p.h +++ b/src/widgets/widgets/qtabbar_p.h @@ -138,6 +138,10 @@ public: } *animation; void startAnimation(QTabBarPrivate *priv, int duration) { + if (!priv->isAnimated()) { + priv->moveTabFinished(priv->tabList.indexOf(*this)); + return; + } if (!animation) animation = new TabBarAnimation(this, priv); animation->setStartValue(dragOffset); @@ -162,6 +166,7 @@ public: int indexAtPos(const QPoint &p) const; + inline bool isAnimated() const { Q_Q(const QTabBar); return q->style()->styleHint(QStyle::SH_Widget_Animate, 0, q); } inline bool validIndex(int index) const { return index >= 0 && index < tabList.count(); } void setCurrentNextEnabledIndex(int offset); diff --git a/src/widgets/widgets/qtabwidget.cpp b/src/widgets/widgets/qtabwidget.cpp index 4df55e2537..9d14c01490 100644 --- a/src/widgets/widgets/qtabwidget.cpp +++ b/src/widgets/widgets/qtabwidget.cpp @@ -172,6 +172,26 @@ QT_BEGIN_NAMESPACE \sa setTabsClosable() */ +/*! + \fn void QTabWidget::tabBarClicked(int index) + + This signal is emitted when user clicks on a tab at an \a index. + + \a index refers to the tab clicked, or -1 if no tab is under the cursor. + + \since 5.2 +*/ + +/*! + \fn void QTabWidget::tabBarDoubleClicked(int index) + + This signal is emitted when the user double clicks on a tab at an \a index. + + \a index is the index of a clicked tab, or -1 if no tab is under the cursor. + + \since 5.2 +*/ + class QTabWidgetPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QTabWidget) @@ -693,6 +713,10 @@ void QTabWidget::setTabBar(QTabBar* tb) this, SLOT(_q_showTab(int))); connect(d->tabs, SIGNAL(tabMoved(int,int)), this, SLOT(_q_tabMoved(int,int))); + connect(d->tabs, SIGNAL(tabBarClicked(int)), + this, SIGNAL(tabBarClicked(int))); + connect(d->tabs, SIGNAL(tabBarDoubleClicked(int)), + this, SIGNAL(tabBarDoubleClicked(int))); if (d->tabs->tabsClosable()) connect(d->tabs, SIGNAL(tabCloseRequested(int)), this, SIGNAL(tabCloseRequested(int))); diff --git a/src/widgets/widgets/qtabwidget.h b/src/widgets/widgets/qtabwidget.h index 1a1eb2ef2b..83c2e31d28 100644 --- a/src/widgets/widgets/qtabwidget.h +++ b/src/widgets/widgets/qtabwidget.h @@ -151,6 +151,8 @@ public Q_SLOTS: Q_SIGNALS: void currentChanged(int index); void tabCloseRequested(int index); + void tabBarClicked(int index); + void tabBarDoubleClicked(int index); protected: virtual void tabInserted(int index); diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index 4b3bf6de65..4e0c682493 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -773,6 +773,35 @@ QTextDocument *QTextEdit::document() const } /*! + \since 5.2 + + \property QTextEdit::placeholderText + \brief the editor placeholder text + + Setting this property makes the editor display a grayed-out + placeholder text as long as the document() is empty. + + By default, this property contains an empty string. + + \sa document() +*/ +QString QTextEdit::placeholderText() const +{ + Q_D(const QTextEdit); + return d->placeholderText; +} + +void QTextEdit::setPlaceholderText(const QString &placeholderText) +{ + Q_D(QTextEdit); + if (d->placeholderText != placeholderText) { + d->placeholderText = placeholderText; + if (d->control->document()->isEmpty()) + d->viewport->update(); + } +} + +/*! Sets the visible \a cursor. */ void QTextEdit::setTextCursor(const QTextCursor &cursor) @@ -1499,6 +1528,13 @@ void QTextEdit::paintEvent(QPaintEvent *e) Q_D(QTextEdit); QPainter p(d->viewport); d->paint(&p, e); + if (!d->placeholderText.isEmpty() && d->control->document()->isEmpty()) { + QColor col = palette().text().color(); + col.setAlpha(128); + p.setPen(col); + const int margin = int(document()->documentMargin()); + p.drawText(d->viewport->rect().adjusted(margin, margin, -margin, -margin), Qt::AlignTop | Qt::TextWordWrap, d->placeholderText); + } } void QTextEditPrivate::_q_currentCharFormatChanged(const QTextCharFormat &fmt) diff --git a/src/widgets/widgets/qtextedit.h b/src/widgets/widgets/qtextedit.h index e1471848e7..06ec5fb889 100644 --- a/src/widgets/widgets/qtextedit.h +++ b/src/widgets/widgets/qtextedit.h @@ -85,6 +85,7 @@ class Q_WIDGETS_EXPORT QTextEdit : public QAbstractScrollArea Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth) Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags) Q_PROPERTY(QTextDocument *document READ document WRITE setDocument DESIGNABLE false) + Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText) public: enum LineWrapMode { NoWrap, @@ -108,6 +109,9 @@ public: void setDocument(QTextDocument *document); QTextDocument *document() const; + void setPlaceholderText(const QString &placeholderText); + QString placeholderText() const; + void setTextCursor(const QTextCursor &cursor); QTextCursor textCursor() const; diff --git a/src/widgets/widgets/qtextedit_p.h b/src/widgets/widgets/qtextedit_p.h index 1ce68dc23e..daa6eb5ed0 100644 --- a/src/widgets/widgets/qtextedit_p.h +++ b/src/widgets/widgets/qtextedit_p.h @@ -130,6 +130,8 @@ public: QString anchorToScrollToWhenVisible; + QString placeholderText; + #ifdef QT_KEYPAD_NAVIGATION QBasicTimer deleteAllTimer; #endif diff --git a/src/widgets/widgets/qwidgetanimator.cpp b/src/widgets/widgets/qwidgetanimator.cpp index bbd96ca29a..1209ade536 100644 --- a/src/widgets/widgets/qwidgetanimator.cpp +++ b/src/widgets/widgets/qwidgetanimator.cpp @@ -91,24 +91,28 @@ void QWidgetAnimator::animate(QWidget *widget, const QRect &_final_geometry, boo QRect(QPoint(-500 - widget->width(), -500 - widget->height()), widget->size()); #ifndef QT_NO_ANIMATION - AnimationMap::const_iterator it = m_animation_map.constFind(widget); - if (it != m_animation_map.constEnd() && (*it)->endValue().toRect() == final_geometry) - return; + //If the QStyle has animations, animate + if (widget->style()->styleHint(QStyle::SH_Widget_Animate, 0, widget)) { + AnimationMap::const_iterator it = m_animation_map.constFind(widget); + if (it != m_animation_map.constEnd() && (*it)->endValue().toRect() == final_geometry) + return; - QPropertyAnimation *anim = new QPropertyAnimation(widget, "geometry", widget); - anim->setDuration(animate ? 200 : 0); - anim->setEasingCurve(QEasingCurve::InOutQuad); - anim->setEndValue(final_geometry); - m_animation_map[widget] = anim; - connect(anim, SIGNAL(finished()), SLOT(animationFinished())); - anim->start(QPropertyAnimation::DeleteWhenStopped); -#else + QPropertyAnimation *anim = new QPropertyAnimation(widget, "geometry", widget); + anim->setDuration(animate ? 200 : 0); + anim->setEasingCurve(QEasingCurve::InOutQuad); + anim->setEndValue(final_geometry); + m_animation_map[widget] = anim; + connect(anim, SIGNAL(finished()), SLOT(animationFinished())); + anim->start(QPropertyAnimation::DeleteWhenStopped); + } else +#endif //QT_NO_ANIMATION + { //we do it in one shot widget->setGeometry(final_geometry); #ifndef QT_NO_MAINWINDOW m_mainWindowLayout->animationFinished(widget); #endif //QT_NO_MAINWINDOW -#endif //QT_NO_ANIMATION + } } bool QWidgetAnimator::animating() const diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 9212f942c5..d10001a305 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -427,7 +427,7 @@ bool QWidgetLineControl::fixup() // this function assumes that validate currentl m_validator->fixup(textCopy); if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) { if (textCopy != m_text || cursorCopy != m_cursor) - internalSetText(textCopy, cursorCopy); + internalSetText(textCopy, cursorCopy, false); return true; } } @@ -672,7 +672,7 @@ bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool e m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); if (m_validInput) { if (m_text != textCopy) { - internalSetText(textCopy, cursorCopy); + internalSetText(textCopy, cursorCopy, false); return true; } m_cursor = cursorCopy; diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index de06d4454a..0255183c87 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -2126,6 +2126,13 @@ void QWidgetTextControlPrivate::editFocusEvent(QEvent *e) #endif #ifndef QT_NO_CONTEXTMENU +static inline void setActionIcon(QAction *action, const QString &name) +{ + const QIcon icon = QIcon::fromTheme(name); + if (!icon.isNull()) + action->setIcon(icon); +} + QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget *parent) { Q_D(QWidgetTextControl); @@ -2145,17 +2152,21 @@ QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget if (d->interactionFlags & Qt::TextEditable) { a = menu->addAction(tr("&Undo") + ACCEL_KEY(QKeySequence::Undo), this, SLOT(undo())); a->setEnabled(d->doc->isUndoAvailable()); + setActionIcon(a, QStringLiteral("edit-undo")); a = menu->addAction(tr("&Redo") + ACCEL_KEY(QKeySequence::Redo), this, SLOT(redo())); a->setEnabled(d->doc->isRedoAvailable()); + setActionIcon(a, QStringLiteral("edit-redo")); menu->addSeparator(); a = menu->addAction(tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut), this, SLOT(cut())); a->setEnabled(d->cursor.hasSelection()); + setActionIcon(a, QStringLiteral("edit-cut")); } if (showTextSelectionActions) { a = menu->addAction(tr("&Copy") + ACCEL_KEY(QKeySequence::Copy), this, SLOT(copy())); a->setEnabled(d->cursor.hasSelection()); + setActionIcon(a, QStringLiteral("edit-copy")); } if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard) @@ -2169,9 +2180,11 @@ QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget #if !defined(QT_NO_CLIPBOARD) a = menu->addAction(tr("&Paste") + ACCEL_KEY(QKeySequence::Paste), this, SLOT(paste())); a->setEnabled(canPaste()); + setActionIcon(a, QStringLiteral("edit-paste")); #endif a = menu->addAction(tr("Delete"), this, SLOT(_q_deleteSelected())); a->setEnabled(d->cursor.hasSelection()); + setActionIcon(a, QStringLiteral("edit-delete")); } diff --git a/src/xml/doc/qtxml.qdocconf b/src/xml/doc/qtxml.qdocconf index 4e8cf34b0c..f9c847e022 100644 --- a/src/xml/doc/qtxml.qdocconf +++ b/src/xml/doc/qtxml.qdocconf @@ -40,3 +40,6 @@ exampledirs += ../../../examples/xml \ imagedirs += images \ ../../../examples/xml/images + +navigation.landingpage = "Qt XML" +navigation.cppclassespage = "Qt XML C++ Classes" diff --git a/src/xml/doc/src/qtxml.qdoc b/src/xml/doc/src/qtxml.qdoc index 5ffa0f7330..925e492880 100644 --- a/src/xml/doc/src/qtxml.qdoc +++ b/src/xml/doc/src/qtxml.qdoc @@ -29,6 +29,7 @@ \module QtXml \title Qt XML C++ Classes \ingroup modules + \qtvariable xml \brief The Qt XML module provides C++ implementations of the SAX and DOM standards for XML. diff --git a/tests/auto/android/runtests.pl b/tests/auto/android/runtests.pl index 7bb6833859..55e1a224d8 100755 --- a/tests/auto/android/runtests.pl +++ b/tests/auto/android/runtests.pl @@ -79,6 +79,7 @@ GetOptions('h|help' => \$help , 'ant=s' => \$ant_tool , 'strip=s' => \$strip_tool , 'readelf=s' => \$readelf_tool + , 'testcase=s' => \$testcase ) or pod2usage(2); pod2usage(1) if $help; pod2usage(-verbose => 2) if $man; @@ -232,6 +233,7 @@ if ($deploy_qt) print ("cp -L $_ $temp_dir/lib\n"); system("cp -L $_ $temp_dir/lib"); } + system("cp -L $android_ndk_dir/sources/cxx-stl/gnu-libstdc++/4.7/libs/armeabi-v7a/libgnustl_shared.so $temp_dir/lib"); system("cp -a plugins $temp_dir"); system("cp -a imports $temp_dir"); system("cp -a qml $temp_dir"); @@ -252,7 +254,14 @@ print "Building $tests_dir \n"; system("make distclean") if ($make_clean); system("$qmake_path CONFIG-=QTDIR_build -r") == 0 or die "Can't run qmake\n"; #exec qmake system("make -j$jobs") == 0 or warn "Can't build all tests\n"; #exec make -my $testsFiles=`find . -name libtst_*.so`; # only tests + +my $testsFiles = ""; +if ($testcase) { + $testsFiles=`find . -name libtst_$testcase.so`; # only tests +} else { + $testsFiles=`find . -name libtst_*.so`; # only tests +} + foreach (split("\n",$testsFiles)) { chomp; #remove white spaces diff --git a/tests/auto/android/src/org/qtproject/qt5/android/QtActivity.java b/tests/auto/android/src/org/qtproject/qt5/android/QtActivity.java index 6242f55488..ed190fdc1b 100644 --- a/tests/auto/android/src/org/qtproject/qt5/android/QtActivity.java +++ b/tests/auto/android/src/org/qtproject/qt5/android/QtActivity.java @@ -62,9 +62,9 @@ public class QtActivity extends Activity { QtNative.loadQtLibraries(libs); // start application - final String envPaths = "NECESSITAS_API_LEVEL=2\tHOME=" + getDir("files", MODE_WORLD_WRITEABLE).getAbsolutePath() + - "\tTMPDIR=" + getDir("files", MODE_WORLD_WRITEABLE).getAbsolutePath() + - "\tCACHE_PATH=" + getDir("files", MODE_WORLD_WRITEABLE).getAbsolutePath(); + final String envPaths = "NECESSITAS_API_LEVEL=2\tHOME=" + getDir("files", MODE_WORLD_WRITEABLE | MODE_WORLD_READABLE).getAbsolutePath() + + "\tTMPDIR=" + getDir("files", MODE_WORLD_WRITEABLE | MODE_WORLD_READABLE).getAbsolutePath() + + "\tCACHE_PATH=" + getDir("files", MODE_WORLD_WRITEABLE | MODE_WORLD_READABLE).getAbsolutePath(); if (environment != null && environment.length() > 0) environment = envPaths + "\t" + environment; else @@ -102,6 +102,7 @@ public class QtActivity extends Activity { } if (getIntent().getExtras().containsKey("lib_name")) { mainLib = getIntent().getExtras().getString("lib_name"); + libraryList.add(mainLib); int slash = mainLib.lastIndexOf("/"); if (slash >= 0) { nativeLibDir = mainLib.substring(0, slash+1); @@ -120,6 +121,7 @@ public class QtActivity extends Activity { // TODO Auto-generated catch block e.printStackTrace(); } + finish(); System.exit(0); } String[] libs = new String[libraryList.size()]; @@ -136,7 +138,7 @@ public class QtActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - getDir("files", MODE_WORLD_WRITEABLE); + getDir("files", MODE_WORLD_WRITEABLE | MODE_WORLD_READABLE); requestWindowFeature(Window.FEATURE_NO_TITLE); m_quitApp = true; QtNative.setMainActivity(this); diff --git a/tests/auto/android/src/org/qtproject/qt5/android/QtNative.java b/tests/auto/android/src/org/qtproject/qt5/android/QtNative.java index d9995e3178..a61543d31a 100644 --- a/tests/auto/android/src/org/qtproject/qt5/android/QtNative.java +++ b/tests/auto/android/src/org/qtproject/qt5/android/QtNative.java @@ -164,7 +164,8 @@ public class QtNative extends Application m_displayMetricsDesktopWidthPixels, m_displayMetricsDesktopHeightPixels, m_displayMetricsXDpi, - m_displayMetricsYDpi); + m_displayMetricsYDpi, + 1.0); startQtApplication(f.getAbsolutePath()+"\t"+params, environment); m_started = true; } @@ -183,7 +184,7 @@ public class QtNative extends Application synchronized (m_mainActivityMutex) { if (m_started) { - setDisplayMetrics(screenWidthPixels, screenHeightPixels, desktopWidthPixels, desktopHeightPixels, XDpi, YDpi); + setDisplayMetrics(screenWidthPixels, screenHeightPixels, desktopWidthPixels, desktopHeightPixels, XDpi, YDpi, 1.0); } else { m_displayMetricsScreenWidthPixels = screenWidthPixels; m_displayMetricsScreenHeightPixels = screenHeightPixels; @@ -379,8 +380,12 @@ public class QtNative extends Application // screen methods public static native void setDisplayMetrics(int screenWidthPixels, - int screenHeightPixels, int desktopWidthPixels, - int desktopHeightPixels, double XDpi, double YDpi); + int screenHeightPixels, + int desktopWidthPixels, + int desktopHeightPixels, + double XDpi, + double YDpi, + double scaledDensity); public static native void handleOrientationChanged(int newOrientation); // screen methods diff --git a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp index 1f57e38b44..4fcc46efab 100644 --- a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp +++ b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp @@ -361,7 +361,7 @@ void tst_QIpAddress::parseIp6() #endif Ip6 result; - bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()); + bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0; QVERIFY(ok); QCOMPARE(result, expected); } @@ -441,7 +441,7 @@ void tst_QIpAddress::invalidParseIp6() #endif Ip6 result; - bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()); + bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0; QVERIFY(!ok); } diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp index f94c8eac4f..501dde1ba5 100644 --- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp +++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp @@ -166,7 +166,7 @@ void tst_qstandardpaths::testCustomLocations() void tst_qstandardpaths::enableTestMode() { QVERIFY(!QStandardPaths::isTestModeEnabled()); - QStandardPaths::enableTestMode(true); + QStandardPaths::setTestModeEnabled(true); QVERIFY(QStandardPaths::isTestModeEnabled()); #ifdef Q_XDG_PLATFORM @@ -204,7 +204,7 @@ void tst_qstandardpaths::enableTestMode() // On Windows, what should "Program Files" become, in test mode? //testLocations.insert(QStandardPaths::ApplicationsLocation, QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)); - QStandardPaths::enableTestMode(false); + QStandardPaths::setTestModeEnabled(false); for (LocationHash::const_iterator it = testLocations.constBegin(); it != testLocations.constEnd(); ++it) QVERIFY2(QStandardPaths::writableLocation(it.key()) != it.value(), qPrintable(it.value())); diff --git a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp index 40621957ce..db2a5b53fd 100644 --- a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp +++ b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp @@ -40,13 +40,11 @@ ****************************************************************************/ -#include <QtCore/QCoreApplication> #include <QtCore/QTextStream> -#include <QtCore/QDebug> +#include <stdio.h> -int main(int argc, char **argv) +int main(int, char**) { - QCoreApplication a(argc, argv); - qDebug() << QTextStream(stdin).readAll(); + fprintf(stderr, "%s\n", QTextStream(stdin).readAll().toLatin1().constData()); return 0; } diff --git a/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp index e36a2aeda8..cb4e75c6a2 100644 --- a/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp +++ b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp @@ -40,17 +40,16 @@ ****************************************************************************/ -#include <QtCore/QCoreApplication> #include <QtCore/QTextStream> +#include <stdio.h> -int main(int argc, char **argv) +int main(int, char**) { - QCoreApplication a(argc, argv); QTextStream qin(stdin); if (!qin.atEnd()) { - int a, b, c; - qin >> a >> b >> c; - qDebug("%d %d %d", a, b, c); + int a, b, c; + qin >> a >> b >> c; + fprintf(stderr, "%d %d %d\n", a, b, c); } return 0; } diff --git a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp index 56c07f1590..c19e80bff3 100644 --- a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp +++ b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp @@ -1425,8 +1425,7 @@ void tst_QTextStream::readAllFromStdin() stdinProcess.closeWriteChannel(); QVERIFY(stdinProcess.waitForFinished(5000)); - QChar quoteChar('"'); - QCOMPARE(stream.readAll(), QString::fromLatin1("%1hello world%2 \n").arg(quoteChar).arg(quoteChar)); + QCOMPARE(stream.readAll(), QString::fromLatin1("hello world\n")); } // ------------------------------------------------------------------------------ diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 2a506ef8e2..2817e6d22c 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -111,6 +111,8 @@ private slots: void percentEncoding(); void swap(); void symmetry(); + void ipvfuture_data(); + void ipvfuture(); void ipv6_data(); void ipv6(); void ipv6_2_data(); @@ -160,6 +162,8 @@ private slots: void binaryData(); void fromUserInput_data(); void fromUserInput(); + void fileName_data(); + void fileName(); void isEmptyForEncodedUrl(); void toEncodedNotUsingUninitializedPath(); void emptyAuthorityRemovesExistingAuthority(); @@ -291,6 +295,8 @@ void tst_QUrl::comparison() QVERIFY(url1 == url2); QVERIFY(!(url1 < url2)); QVERIFY(!(url2 < url1)); + QVERIFY(url1.matches(url2, QUrl::None)); + QVERIFY(url1.matches(url2, QUrl::StripTrailingSlash)); // 6.2.2 Syntax-based Normalization QUrl url3 = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D"); @@ -298,6 +304,20 @@ void tst_QUrl::comparison() QEXPECT_FAIL("", "Normalization not implemented, will probably not be implemented like this", Continue); QCOMPARE(url3, url4); + QUrl url3bis = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D/"); + QUrl url3bisNoSlash = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D"); + QUrl url4bis = QUrl::fromEncoded("example://a/.//b/../b/c//%7Bfoo%7D/"); + QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments), url3bis); + QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments | QUrl::StripTrailingSlash), url3bisNoSlash); + QVERIFY(url3bis.matches(url4bis, QUrl::NormalizePathSegments)); + QVERIFY(!url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments)); + QVERIFY(url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments | QUrl::StripTrailingSlash)); + + QUrl url4EncodedDots = QUrl("example://a/.//b/%2E%2E%2F/b/c/"); + QCOMPARE(QString::fromLatin1(url4EncodedDots.toEncoded()), QString::fromLatin1("example://a/.//b/..%2F/b/c/")); + QCOMPARE(url4EncodedDots.toString(), QString("example://a/.//b/..%2F/b/c/")); + QCOMPARE(url4EncodedDots.adjusted(QUrl::NormalizePathSegments).toString(), QString("example://a/b/..%2F/b/c/")); + // 6.2.2.1 Make sure hexdecimal characters in percent encoding are // treated case-insensitively QUrl url5; @@ -312,6 +332,59 @@ void tst_QUrl::comparison() url8.setEncodedQuery("a=c"); QVERIFY(url7 != url8); QVERIFY(url7 < url8); + + // Trailing slash difference + QUrl url9("http://qt-project.org/path/"); + QUrl url9NoSlash("http://qt-project.org/path"); + QVERIFY(!(url9 == url9NoSlash)); + QVERIFY(!url9.matches(url9NoSlash, QUrl::None)); + QVERIFY(url9.matches(url9NoSlash, QUrl::StripTrailingSlash)); + + // RemoveFilename + QUrl url10("http://qt-project.org/file"); + QUrl url10bis("http://qt-project.org/otherfile"); + QVERIFY(!(url10 == url10bis)); + QVERIFY(!url10.matches(url10bis, QUrl::None)); + QVERIFY(!url10.matches(url10bis, QUrl::StripTrailingSlash)); + QVERIFY(url10.matches(url10bis, QUrl::RemoveFilename)); + + // RemoveAuthority + QUrl authUrl1("x://host/a/b"); + QUrl authUrl2("x://host/a/"); + QUrl authUrl3("x:/a/b"); + QVERIFY(authUrl1.matches(authUrl2, QUrl::RemoveFilename)); + QCOMPARE(authUrl1.adjusted(QUrl::RemoveAuthority), authUrl3.adjusted(QUrl::RemoveAuthority)); + QVERIFY(authUrl1.matches(authUrl3, QUrl::RemoveAuthority)); + QCOMPARE(authUrl2.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename), authUrl3.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename)); + QVERIFY(authUrl2.matches(authUrl3, QUrl::RemoveAuthority | QUrl::RemoveFilename)); + QVERIFY(authUrl3.matches(authUrl2, QUrl::RemoveAuthority | QUrl::RemoveFilename)); + + QUrl hostUrl1("file:/foo"); + QUrl hostUrl2("file:///foo"); + QVERIFY(hostUrl1 == hostUrl2); + QVERIFY(hostUrl1.matches(hostUrl2, QUrl::None)); + QVERIFY(hostUrl1.matches(hostUrl2, QUrl::RemoveAuthority)); + + // RemovePassword + QUrl passUrl1("http://user:pass@host/"); + QUrl passUrl2("http://user:PASS@host/"); + QVERIFY(!(passUrl1 == passUrl2)); + QVERIFY(passUrl1 != passUrl2); + QVERIFY(!passUrl1.matches(passUrl2, QUrl::None)); + QVERIFY(passUrl1.matches(passUrl2, QUrl::RemovePassword)); + + // RemoveQuery, RemoveFragment + QUrl queryFragUrl1("http://host/file?query#fragment"); + QUrl queryFragUrl2("http://host/file?q2#f2"); + QUrl queryFragUrl3("http://host/file"); + QVERIFY(!(queryFragUrl1 == queryFragUrl2)); + QVERIFY(queryFragUrl1 != queryFragUrl2); + QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::None)); + QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery)); + QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveFragment)); + QVERIFY(queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery | QUrl::RemoveFragment)); + QVERIFY(queryFragUrl1.matches(queryFragUrl3, QUrl::RemoveQuery | QUrl::RemoveFragment)); + QVERIFY(queryFragUrl3.matches(queryFragUrl1, QUrl::RemoveQuery | QUrl::RemoveFragment)); } void tst_QUrl::comparison2_data() @@ -685,8 +758,8 @@ void tst_QUrl::setUrl() QVERIFY(url.isValid()); QCOMPARE(url.scheme(), QString("data")); QCOMPARE(url.host(), QString()); - QCOMPARE(url.path(), QString("text/javascript,d5 = 'five\\u0027s';")); - QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20=%20'five%5Cu0027s';"); + QCOMPARE(url.path(), QString("text/javascript,d5 %3D 'five\\u0027s'%3B")); + QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20%3D%20'five%5Cu0027s'%3B"); } { @@ -946,8 +1019,12 @@ void tst_QUrl::toString() QFETCH(uint, options); QFETCH(QString, string); + QUrl::FormattingOptions opt(options); + QUrl url(urlString); - QCOMPARE(url.toString(QUrl::FormattingOptions(options)), string); + QCOMPARE(url.toString(opt), string); + + QCOMPARE(url.adjusted(opt).toString(), string); } void tst_QUrl::toAndFromStringList_data() @@ -1498,17 +1575,17 @@ void tst_QUrl::relative() void tst_QUrl::percentEncoding_data() { + // This test is limited. It's superseded by componentEncodings below QTest::addColumn<QString>("original"); QTest::addColumn<QByteArray>("encoded"); QTest::newRow("test_01") << QString::fromLatin1("sdfsdf") << QByteArray("sdfsdf"); QTest::newRow("test_02") << QString::fromUtf8("æss") << QByteArray("%C3%A6ss"); - // not unreserved or reserved - QTest::newRow("test_03") << QString::fromLatin1("{}") << QByteArray("%7B%7D"); } void tst_QUrl::percentEncoding() { + // This test is limited. It's superseded by componentEncodings below QFETCH(QString, original); QFETCH(QByteArray, encoded); @@ -1583,21 +1660,83 @@ void tst_QUrl::symmetry() { QString urlString = QString::fromLatin1("http://desktop:33326/upnp/{32f525a6-6f31-426e-91ca-01c2e6c2c57e}"); + QString encodedUrlString = QString("http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D"); QUrl urlPreviewList(urlString); - QCOMPARE(urlPreviewList.toString(), urlString); + QCOMPARE(urlPreviewList.toString(), encodedUrlString); QByteArray b = urlPreviewList.toEncoded(); - QCOMPARE(b.constData(), "http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D"); - QCOMPARE(QUrl::fromEncoded(b).toString(), urlString); - QCOMPARE(QUrl(b).toString(), urlString); + QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData()); + QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString); + QCOMPARE(QUrl(b).toString(), encodedUrlString); } { QString urlString = QString::fromLatin1("http://desktop:53423/deviceDescription?uuid={7977c17b-00bf-4af9-894e-fed28573c3a9}"); + QString encodedUrlString = QString("http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D"); QUrl urlPreviewList(urlString); - QCOMPARE(urlPreviewList.toString(), urlString); + QCOMPARE(urlPreviewList.toString(), encodedUrlString); QByteArray b = urlPreviewList.toEncoded(); - QCOMPARE(b.constData(), "http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D"); - QCOMPARE(QUrl::fromEncoded(b).toString(), urlString); - QCOMPARE(QUrl(b).toString(), urlString); + QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData()); + QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString); + QCOMPARE(QUrl(b).toString(), encodedUrlString); + } +} + +void tst_QUrl::ipvfuture_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<bool>("isValid"); + QTest::addColumn<QString>("output"); + + // No one uses IPvFuture yet, so we have no clue what it might contain + // We're just testing that it can hold what the RFC says it should hold: + // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + QTest::newRow("missing-version-dot") << "x://[v]" << false; + QTest::newRow("missing-version") << "x://[v.]" << false; + QTest::newRow("missing-version-2") << "x://[v.1234]" << false; + QTest::newRow("missing-dot") << "x://[v7]" << false; + QTest::newRow("missing-dot-2") << "x://[v71234]" << false; + QTest::newRow("missing-data") << "x://[v7.]" << false; + QTest::newRow("non-hex-version") << "x://[vz.1234]" << false; + + QTest::newRow("digit-ver") << "x://[v7.1]" << true << "x://[v7.1]"; + QTest::newRow("lowercase-hex-ver") << "x://[va.1]" << true << "x://[vA.1]"; + QTest::newRow("lowercase-hex-ver") << "x://[vA.1]" << true << "x://[vA.1]"; + + QTest::newRow("data-digits") << "x://[v7.1234]" << true << "x://[v7.1234]"; + QTest::newRow("data-unreserved") << "x://[v7.hello~-WORLD_.com]" << true << "x://[v7.hello~-WORLD_.com]"; + QTest::newRow("data-sub-delims-colon") << "x://[v7.!$&'()*+,;=:]" << true << "x://[v7.!$&'()*+,;=:]"; + + // we're using the tolerant parser + QTest::newRow("data-encoded-digits") << "x://[v7.%31%32%33%34]" << true << "x://[v7.1234]"; + QTest::newRow("data-encoded-unreserved") << "x://[v7.%7E%2D%54%5f%2E]" << true << "x://[v7.~-T_.]"; + QTest::newRow("data-encoded-sub-delims-colon") << "x://[v7.%21%24%26%27%28%29%2A%2B%2C%3B%3D%3A]" << true << "x://[v7.!$&'()*+,;=:]"; + + // should we test "[%76%37%2ex]" -> "[v7.x]" ? + + QTest::newRow("data-invalid-space") << "x://[v7.%20]" << false; + QTest::newRow("data-invalid-control") << "x://[v7.\x7f]" << false; + QTest::newRow("data-invalid-other-1") << "x://[v7.{1234}]" << false; + QTest::newRow("data-invalid-other-2") << "x://[v7.<hello>]" << false; + QTest::newRow("data-invalid-unicode") << "x://[v7.æøå]" << false; + QTest::newRow("data-invalid-percent") << "x://[v7.%]" << false; + QTest::newRow("data-invalid-percent-percent") << "x://[v7.%25]" << false; +} + +void tst_QUrl::ipvfuture() +{ + QFETCH(QString, input); + QFETCH(bool, isValid); + + QUrl url(input); + if (isValid) { + QVERIFY2(url.isValid(), qPrintable(url.errorString())); + + QFETCH(QString, output); + QCOMPARE(url.toString(), output); + + QUrl url2(output); + QCOMPARE(url2, url); + } else { + QVERIFY(!url.isValid()); } } @@ -1641,6 +1780,9 @@ void tst_QUrl::ipv6_data() QTest::newRow("case :,") << QString::fromLatin1("//[:,]") << false << ""; QTest::newRow("case ::bla") << QString::fromLatin1("//[::bla]") << false << ""; QTest::newRow("case v4-mapped") << "//[0:0:0:0:0:ffff:7f00:1]" << true << "//[::ffff:127.0.0.1]"; + + QTest::newRow("encoded-digit") << "//[::%31]" << true << "//[::1]"; + QTest::newRow("encoded-colon") << "//[%3A%3A]" << true << "//[::]"; } void tst_QUrl::ipv6() @@ -1932,9 +2074,14 @@ void tst_QUrl::strictParser_data() QTest::newRow("invalid-regname") << "http://bad<hostname>" << "Invalid hostname (contains invalid characters)"; QTest::newRow("invalid-regname-2") << "http://b%61d" << "Invalid hostname (contains invalid characters)"; QTest::newRow("invalid-ipv6") << "http://[:::]" << "Invalid IPv6 address"; + QTest::newRow("invalid-ipv6-char1") << "http://[::g]" << "Invalid IPv6 address (character 'g' not permitted)"; + QTest::newRow("invalid-ipv6-char2") << "http://[z::]" << "Invalid IPv6 address (character 'z' not permitted)"; QTest::newRow("invalid-ipvfuture-1") << "http://[v7]" << "Invalid IPvFuture address"; QTest::newRow("invalid-ipvfuture-2") << "http://[v7.]" << "Invalid IPvFuture address"; QTest::newRow("invalid-ipvfuture-3") << "http://[v789]" << "Invalid IPvFuture address"; + QTest::newRow("invalid-ipvfuture-char1") << "http://[v7.^]" << "Invalid IPvFuture address"; + QTest::newRow("invalid-encoded-ipv6") << "x://[%3a%3a%31]" << "Invalid IPv6 address"; + QTest::newRow("invalid-encoded-ipvfuture") << "x://[v7.%7E%2D%54%5f%2E]" << "Invalid IPvFuture address"; QTest::newRow("unbalanced-brackets") << "http://[ff02::1" << "Expected ']' to match '[' in hostname"; // invalid hostnames happen in TolerantMode too @@ -2035,35 +2182,22 @@ void tst_QUrl::tolerantParser() url.setUrl("http://foo.bar/[image][1].jpg"); QVERIFY(url.isValid()); QVERIFY(!url.toString().isEmpty()); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg")); QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg")); - url.setUrl("[].jpg"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%5B%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg")); - QCOMPARE(url.toString(), QString("[].jpg")); - - url.setUrl("/some/[path]/[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toString(), QString("/some/[path]/[]")); + url.setUrl("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"); + QVERIFY(url.isValid()); + QVERIFY(!url.toString().isEmpty()); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); url.setUrl("//[::56:56:56:56:56:56:56]"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]")); QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]")); QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]")); - url.setUrl("//[::56:56:56:56:56:56:56]#[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]#[]")); - - url.setUrl("//[::56:56:56:56:56:56:56]?[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]?[]")); - // invoke the tolerant parser's error correction url.setUrl("%hello.com/f%"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%25hello.com/f%25")); @@ -2076,38 +2210,24 @@ void tst_QUrl::tolerantParser() url.setEncodedUrl("http://foo.bar/[image][1].jpg"); QVERIFY(url.isValid()); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg")); QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg")); - url.setEncodedUrl("[].jpg"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%5B%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg")); - QCOMPARE(url.toString(), QString("[].jpg")); - - url.setEncodedUrl("/some/[path]/[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toString(), QString("/some/[path]/[]")); + url.setEncodedUrl("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"); + QVERIFY(url.isValid()); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); url.setEncodedUrl("//[::56:56:56:56:56:56:56]"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]")); QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]")); - url.setEncodedUrl("//[::56:56:56:56:56:56:56]#[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]#[]")); - - url.setEncodedUrl("//[::56:56:56:56:56:56:56]?[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]?[]")); - url.setEncodedUrl("data:text/css,div%20{%20border-right:%20solid;%20}"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("data:text/css,div%20%7B%20border-right:%20solid;%20%7D")); QCOMPARE(url.toEncoded(), QByteArray("data:text/css,div%20%7B%20border-right:%20solid;%20%7D")); - QCOMPARE(url.toString(), QString("data:text/css,div { border-right: solid; }")); + QCOMPARE(url.toString(), QString("data:text/css,div %7B border-right: solid; %7D")); } { @@ -2386,7 +2506,7 @@ void tst_QUrl::setEncodedFragment_data() QTest::newRow("basic test") << BA("http://www.kde.org") << BA("abc") << BA("http://www.kde.org#abc"); QTest::newRow("initial url has fragment") << BA("http://www.kde.org#old") << BA("new") << BA("http://www.kde.org#new"); QTest::newRow("encoded fragment") << BA("http://www.kde.org") << BA("a%20c") << BA("http://www.kde.org#a%20c"); - QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a#b"); + QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a%23b"); // toString uses "a#b" QTest::newRow("unicode") << BA("http://www.kde.org") << BA("\xc3\xa9") << BA("http://www.kde.org#%C3%A9"); QTest::newRow("binary") << BA("http://www.kde.org") << BA("\x00\xc0\x80", 3) << BA("http://www.kde.org#%00%C0%80"); } @@ -2427,23 +2547,37 @@ void tst_QUrl::fromEncoded() void tst_QUrl::stripTrailingSlash_data() { QTest::addColumn<QString>("url"); - QTest::addColumn<QString>("expected"); + QTest::addColumn<QString>("expectedStrip"); // toString(Strip) + QTest::addColumn<QString>("expectedDir"); // toString(RemoveFilename) + QTest::addColumn<QString>("expectedDirStrip"); // toString(RemoveFilename|Strip) - QTest::newRow("ftp no slash") << "ftp://ftp.de.kde.org/dir" << "ftp://ftp.de.kde.org/dir"; - QTest::newRow("ftp slash") << "ftp://ftp.de.kde.org/dir/" << "ftp://ftp.de.kde.org/dir"; - QTest::newRow("file slash") << "file:///dir/" << "file:///dir"; - QTest::newRow("file no slash") << "file:///dir/" << "file:///dir"; - QTest::newRow("file root") << "file:///" << "file:///"; - QTest::newRow("no path") << "remote://" << "remote://"; + QTest::newRow("subdir no slash") << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir"; + QTest::newRow("ftp no slash") << "ftp://kde.org/dir" << "ftp://kde.org/dir" << "ftp://kde.org/" << "ftp://kde.org/"; + QTest::newRow("ftp slash") << "ftp://kde.org/dir/" << "ftp://kde.org/dir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir"; + QTest::newRow("ftp_two_slashes") << "ftp://kde.org/dir//" << "ftp://kde.org/dir" << "ftp://kde.org/dir//" << "ftp://kde.org/dir"; + QTest::newRow("file slash") << "file:///dir/" << "file:///dir" << "file:///dir/" << "file:///dir"; + QTest::newRow("file no slash") << "file:///dir" << "file:///dir" << "file:///" << "file:///"; + QTest::newRow("file root") << "file:///" << "file:///" << "file:///" << "file:///"; + QTest::newRow("file_root_manyslashes") << "file://///" << "file:///" << "file://///" << "file:///"; + QTest::newRow("no path") << "remote://" << "remote://" << "remote://" << "remote://"; } void tst_QUrl::stripTrailingSlash() { QFETCH(QString, url); - QFETCH(QString, expected); + QFETCH(QString, expectedStrip); + QFETCH(QString, expectedDir); + QFETCH(QString, expectedDirStrip); QUrl u(url); - QCOMPARE(u.toString(QUrl::StripTrailingSlash), expected); + QCOMPARE(u.toString(QUrl::StripTrailingSlash), expectedStrip); + QCOMPARE(u.toString(QUrl::RemoveFilename), expectedDir); + QCOMPARE(u.toString(QUrl::RemoveFilename | QUrl::StripTrailingSlash), expectedDirStrip); + + // Same thing, using QUrl::adjusted() + QCOMPARE(u.adjusted(QUrl::StripTrailingSlash).toString(), expectedStrip); + QCOMPARE(u.adjusted(QUrl::RemoveFilename).toString(), expectedDir); + QCOMPARE(u.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toString(), expectedDirStrip); } void tst_QUrl::hosts_data() @@ -2729,6 +2863,43 @@ void tst_QUrl::fromUserInput() QCOMPARE(url, guessUrlFromString); } +void tst_QUrl::fileName_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<QString>("expectedDirPath"); + QTest::addColumn<QString>("expectedPrettyDecodedFileName"); + QTest::addColumn<QString>("expectedFullyDecodedFileName"); + + QTest::newRow("fromDocu") << "http://qt-project.org/support/file.html" + << "/support/" << "file.html" << "file.html"; + QTest::newRow("absoluteFile") << "file:///temp/tmp.txt" + << "/temp/" << "tmp.txt" << "tmp.txt"; + QTest::newRow("absoluteDir") << "file:///temp/" + << "/temp/" << QString() << QString(); + QTest::newRow("absoluteInRoot") << "file:///temp" + << "/" << "temp" << "temp"; + QTest::newRow("relative") << "temp/tmp.txt" + << "temp/" << "tmp.txt" << "tmp.txt"; + QTest::newRow("relativeNoSlash") << "tmp.txt" + << QString() << "tmp.txt" << "tmp.txt"; + QTest::newRow("encoded") << "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)" + << "/specials/" << "Print To File (PDF%252FAcrobat)" << "Print To File (PDF%2FAcrobat)"; +} + +void tst_QUrl::fileName() +{ + QFETCH(QString, urlStr); + QFETCH(QString, expectedDirPath); + QFETCH(QString, expectedPrettyDecodedFileName); + QFETCH(QString, expectedFullyDecodedFileName); + + QUrl url(urlStr); + QVERIFY(url.isValid()); + QCOMPARE(url.adjusted(QUrl::RemoveFilename).path(), expectedDirPath); + QCOMPARE(url.fileName(QUrl::PrettyDecoded), expectedPrettyDecodedFileName); + QCOMPARE(url.fileName(QUrl::FullyDecoded), expectedFullyDecodedFileName); +} + // This is a regression test for a previously fixed bug where isEmpty didn't // work for an encoded URL that was yet to be decoded. The test checks that // isEmpty works for an encoded URL both after and before decoding. @@ -2866,7 +3037,8 @@ void tst_QUrl::effectiveTLDs() { QFETCH(QUrl, domain); QFETCH(QString, TLD); - QCOMPARE(domain.topLevelDomain(), TLD); + QCOMPARE(domain.topLevelDomain(QUrl::PrettyDecoded), TLD); + QCOMPARE(domain.topLevelDomain(QUrl::FullyDecoded), TLD); } void tst_QUrl::lowercasesScheme() @@ -2950,19 +3122,25 @@ void tst_QUrl::componentEncodings_data() // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" // / "*" / "+" / "," / ";" / "=" - // like the unreserved, these are decoded everywhere - // don't test in query because they might remain encoded - QTest::newRow("decoded-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c#%3b%3d") + // these are always left alone + QTest::newRow("decoded-subdelims") << QUrl("x://!$&:'()@host/*+,?$=(+)#;=") << int(QUrl::FullyEncoded) << "!$&" << "'()" << "!$&:'()" << "host" << "!$&:'()@host" - << "/*+," << "" << ";=" - << "x://!$&:'()@host/*+,#;="; + << "/*+," << "$=(+)" << ";=" + << "x://!$&:'()@host/*+,?$=(+)#;="; + QTest::newRow("encoded-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c?%26=%26&%3d=%3d#%3b%3d") + << MostDecoded + << "%21%24%26" << "%27%28%29" << "%21%24%26:%27%28%29" + << "host" << "%21%24%26:%27%28%29@host" + << "/%2A%2B%2C" << "%26=%26&%3D=%3D" << "%3B%3D" + << "x://%21%24%26:%27%28%29@host/%2A%2B%2C?%26=%26&%3D=%3D#%3B%3D"; // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" // these are the separators between fields - // they must appear encoded in certain positions, no exceptions - // in other positions, they can appear decoded, so they always do + // they must appear encoded in certain positions in the full URL, no exceptions + // when in those positions, they appear decoded in the isolated parts + // in other positions and the other delimiters are always left untransformed // 1) test the delimiters that must appear encoded // (if they were decoded, they'd would change the URL parsing) QTest::newRow("encoded-gendelims-changing") << QUrl("x://%5b%3a%2f%3f%23%40%5d:%5b%2f%3f%23%40%5d@host/%2f%3f%23?%23") @@ -2972,32 +3150,21 @@ void tst_QUrl::componentEncodings_data() << "/%2F?#" << "#" << "" << "x://%5B%3A%2F%3F%23%40%5D:%5B%2F%3F%23%40%5D@host/%2F%3F%23?%23"; - // 2) test the delimiters that may appear decoded and would not change the meaning - // and test that %2f is *not* decoded to a slash in the path - // don't test the query because in this mode it doesn't transform anything - QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://:%3a@host/%2f%3a%40#%23%3a%2f%3f%40") + // 2) test that the other delimiters remain decoded + QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://::@host/:@/[]?:/?@[]?#:/?@[]") << int(QUrl::FullyEncoded) << "" << ":" << "::" << "host" << "::@host" - << "/%2F:@" << "" << "#:/?@" - << "x://::@host/%2F:@##:/?@"; - - // 3) test "[" and "]". Even though they are not ambiguous in the path, query or fragment - // the RFC does not allow them to appear there decoded. QUrl adheres strictly in FullyEncoded mode - QTest::newRow("encoded-square-brackets") << QUrl("x:/[]#[]") - << int(QUrl::FullyEncoded) - << "" << "" << "" - << "" << "" - << "/%5B%5D" << "" << "%5B%5D" - << "x:/%5B%5D#%5B%5D"; - - // 4) like above, but now decode them, which is allowed - QTest::newRow("decoded-square-brackets") << QUrl("x:/%5B%5D#%5B%5D") - << MostDecoded - << "" << "" << "" - << "" << "" - << "/[]" << "" << "[]" - << "x:/[]#[]"; + << "/:@/[]" << ":/?@[]?" << ":/?@[]" + << "x://::@host/:@/[]?:/?@[]?#:/?@[]"; + + // 3) and test that the same encoded sequences remain encoded + QTest::newRow("encoded-gendelims-unchanging") << QUrl("x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D") + << MostDecoded + << "" << "%3A" << ":%3A" + << "host" << ":%3A@host" + << "/%3A%40%5B%5D" << "%3A%2F%3F%40%5B%5D" << "%23%3A%2F%3F%40%5B%5D" + << "x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D"; // test the query // since QUrl doesn't know what chars the user wants to use for the pair and value delimiters, @@ -3051,23 +3218,13 @@ void tst_QUrl::componentEncodings_data() << QString::fromUtf8("é ") << QString::fromUtf8("x:// é:é @smørbrød.example.no/é ? é#é "); - // the pretty form re-encodes the subdelims (except in the query, where they are left alone) - QTest::newRow("pretty-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c?%26=%26&%3d=%3d#%3b%3d") - << int(QUrl::PrettyDecoded) - << "!$&" << "'()" << "!$&:'()" - << "host" << "!$&:'()@host" - << "/*+," << "%26=%26&%3D=%3D" << ";=" - << "x://!$&:'()@host/*+,?%26=%26&%3D=%3D#;="; - - // the pretty form decodes all unambiguous gen-delims - // (except in query, where they are left alone) - QTest::newRow("pretty-gendelims") << QUrl("x://%5b%3a%40%2f%5d:%5b%3a%40%2f%5d@host" - "/%3a%40%5b%3f%23%5d?[?%3f%23]%5b:%3a@%40%5d#%23") + // the pretty form decodes all unambiguous gen-delims in the individual parts + QTest::newRow("pretty-gendelims") << QUrl("x://%5b%3a%40%2f%3f%23%5d:%5b%40%2f%3f%23%5d@host/%3f%23?%23") << int(QUrl::PrettyDecoded) - << "[:@/]" << "[:@/]" << "[%3A@/]:[:@/]" - << "host" << "%5B%3A%40/%5D:%5B:%40/%5D@host" - << "/:@[?#]" << "[?%3F#]%5B:%3A@%40%5D" << "#" - << "x://%5B%3A%40%2F%5D:%5B:%40%2F%5D@host/:@[%3F%23]?[?%3F%23]%5B:%3A@%40%5D##"; + << "[:@/?#]" << "[@/?#]" << "[%3A@/?#]:[@/?#]" + << "host" << "%5B%3A%40/?#%5D:%5B%40/?#%5D@host" + << "/?#" << "#" << "" + << "x://%5B%3A%40%2F%3F%23%5D:%5B%40%2F%3F%23%5D@host/%3F%23?%23"; // the pretty form keeps the other characters decoded everywhere // except when rebuilding the full URL, when we only allow "{}" to remain decoded @@ -3076,8 +3233,8 @@ void tst_QUrl::componentEncodings_data() << "\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}:\"<>^\\{|}" << "host" << "\"<>^\\{|}:\"<>^\\{|}@host" << "/\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}" - << "x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host/%22%3C%3E%5E%5C{%7C}" - "?%22%3C%3E%5E%5C{%7C}#%22%3C%3E%5E%5C%7B%7C%7D"; + << "x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host/%22%3C%3E%5E%5C%7B%7C%7D" + "?%22%3C%3E%5E%5C%7B%7C%7D#%22%3C%3E%5E%5C%7B%7C%7D"; } void tst_QUrl::componentEncodings() @@ -3346,9 +3503,6 @@ void tst_QUrl::setComponents_data() QTest::newRow("invalid-scheme-encode") << QUrl("http://example.com") << int(Scheme) << "http%61" << Decoded << false << PrettyDecoded << "" << ""; - QTest::newRow("userinfo-encode") << QUrl("http://example.com") - << int(UserInfo) << "h%61llo:world@" << Decoded << true - << PrettyDecoded << "h%2561llo:world@" << "http://h%2561llo:world%40@example.com"; QTest::newRow("username-encode") << QUrl("http://example.com") << int(UserName) << "h%61llo:world" << Decoded << true << PrettyDecoded << "h%2561llo:world" << "http://h%2561llo%3Aworld@example.com"; @@ -3359,9 +3513,6 @@ void tst_QUrl::setComponents_data() QTest::newRow("invalid-host-encode") << QUrl("http://example.com") << int(Host) << "ex%61mple.com" << Decoded << false << PrettyDecoded << "" << ""; - QTest::newRow("invalid-authority-encode") << QUrl("http://example.com") - << int(Authority) << "ex%61mple.com" << Decoded << false - << PrettyDecoded << "" << ""; QTest::newRow("path-encode") << QUrl("http://example.com/foo") << int(Path) << "/bar%23" << Decoded << true << PrettyDecoded << "/bar%2523" << "http://example.com/bar%2523"; @@ -3371,11 +3522,7 @@ void tst_QUrl::setComponents_data() QTest::newRow("fragment-encode") << QUrl("http://example.com/foo#z") << int(Fragment) << "bar%23" << Decoded << true << PrettyDecoded << "bar%2523" << "http://example.com/foo#bar%2523"; - // force decoding; note how the userinfo becomes ambiguous - QTest::newRow("userinfo-decode") << QUrl("http://example.com") - << int(UserInfo) << "hello%3Aworld:}}>b9o%25kR(" << Tolerant << true - << FullyDecoded << "hello:world:}}>b9o%kR(" - << "http://hello%3Aworld:%7D%7D%3Eb9o%25kR(@example.com"; + // force decoding QTest::newRow("username-decode") << QUrl("http://example.com") << int(UserName) << "hello%3Aworld%25" << Tolerant << true << FullyDecoded << "hello:world%" << "http://hello%3Aworld%25@example.com"; diff --git a/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp b/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp index 2014045171..05d5f94e3d 100644 --- a/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp +++ b/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp @@ -824,12 +824,20 @@ void tst_QUrlInternal::correctEncodedMistakes() QFETCH(QString, expected); // prepend some data to be sure that it remains there - QString output = QTest::currentDataTag(); - expected.prepend(output); + QString dataTag = QTest::currentDataTag(); + QString output = dataTag; if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), 0)) output += input; - QCOMPARE(output, expected); + QCOMPARE(output, dataTag + expected); + + // now try the full decode mode + output = dataTag; + QString expected2 = QUrl::fromPercentEncoding(expected.toLatin1()); + + if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyDecoded)) + output += input; + QCOMPARE(output, dataTag + expected2); } static void addUtf8Data(const char *name, const char *data) @@ -1027,6 +1035,15 @@ void tst_QUrlInternal::encodingRecodeInvalidUtf8() if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyEncoded)) output += input; QCOMPARE(output, QTest::currentDataTag() + input); + + // verify for security reasons that all bad UTF-8 data got replaced by QChar::ReplacementCharacter + output = QTest::currentDataTag(); + if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyEncoded)) + output += input; + for (int i = strlen(QTest::currentDataTag()); i < output.length(); ++i) { + QVERIFY2(output.at(i).unicode() < 0x80 || output.at(i) == QChar::ReplacementCharacter, + qPrintable(QString("Character at i == %1 was U+%2").arg(i).arg(output.at(i).unicode(), 4, 16, QLatin1Char('0')))); + } } void tst_QUrlInternal::recodeByteArray_data() diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp index 94e6e1129e..9111c59408 100644 --- a/tests/auto/corelib/json/tst_qtjson.cpp +++ b/tests/auto/corelib/json/tst_qtjson.cpp @@ -45,6 +45,7 @@ #include "qjsonobject.h" #include "qjsonvalue.h" #include "qjsondocument.h" +#include <limits> #define INVALID_UNICODE "\357\277\277" // "\uffff" #define UNICODE_DJE "\320\202" // Character from the Serbian Cyrillic alphabet @@ -97,6 +98,8 @@ private Q_SLOTS: void toVariantList(); void toJson(); + void toJsonSillyNumericValues(); + void toJsonLargeNumericValues(); void fromJson(); void fromJsonErrors(); void fromBinary(); @@ -1201,6 +1204,89 @@ void tst_QtJson::toJson() } } +void tst_QtJson::toJsonSillyNumericValues() +{ + QJsonObject object; + QJsonArray array; + array.append(QJsonValue(std::numeric_limits<double>::infinity())); // encode to: null + array.append(QJsonValue(-std::numeric_limits<double>::infinity())); // encode to: null + array.append(QJsonValue(std::numeric_limits<double>::quiet_NaN())); // encode to: null + object.insert("Array", array); + + QByteArray json = QJsonDocument(object).toJson(); + + QByteArray expected = + "{\n" + " \"Array\": [\n" + " null,\n" + " null,\n" + " null\n" + " ]\n" + "}\n"; + + QCOMPARE(json, expected); + + QJsonDocument doc; + doc.setObject(object); + json = doc.toJson(); + QCOMPARE(json, expected); +} + +void tst_QtJson::toJsonLargeNumericValues() +{ + QJsonObject object; + QJsonArray array; + array.append(QJsonValue(1.234567)); // actual precision bug in Qt 5.0.0 + array.append(QJsonValue(1.7976931348623157e+308)); // JS Number.MAX_VALUE + array.append(QJsonValue(5e-324)); // JS Number.MIN_VALUE + array.append(QJsonValue(std::numeric_limits<double>::min())); + array.append(QJsonValue(std::numeric_limits<double>::max())); + array.append(QJsonValue(std::numeric_limits<double>::epsilon())); + array.append(QJsonValue(std::numeric_limits<double>::denorm_min())); + array.append(QJsonValue(0.0)); + array.append(QJsonValue(-std::numeric_limits<double>::min())); + array.append(QJsonValue(-std::numeric_limits<double>::max())); + array.append(QJsonValue(-std::numeric_limits<double>::epsilon())); + array.append(QJsonValue(-std::numeric_limits<double>::denorm_min())); + array.append(QJsonValue(-0.0)); + array.append(QJsonValue(9007199254740992LL)); // JS Number max integer + array.append(QJsonValue(-9007199254740992LL)); // JS Number min integer + object.insert("Array", array); + + QByteArray json = QJsonDocument(object).toJson(); + + QByteArray expected = + "{\n" + " \"Array\": [\n" + " 1.234567,\n" + " 1.7976931348623157e+308,\n" + // ((4.9406564584124654e-324 == 5e-324) == true) + // I can only think JavaScript has a special formatter to + // emit this value for this IEEE754 bit pattern. + " 4.9406564584124654e-324,\n" + " 2.2250738585072014e-308,\n" + " 1.7976931348623157e+308,\n" + " 2.2204460492503131e-16,\n" + " 4.9406564584124654e-324,\n" + " 0,\n" + " -2.2250738585072014e-308,\n" + " -1.7976931348623157e+308,\n" + " -2.2204460492503131e-16,\n" + " -4.9406564584124654e-324,\n" + " 0,\n" + " 9007199254740992,\n" + " -9007199254740992\n" + " ]\n" + "}\n"; + + QCOMPARE(json, expected); + + QJsonDocument doc; + doc.setObject(object); + json = doc.toJson(); + QCOMPARE(json, expected); +} + void tst_QtJson::fromJson() { { diff --git a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp index df374ffc23..c6d04e64db 100644 --- a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp +++ b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp @@ -195,11 +195,11 @@ protected: void tst_QEventLoop::processEvents() { - QSignalSpy spy1(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock())); - QSignalSpy spy2(QAbstractEventDispatcher::instance(), SIGNAL(awake())); + QSignalSpy aboutToBlockSpy(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock())); + QSignalSpy awakeSpy(QAbstractEventDispatcher::instance(), SIGNAL(awake())); - QVERIFY(spy1.isValid()); - QVERIFY(spy2.isValid()); + QVERIFY(aboutToBlockSpy.isValid()); + QVERIFY(awakeSpy.isValid()); QEventLoop eventLoop; @@ -208,8 +208,8 @@ void tst_QEventLoop::processEvents() // process posted events, QEventLoop::processEvents() should return // true QVERIFY(eventLoop.processEvents()); - QCOMPARE(spy1.count(), 0); - QCOMPARE(spy2.count(), 1); + QCOMPARE(aboutToBlockSpy.count(), 0); + QCOMPARE(awakeSpy.count(), 1); // allow any session manager to complete its handshake, so that // there are no pending events left. @@ -222,28 +222,28 @@ void tst_QEventLoop::processEvents() // no events to process, QEventLoop::processEvents() should return // false - spy1.clear(); - spy2.clear(); + aboutToBlockSpy.clear(); + awakeSpy.clear(); QVERIFY(!eventLoop.processEvents()); - QCOMPARE(spy1.count(), 0); - QCOMPARE(spy2.count(), 1); + QCOMPARE(aboutToBlockSpy.count(), 0); + QCOMPARE(awakeSpy.count(), 1); // make sure the test doesn't block forever int timerId = startTimer(100); // wait for more events to process, QEventLoop::processEvents() // should return true - spy1.clear(); - spy2.clear(); + aboutToBlockSpy.clear(); + awakeSpy.clear(); QVERIFY(eventLoop.processEvents(QEventLoop::WaitForMoreEvents)); // Verify that the eventloop has blocked and woken up. Some eventloops // may block and wake up multiple times. - QVERIFY(spy1.count() > 0); - QVERIFY(spy2.count() > 0); + QVERIFY(aboutToBlockSpy.count() > 0); + QVERIFY(awakeSpy.count() > 0); // We should get one awake for each aboutToBlock, plus one awake when // processEvents is entered. - QVERIFY(spy2.count() >= spy1.count()); + QVERIFY(awakeSpy.count() >= aboutToBlockSpy.count()); killTimer(timerId); } diff --git a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro index 5009fedc4f..23a8e6d23a 100644 --- a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro +++ b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro @@ -1,6 +1,7 @@ CONFIG += testcase parallel_test TARGET = tst_qmetatype QT = core testlib +INCLUDEPATH += $$PWD/../../../other/qvariant_common SOURCES = tst_qmetatype.cpp TESTDATA=./typeFlags.bin DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 77ea39da53..47900204e7 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -43,6 +43,8 @@ #include <QtCore> #include <QtTest/QtTest> +#include "tst_qvariant_common.h" + #ifdef Q_OS_LINUX # include <pthread.h> #endif @@ -111,6 +113,11 @@ private slots: void metaObject(); void constexprMetaTypeIds(); void constRefs(); + void convertCustomType_data(); + void convertCustomType(); + void compareCustomType_data(); + void compareCustomType(); + void customDebugStream(); }; struct Foo { int i; }; @@ -1302,15 +1309,20 @@ Q_DECLARE_METATYPE(MyObjectPtr) void tst_QMetaType::automaticTemplateRegistration() { - { - QList<int> intList; - intList << 42; - QVERIFY(QVariant::fromValue(intList).value<QList<int> >().first() == 42); - QVector<QList<int> > vectorList; - vectorList << intList; - QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<int> > >().first().first() == 42); +#define TEST_SEQUENTIAL_CONTAINER(CONTAINER, VALUE_TYPE) \ + { \ + CONTAINER<VALUE_TYPE> innerContainer; \ + innerContainer.push_back(42); \ + QVERIFY(*QVariant::fromValue(innerContainer).value<CONTAINER<VALUE_TYPE> >().begin() == 42); \ + QVector<CONTAINER<VALUE_TYPE> > outerContainer; \ + outerContainer << innerContainer; \ + QVERIFY(*QVariant::fromValue(outerContainer).value<QVector<CONTAINER<VALUE_TYPE> > >().first().begin() == 42); \ } + TEST_SEQUENTIAL_CONTAINER(QList, int) + TEST_SEQUENTIAL_CONTAINER(std::vector, int) + TEST_SEQUENTIAL_CONTAINER(std::list, int) + { QList<QByteArray> bytearrayList; bytearrayList << QByteArray("foo"); @@ -1323,14 +1335,9 @@ void tst_QMetaType::automaticTemplateRegistration() QCOMPARE(::qMetaTypeId<QVariantList>(), (int)QMetaType::QVariantList); QCOMPARE(::qMetaTypeId<QList<QVariant> >(), (int)QMetaType::QVariantList); - { - QList<QVariant> variantList; - variantList << 42; - QVERIFY(QVariant::fromValue(variantList).value<QList<QVariant> >().first() == 42); - QVector<QList<QVariant> > vectorList; - vectorList << variantList; - QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QVariant> > >().first().first() == 42); - } + TEST_SEQUENTIAL_CONTAINER(QList, QVariant) + TEST_SEQUENTIAL_CONTAINER(std::vector, QVariant) + TEST_SEQUENTIAL_CONTAINER(std::list, QVariant) { QList<QSharedPointer<QObject> > sharedPointerList; @@ -1395,6 +1402,31 @@ void tst_QMetaType::automaticTemplateRegistration() QCOMPARE(QVariant::fromValue(variantMap).value<QVariantMap>().value(QStringLiteral("4")), QVariant(2)); } { + typedef std::map<int, int> IntIntMap; + IntIntMap intIntMap; + intIntMap[4] = 2; + QCOMPARE(QVariant::fromValue(intIntMap).value<IntIntMap>()[4], 2); + } + { + typedef std::map<int, uint> StdIntUIntMap; + StdIntUIntMap intUIntMap; + intUIntMap[4] = 2; + QCOMPARE(QVariant::fromValue(intUIntMap).value<StdIntUIntMap>()[4], (uint)2); + } + { + typedef std::map<int, CustomObject*> StdMapIntCustomObject ; + StdMapIntCustomObject intComparableMap; + CustomObject *o = 0; + intComparableMap[4] = o; + QCOMPARE(QVariant::fromValue(intComparableMap).value<StdMapIntCustomObject >()[4], o); + } + { + typedef std::map<QString, QVariant> StdMapStringVariant; + StdMapStringVariant variantMap; + variantMap[QStringLiteral("4")] = 2; + QCOMPARE(QVariant::fromValue(variantMap).value<StdMapStringVariant>()[QStringLiteral("4")], QVariant(2)); + } + { typedef QPair<int, int> IntIntPair; IntIntPair intIntPair = qMakePair(4, 2); QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4); @@ -1412,6 +1444,25 @@ void tst_QMetaType::automaticTemplateRegistration() QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().second, m); } { + typedef std::pair<int, int> IntIntPair; + IntIntPair intIntPair = std::make_pair(4, 2); + QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4); + QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().second, 2); + } + { + typedef std::pair<int, uint> StdIntUIntPair; + StdIntUIntPair intUIntPair = std::make_pair<int, uint>(4, 2); + QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().first, 4); + QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().second, (uint)2); + } + { + typedef std::pair<int, CustomQObject*> StdIntComparablePair; + CustomQObject* o = 0; + StdIntComparablePair intComparablePair = std::make_pair(4, o); + QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().first, 4); + QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().second, o); + } + { typedef QHash<int, UnregisteredType> IntUnregisteredTypeHash; QVERIFY(qRegisterMetaType<IntUnregisteredTypeHash>("IntUnregisteredTypeHash") > 0); } @@ -1446,17 +1497,14 @@ void tst_QMetaType::automaticTemplateRegistration() F(uint, __VA_ARGS__) \ F(qlonglong, __VA_ARGS__) \ F(qulonglong, __VA_ARGS__) \ - F(double, __VA_ARGS__) \ F(long, __VA_ARGS__) \ F(short, __VA_ARGS__) \ F(char, __VA_ARGS__) \ F(ulong, __VA_ARGS__) \ F(ushort, __VA_ARGS__) \ F(uchar, __VA_ARGS__) \ - F(float, __VA_ARGS__) \ F(QObject*, __VA_ARGS__) \ - F(QString, __VA_ARGS__) \ - F(CustomMovable, __VA_ARGS__) + F(QString, __VA_ARGS__) #define CREATE_AND_VERIFY_CONTAINER(CONTAINER, ...) \ @@ -1774,6 +1822,366 @@ void tst_QMetaType::constRefs() #endif } +struct CustomConvertibleType +{ + explicit CustomConvertibleType(const QVariant &foo = QVariant()) : m_foo(foo) {} + virtual ~CustomConvertibleType() {} + QString toString() const { return m_foo.toString(); } + operator QPoint() const { return QPoint(12, 34); } + template<typename To> + To convert() const { return s_value.value<To>();} + template<typename To> + To convertOk(bool *ok) const { *ok = s_ok; return s_value.value<To>();} + + QVariant m_foo; + static QVariant s_value; + static bool s_ok; +}; + +bool operator<(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs) +{ return lhs.m_foo < rhs.m_foo; } +bool operator==(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs) +{ return lhs.m_foo == rhs.m_foo; } +bool operator!=(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs) +{ return !operator==(lhs, rhs); } + +QVariant CustomConvertibleType::s_value; +bool CustomConvertibleType::s_ok = true; + +struct CustomConvertibleType2 +{ + // implicit + CustomConvertibleType2(const CustomConvertibleType &t = CustomConvertibleType()) + : m_foo(t.m_foo) {} + virtual ~CustomConvertibleType2() {} + + QVariant m_foo; +}; + +struct CustomDebugStreamableType +{ + QString toString() const { return "test"; } +}; + +QDebug operator<<(QDebug dbg, const CustomDebugStreamableType&) +{ + return dbg << "string-content"; +} + +bool operator==(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs) +{ return lhs.m_foo == rhs.m_foo; } +bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs) +{ return !operator==(lhs, rhs); } + +Q_DECLARE_METATYPE(CustomConvertibleType); +Q_DECLARE_METATYPE(CustomConvertibleType2); +Q_DECLARE_METATYPE(CustomDebugStreamableType); + +template<typename T, typename U> +U convert(const T &t) +{ + return t; +} + +template<typename From> +struct ConvertFunctor +{ + CustomConvertibleType operator()(const From& f) const + { + return CustomConvertibleType(QVariant::fromValue(f)); + } +}; + +template<typename From, typename To> +bool hasRegisteredConverterFunction() +{ + return QMetaType::hasRegisteredConverterFunction<From, To>(); +} + +template<typename From, typename To> +void testCustomTypeNotYetConvertible() +{ + QVERIFY((!hasRegisteredConverterFunction<From, To>())); + QVERIFY((!QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>()))); +} + +template<typename From, typename To> +void testCustomTypeConvertible() +{ + QVERIFY((hasRegisteredConverterFunction<From, To>())); + QVERIFY((QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>()))); +} + +void customTypeNotYetConvertible() +{ + testCustomTypeNotYetConvertible<CustomConvertibleType, QString>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, bool>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, int>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, double>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, float>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QRect>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QRectF>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QPoint>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QPointF>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QSize>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QSizeF>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QLine>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QLineF>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, QChar>(); + testCustomTypeNotYetConvertible<QString, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<bool, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<int, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<double, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<float, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QRect, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QRectF, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QPoint, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QPointF, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QSize, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QSizeF, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QLine, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QLineF, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<QChar, CustomConvertibleType>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, CustomConvertibleType2>(); +} + +void registerCustomTypeConversions() +{ + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QString>(&CustomConvertibleType::convertOk<QString>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, bool>(&CustomConvertibleType::convert<bool>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, int>(&CustomConvertibleType::convertOk<int>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, double>(&CustomConvertibleType::convert<double>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, float>(&CustomConvertibleType::convertOk<float>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRect>(&CustomConvertibleType::convert<QRect>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRectF>(&CustomConvertibleType::convertOk<QRectF>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPoint>(convert<CustomConvertibleType,QPoint>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPointF>(&CustomConvertibleType::convertOk<QPointF>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSize>(&CustomConvertibleType::convert<QSize>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSizeF>(&CustomConvertibleType::convertOk<QSizeF>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLine>(&CustomConvertibleType::convert<QLine>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLineF>(&CustomConvertibleType::convertOk<QLineF>))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QChar>(&CustomConvertibleType::convert<QChar>))); + QVERIFY((QMetaType::registerConverter<QString, CustomConvertibleType>(ConvertFunctor<QString>()))); + QVERIFY((QMetaType::registerConverter<bool, CustomConvertibleType>(ConvertFunctor<bool>()))); + QVERIFY((QMetaType::registerConverter<int, CustomConvertibleType>(ConvertFunctor<int>()))); + QVERIFY((QMetaType::registerConverter<double, CustomConvertibleType>(ConvertFunctor<double>()))); + QVERIFY((QMetaType::registerConverter<float, CustomConvertibleType>(ConvertFunctor<float>()))); + QVERIFY((QMetaType::registerConverter<QRect, CustomConvertibleType>(ConvertFunctor<QRect>()))); + QVERIFY((QMetaType::registerConverter<QRectF, CustomConvertibleType>(ConvertFunctor<QRectF>()))); + QVERIFY((QMetaType::registerConverter<QPoint, CustomConvertibleType>(ConvertFunctor<QPoint>()))); + QVERIFY((QMetaType::registerConverter<QPointF, CustomConvertibleType>(ConvertFunctor<QPointF>()))); + QVERIFY((QMetaType::registerConverter<QSize, CustomConvertibleType>(ConvertFunctor<QSize>()))); + QVERIFY((QMetaType::registerConverter<QSizeF, CustomConvertibleType>(ConvertFunctor<QSizeF>()))); + QVERIFY((QMetaType::registerConverter<QLine, CustomConvertibleType>(ConvertFunctor<QLine>()))); + QVERIFY((QMetaType::registerConverter<QLineF, CustomConvertibleType>(ConvertFunctor<QLineF>()))); + QVERIFY((QMetaType::registerConverter<QChar, CustomConvertibleType>(ConvertFunctor<QChar>()))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>())); + QTest::ignoreMessage(QtWarningMsg, "Type conversion already registered from type CustomConvertibleType to type CustomConvertibleType2"); + QVERIFY((!QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>())); +} + +void tst_QMetaType::convertCustomType_data() +{ + customTypeNotYetConvertible(); + registerCustomTypeConversions(); + + QTest::addColumn<bool>("ok"); + QTest::addColumn<QString>("testQString"); + QTest::addColumn<bool>("testBool"); + QTest::addColumn<int>("testInt"); + QTest::addColumn<double>("testDouble"); + QTest::addColumn<float>("testFloat"); + QTest::addColumn<QRect>("testQRect"); + QTest::addColumn<QRectF>("testQRectF"); + QTest::addColumn<QPoint>("testQPoint"); + QTest::addColumn<QPointF>("testQPointF"); + QTest::addColumn<QSize>("testQSize"); + QTest::addColumn<QSizeF>("testQSizeF"); + QTest::addColumn<QLine>("testQLine"); + QTest::addColumn<QLineF>("testQLineF"); + QTest::addColumn<QChar>("testQChar"); + QTest::addColumn<CustomConvertibleType>("testCustom"); + + QTest::newRow("default") << true + << QString::fromLatin1("string") << true << 15 + << double(3.14) << float(3.6) << QRect(1, 2, 3, 4) + << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34) + << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8) + << QLine(3, 9, 29, 4) << QLineF(38.9, 28.9, 102.3, 0.0) + << QChar('Q') << CustomConvertibleType(QString::fromLatin1("test")); + QTest::newRow("not ok") << false + << QString::fromLatin1("string") << true << 15 + << double(3.14) << float(3.6) << QRect(1, 2, 3, 4) + << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34) + << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8) + << QLine(3, 9, 29, 4) << QLineF() + << QChar('Q') << CustomConvertibleType(42); +} + +void tst_QMetaType::convertCustomType() +{ + QFETCH(bool, ok); + CustomConvertibleType::s_ok = ok; + + CustomConvertibleType t; + QVariant v = QVariant::fromValue(t); + QFETCH(QString, testQString); + CustomConvertibleType::s_value = testQString; + QCOMPARE(v.toString(), ok ? testQString : QString()); + QCOMPARE(v.value<QString>(), ok ? testQString : QString()); + QVERIFY(CustomConvertibleType::s_value.canConvert<CustomConvertibleType>()); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toString()), testQString); + + QFETCH(bool, testBool); + CustomConvertibleType::s_value = testBool; + QCOMPARE(v.toBool(), testBool); + QCOMPARE(v.value<bool>(), testBool); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toBool()), testBool); + + QFETCH(int, testInt); + CustomConvertibleType::s_value = testInt; + QCOMPARE(v.toInt(), ok ? testInt : 0); + QCOMPARE(v.value<int>(), ok ? testInt : 0); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toInt()), testInt); + + QFETCH(double, testDouble); + CustomConvertibleType::s_value = testDouble; + QCOMPARE(v.toDouble(), testDouble); + QCOMPARE(v.value<double>(), testDouble); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toDouble()), testDouble); + + QFETCH(float, testFloat); + CustomConvertibleType::s_value = testFloat; + QCOMPARE(v.toFloat(), ok ? testFloat : 0.0); + QCOMPARE(v.value<float>(), ok ? testFloat : 0.0); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toFloat()), testFloat); + + QFETCH(QRect, testQRect); + CustomConvertibleType::s_value = testQRect; + QCOMPARE(v.toRect(), testQRect); + QCOMPARE(v.value<QRect>(), testQRect); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRect()), testQRect); + + QFETCH(QRectF, testQRectF); + CustomConvertibleType::s_value = testQRectF; + QCOMPARE(v.toRectF(), ok ? testQRectF : QRectF()); + QCOMPARE(v.value<QRectF>(), ok ? testQRectF : QRectF()); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRectF()), testQRectF); + + QFETCH(QPoint, testQPoint); + CustomConvertibleType::s_value = testQPoint; + QCOMPARE(v.toPoint(), testQPoint); + QCOMPARE(v.value<QPoint>(), testQPoint); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPoint()), testQPoint); + + QFETCH(QPointF, testQPointF); + CustomConvertibleType::s_value = testQPointF; + QCOMPARE(v.toPointF(), ok ? testQPointF : QPointF()); + QCOMPARE(v.value<QPointF>(), ok ? testQPointF : QPointF()); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPointF()), testQPointF); + + QFETCH(QSize, testQSize); + CustomConvertibleType::s_value = testQSize; + QCOMPARE(v.toSize(), testQSize); + QCOMPARE(v.value<QSize>(), testQSize); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSize()), testQSize); + + QFETCH(QSizeF, testQSizeF); + CustomConvertibleType::s_value = testQSizeF; + QCOMPARE(v.toSizeF(), ok ? testQSizeF : QSizeF()); + QCOMPARE(v.value<QSizeF>(), ok ? testQSizeF : QSizeF()); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSizeF()), testQSizeF); + + QFETCH(QLine, testQLine); + CustomConvertibleType::s_value = testQLine; + QCOMPARE(v.toLine(), testQLine); + QCOMPARE(v.value<QLine>(), testQLine); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLine()), testQLine); + + QFETCH(QLineF, testQLineF); + CustomConvertibleType::s_value = testQLineF; + QCOMPARE(v.toLineF(), ok ? testQLineF : QLineF()); + QCOMPARE(v.value<QLineF>(), ok ? testQLineF : QLineF()); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLineF()), testQLineF); + + QFETCH(QChar, testQChar); + CustomConvertibleType::s_value = testQChar; + QCOMPARE(v.toChar(), testQChar); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toChar()), testQChar); + + QFETCH(CustomConvertibleType, testCustom); + v = QVariant::fromValue(testCustom); + QVERIFY(v.canConvert(::qMetaTypeId<CustomConvertibleType2>())); + QCOMPARE(v.value<CustomConvertibleType2>().m_foo, testCustom.m_foo); +} + +void tst_QMetaType::compareCustomType_data() +{ + QMetaType::registerComparators<CustomConvertibleType>(); + + QTest::addColumn<QVariantList>("unsorted"); + QTest::addColumn<QVariantList>("sorted"); + + QTest::newRow("int") << (QVariantList() << 37 << 458 << 1 << 243 << -4 << 383) + << (QVariantList() << -4 << 1 << 37 << 243 << 383 << 458); + + QTest::newRow("dobule") << (QVariantList() << 4934.93 << 0.0 << 302.39 << -39.0) + << (QVariantList() << -39.0 << 0.0 << 302.39 << 4934.93); + + QTest::newRow("QString") << (QVariantList() << "Hello" << "World" << "this" << "is" << "a" << "test") + << (QVariantList() << "a" << "Hello" << "is" << "test" << "this" << "World"); + + QTest::newRow("QTime") << (QVariantList() << QTime(14, 39) << QTime(0, 0) << QTime(18, 18) << QTime(9, 27)) + << (QVariantList() << QTime(0, 0) << QTime(9, 27) << QTime(14, 39) << QTime(18, 18)); + + QTest::newRow("QDate") << (QVariantList() << QDate(2013, 3, 23) << QDate(1900, 12, 1) << QDate(2001, 2, 2) << QDate(1982, 12, 16)) + << (QVariantList() << QDate(1900, 12, 1) << QDate(1982, 12, 16) << QDate(2001, 2, 2) << QDate(2013, 3, 23)); + + QTest::newRow("mixed") << (QVariantList() << "Hello" << "World" << QChar('a') << 38 << QChar('z') << -39 << 4.6) + << (QVariantList() << -39 << 4.6 << 38 << QChar('a') << "Hello" << "World" << QChar('z')); + + QTest::newRow("custom") << (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(100)) << QVariant::fromValue(CustomConvertibleType(50))) + << (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(50)) << QVariant::fromValue(CustomConvertibleType(100))); +} + +void tst_QMetaType::compareCustomType() +{ + QFETCH(QVariantList, unsorted); + QFETCH(QVariantList, sorted); + qSort(unsorted); + QCOMPARE(unsorted, sorted); +} + +struct MessageHandlerCustom : public MessageHandler +{ + MessageHandlerCustom(const int typeId) + : MessageHandler(typeId, handler) + {} + static void handler(QtMsgType, const QMessageLogContext &, const QString &msg) + { + QCOMPARE(msg.trimmed(), expectedMessage.trimmed()); + } + static QString expectedMessage; +}; + +QString MessageHandlerCustom::expectedMessage; + +void tst_QMetaType::customDebugStream() +{ + MessageHandlerCustom handler(::qMetaTypeId<CustomDebugStreamableType>()); + QVariant v1 = QVariant::fromValue(CustomDebugStreamableType()); + handler.expectedMessage = "QVariant(CustomDebugStreamableType, )"; + qDebug() << v1; + + QMetaType::registerConverter<CustomDebugStreamableType, QString>(&CustomDebugStreamableType::toString); + handler.expectedMessage = "QVariant(CustomDebugStreamableType, \"test\")"; + qDebug() << v1; + + QMetaType::registerDebugStreamOperator<CustomDebugStreamableType>(); + handler.expectedMessage = "QVariant(CustomDebugStreamableType, string-content)"; + qDebug() << v1; +} + // Compile-time test, it should be possible to register function pointer types class Undefined; @@ -1781,11 +2189,15 @@ typedef Undefined (*UndefinedFunction0)(); typedef Undefined (*UndefinedFunction1)(Undefined); typedef Undefined (*UndefinedFunction2)(Undefined, Undefined); typedef Undefined (*UndefinedFunction3)(Undefined, Undefined, Undefined); +typedef Undefined (*UndefinedFunction4)(Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined); Q_DECLARE_METATYPE(UndefinedFunction0); Q_DECLARE_METATYPE(UndefinedFunction1); Q_DECLARE_METATYPE(UndefinedFunction2); Q_DECLARE_METATYPE(UndefinedFunction3); +#ifdef Q_COMPILER_VARIADIC_TEMPLATES +Q_DECLARE_METATYPE(UndefinedFunction4); +#endif QTEST_MAIN(tst_QMetaType) #include "tst_qmetatype.moc" diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 1cdf39018b..8d1ea3b510 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -146,6 +146,7 @@ private slots: void connectFunctorOverloads(); void disconnectDoesNotLeakFunctor(); void connectBase(); + void qmlConnect(); }; struct QObjectCreatedOnShutdown @@ -5879,6 +5880,56 @@ void tst_QObject::connectBase() QCOMPARE( r1.count_slot3, 1 ); } +struct QmlReceiver : public QtPrivate::QSlotObjectBase +{ + int callCount; + void *magic; + + QmlReceiver() + : QtPrivate::QSlotObjectBase(&impl) + , callCount(0) + , magic(0) + {} + + static void impl(int which, QSlotObjectBase *this_, QObject *, void **metaArgs, bool *ret) + { + switch (which) { + case Destroy: delete static_cast<QmlReceiver*>(this_); return; + case Call: static_cast<QmlReceiver*>(this_)->callCount++; return; + case Compare: *ret = static_cast<QmlReceiver*>(this_)->magic == metaArgs[0]; return; + case NumOperations: break; + } + } +}; + +void tst_QObject::qmlConnect() +{ +#ifdef QT_BUILD_INTERNAL + SenderObject sender; + QmlReceiver *receiver = new QmlReceiver; + receiver->magic = receiver; + receiver->ref(); + + QVERIFY(QObjectPrivate::connect(&sender, sender.metaObject()->indexOfSignal("signal1()"), + receiver, Qt::AutoConnection)); + + QCOMPARE(receiver->callCount, 0); + sender.emitSignal1(); + QCOMPARE(receiver->callCount, 1); + + void *a[] = { + receiver + }; + QVERIFY(QObjectPrivate::disconnect(&sender, sender.metaObject()->indexOfSignal("signal1()"), reinterpret_cast<void**>(&a))); + + sender.emitSignal1(); + QCOMPARE(receiver->callCount, 1); + + receiver->destroyIfLastRef(); +#else + QSKIP("Needs QT_BUILD_INTERNAL"); +#endif +} QTEST_MAIN(tst_QObject) #include "tst_qobject.moc" diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 4d862f4fc5..dab40db0ec 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -242,6 +242,9 @@ private slots: void saveNewBuiltinWithOldStream(); void implicitConstruction(); + + void iterateContainerElements(); + void pairElements(); private: void dataStream_data(QDataStream::Version version); void loadQVariantFromDataStream(QDataStream::Version version); @@ -990,8 +993,8 @@ void tst_QVariant::toString_data() QTest::newRow( "float" ) << QVariant( 123.456f ) << QString( "123.456" ); QTest::newRow( "bool" ) << QVariant( true ) << QString( "true" ); QTest::newRow( "qdate" ) << QVariant( QDate( 2002, 1, 1 ) ) << QString( "2002-01-01" ); - QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QString( "12:34:56" ); - QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 1, 1 ), QTime( 12, 34, 56 ) ) ) << QString( "2002-01-01T12:34:56" ); + QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QString( "12:34:56.000" ); + QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 1, 1 ), QTime( 12, 34, 56 ) ) ) << QString( "2002-01-01T12:34:56.000" ); QTest::newRow( "llong" ) << QVariant( (qlonglong)Q_INT64_C(123456789012) ) << QString( "123456789012" ); QTest::newRow("QJsonValue") << QVariant(QJsonValue(QString("hello"))) << QString("hello"); @@ -3392,5 +3395,312 @@ void tst_QVariant::saveNewBuiltinWithOldStream() QCOMPARE(int(data.constData()[3]), 0); } +template<typename Container, typename Value_Type = typename Container::value_type> +struct ContainerAPI +{ + static void insert(Container &container, typename Container::value_type value) + { + container.push_back(value); + } + + static bool compare(const QVariant &variant, typename Container::value_type value) + { + return variant.value<typename Container::value_type>() == value; + } + static bool compare(QVariant variant, const QVariant &value) + { + return variant == value; + } +}; + +template<typename Container> +struct ContainerAPI<Container, QVariant> +{ + static void insert(Container &container, int value) + { + container.push_back(QVariant::fromValue(value)); + } + + static bool compare(QVariant variant, const QVariant &value) + { + return variant == value; + } +}; + +template<typename Container> +struct ContainerAPI<Container, QString> +{ + static void insert(Container &container, int value) + { + container.push_back(QString::number(value)); + } + + static bool compare(const QVariant &variant, QString value) + { + return variant.value<QString>() == value; + } + static bool compare(QVariant variant, const QVariant &value) + { + return variant == value; + } +}; + +// We have no built-in defines to check the stdlib features. +// #define TEST_FORWARD_LIST + +#ifdef TEST_FORWARD_LIST +#include <forward_list> +Q_DECLARE_METATYPE(std::forward_list<int>) +Q_DECLARE_METATYPE(std::forward_list<QVariant>) +Q_DECLARE_METATYPE(std::forward_list<QString>) + +template<typename Value_Type> +struct ContainerAPI<std::forward_list<Value_Type> > +{ + static void insert(std::forward_list<Value_Type> &container, Value_Type value) + { + container.push_front(value); + } + static bool compare(const QVariant &variant, Value_Type value) + { + return variant.value<Value_Type>() == value; + } + static bool compare(QVariant variant, const QVariant &value) + { + return variant == value; + } +}; + +template<> +struct ContainerAPI<std::forward_list<QVariant> > +{ + static void insert(std::forward_list<QVariant> &container, int value) + { + container.push_front(QVariant::fromValue(value)); + } + + static bool compare(QVariant variant, const QVariant &value) + { + return variant == value; + } +}; + +template<> +struct ContainerAPI<std::forward_list<QString> > +{ + static void insert(std::forward_list<QString> &container, int value) + { + container.push_front(QString::number(value)); + } + static bool compare(const QVariant &variant, QString value) + { + return variant.value<QString>() == value; + } + static bool compare(QVariant variant, const QVariant &value) + { + return variant == value; + } +}; +#endif + +template<typename Container> +struct KeyGetter +{ + static const typename Container::key_type & get(const typename Container::const_iterator &it) + { + return it.key(); + } + static const typename Container::mapped_type & value(const typename Container::const_iterator &it) + { + return it.value(); + } +}; + +template<typename T, typename U> +struct KeyGetter<std::map<T, U> > +{ + static const T & get(const typename std::map<T, U>::const_iterator &it) + { + return it->first; + } + static const U & value(const typename std::map<T, U>::const_iterator &it) + { + return it->second; + } +}; + + +// We have no built-in defines to check the stdlib features. +// #define TEST_UNORDERED_MAP + +#ifdef TEST_UNORDERED_MAP +#include <unordered_map> +typedef std::unordered_map<int, bool> StdUnorderedMap_int_bool; +Q_DECLARE_METATYPE(StdUnorderedMap_int_bool) + +template<typename T, typename U> +struct KeyGetter<std::unordered_map<T, U> > +{ + static const T & get(const typename std::unordered_map<T, U>::const_iterator &it) + { + return it->first; + } + static const U & value(const typename std::unordered_map<T, U>::const_iterator &it) + { + return it->second; + } +}; +#endif + +void tst_QVariant::iterateContainerElements() +{ +#ifdef Q_COMPILER_RANGE_FOR + +#define TEST_RANGE_FOR(CONTAINER, VALUE_TYPE) \ + numSeen = 0; \ + containerIter = intList.begin(); \ + for (QVariant v : listIter) { \ + QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, *containerIter)); \ + QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, varList.at(numSeen))); \ + ++containerIter; \ + ++numSeen; \ + } \ + QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); + +#else + +#define TEST_RANGE_FOR(CONTAINER, VALUE_TYPE) + +#endif + +#define TEST_SEQUENTIAL_ITERATION(CONTAINER, VALUE_TYPE) \ + { \ + int numSeen = 0; \ + CONTAINER<VALUE_TYPE > intList; \ + ContainerAPI<CONTAINER<VALUE_TYPE > >::insert(intList, 1); \ + ContainerAPI<CONTAINER<VALUE_TYPE > >::insert(intList, 2); \ + ContainerAPI<CONTAINER<VALUE_TYPE > >::insert(intList, 3); \ + \ + QVariant listVariant = QVariant::fromValue(intList); \ + QVERIFY(listVariant.canConvert<QVariantList>()); \ + QVariantList varList = listVariant.value<QVariantList>(); \ + QCOMPARE(varList.size(), (int)std::distance(intList.begin(), intList.end())); \ + QSequentialIterable listIter = listVariant.value<QSequentialIterable>(); \ + QCOMPARE(varList.size(), listIter.size()); \ + \ + CONTAINER<VALUE_TYPE >::iterator containerIter = intList.begin(); \ + const CONTAINER<VALUE_TYPE >::iterator containerEnd = intList.end(); \ + for (int i = 0; i < listIter.size(); ++i, ++containerIter, ++numSeen) \ + { \ + QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(listIter.at(i), *containerIter)); \ + QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(listIter.at(i), varList.at(i))); \ + } \ + QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \ + QCOMPARE(containerIter, containerEnd); \ + \ + containerIter = intList.begin(); \ + numSeen = 0; \ + Q_FOREACH (const QVariant &v, listIter) { \ + QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, *containerIter)); \ + QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, varList.at(numSeen))); \ + ++containerIter; \ + ++numSeen; \ + } \ + QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \ + TEST_RANGE_FOR(CONTAINER, VALUE_TYPE) \ + } + + TEST_SEQUENTIAL_ITERATION(QVector, int) + TEST_SEQUENTIAL_ITERATION(QVector, QVariant) + TEST_SEQUENTIAL_ITERATION(QVector, QString) + TEST_SEQUENTIAL_ITERATION(QQueue, int) + TEST_SEQUENTIAL_ITERATION(QQueue, QVariant) + TEST_SEQUENTIAL_ITERATION(QQueue, QString) + TEST_SEQUENTIAL_ITERATION(QList, int) + TEST_SEQUENTIAL_ITERATION(QList, QVariant) + TEST_SEQUENTIAL_ITERATION(QList, QString) + TEST_SEQUENTIAL_ITERATION(QStack, int) + TEST_SEQUENTIAL_ITERATION(QStack, QVariant) + TEST_SEQUENTIAL_ITERATION(QStack, QString) + TEST_SEQUENTIAL_ITERATION(std::vector, int) + TEST_SEQUENTIAL_ITERATION(std::vector, QVariant) + TEST_SEQUENTIAL_ITERATION(std::vector, QString) + TEST_SEQUENTIAL_ITERATION(std::list, int) + TEST_SEQUENTIAL_ITERATION(std::list, QVariant) + TEST_SEQUENTIAL_ITERATION(std::list, QString) + +#ifdef TEST_FORWARD_LIST + qRegisterSequentialConverter<std::forward_list<int> >(); + qRegisterSequentialConverter<std::forward_list<QVariant> >(); + qRegisterSequentialConverter<std::forward_list<QString> >(); + TEST_SEQUENTIAL_ITERATION(std::forward_list, int) + TEST_SEQUENTIAL_ITERATION(std::forward_list, QVariant) + TEST_SEQUENTIAL_ITERATION(std::forward_list, QString) +#endif + +#define TEST_ASSOCIATIVE_ITERATION(CONTAINER, KEY_TYPE, MAPPED_TYPE) \ + { \ + int numSeen = 0; \ + CONTAINER<KEY_TYPE, MAPPED_TYPE> mapping; \ + mapping[5] = true; \ + mapping[15] = false; \ + \ + QVariant mappingVariant = QVariant::fromValue(mapping); \ + QVariantMap varMap = mappingVariant.value<QVariantMap>(); \ + QVariantMap varHash = mappingVariant.value<QVariantMap>(); \ + QAssociativeIterable mappingIter = mappingVariant.value<QAssociativeIterable>(); \ + \ + CONTAINER<KEY_TYPE, MAPPED_TYPE>::const_iterator containerIter = mapping.begin(); \ + const CONTAINER<KEY_TYPE, MAPPED_TYPE>::const_iterator containerEnd = mapping.end(); \ + for ( ; containerIter != containerEnd; ++containerIter, ++numSeen) \ + { \ + MAPPED_TYPE expected = KeyGetter<CONTAINER<KEY_TYPE, MAPPED_TYPE> >::value(containerIter); \ + KEY_TYPE key = KeyGetter<CONTAINER<KEY_TYPE, MAPPED_TYPE> >::get(containerIter); \ + MAPPED_TYPE actual = mappingIter.value(key).value<MAPPED_TYPE >(); \ + QCOMPARE(varMap.value(QString::number(key)).value<MAPPED_TYPE>(), expected); \ + QCOMPARE(varHash.value(QString::number(key)).value<MAPPED_TYPE>(), expected); \ + QCOMPARE(actual, expected); \ + } \ + QCOMPARE(numSeen, (int)std::distance(mapping.begin(), mapping.end())); \ + QCOMPARE(containerIter, containerEnd); \ + \ + } + + TEST_ASSOCIATIVE_ITERATION(QHash, int, bool) + TEST_ASSOCIATIVE_ITERATION(QMap, int, bool) + TEST_ASSOCIATIVE_ITERATION(std::map, int, bool) +#ifdef TEST_UNORDERED_MAP + qRegisterAssociativeConverter<StdUnorderedMap_int_bool>(); + TEST_ASSOCIATIVE_ITERATION(std::unordered_map, int, bool) +#endif +} + +void tst_QVariant::pairElements() +{ + typedef QPair<QVariant, QVariant> QVariantPair; + +#define TEST_PAIR_ELEMENT_ACCESS(PAIR, T1, T2, VALUE1, VALUE2) \ + { \ + PAIR<T1, T2> p(VALUE1, VALUE2); \ + QVariant v = QVariant::fromValue(p); \ + \ + QVERIFY(v.canConvert<QVariantPair>()); \ + QVariantPair pi = v.value<QVariantPair>(); \ + QCOMPARE(pi.first, QVariant::fromValue(VALUE1)); \ + QCOMPARE(pi.second, QVariant::fromValue(VALUE2)); \ + } + + TEST_PAIR_ELEMENT_ACCESS(QPair, int, int, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(std::pair, int, int, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(QPair, QString, QString, QStringLiteral("one"), QStringLiteral("two")) + TEST_PAIR_ELEMENT_ACCESS(std::pair, QString, QString, QStringLiteral("one"), QStringLiteral("two")) + TEST_PAIR_ELEMENT_ACCESS(QPair, QVariant, QVariant, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(std::pair, QVariant, QVariant, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(QPair, QVariant, int, 41, 15) + TEST_PAIR_ELEMENT_ACCESS(std::pair, QVariant, int, 34, 65) + TEST_PAIR_ELEMENT_ACCESS(QPair, int, QVariant, 24, 25) + TEST_PAIR_ELEMENT_ACCESS(std::pair, int, QVariant, 44, 15) +} + QTEST_MAIN(tst_QVariant) #include "tst_qvariant.moc" diff --git a/mkspecs/macx-clang-libc++-32/qplatformdefs.h b/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp index 2c3a8b1c09..d5c933e3af 100644 --- a/mkspecs/macx-clang-libc++-32/qplatformdefs.h +++ b/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Intel Corporation ** Contact: http://www.qt-project.org/legal ** -** This file is part of the qmake spec of the Qt Toolkit. +** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,5 +39,11 @@ ** ****************************************************************************/ -#include "../common/mac/qplatformdefs.h" +#include <QtCore/qplugin.h> +#if QT_POINTER_SIZE == 8 +QT_PLUGIN_METADATA_SECTION void *const pluginSection = (void*)(0xc0ffeec0ffeeL); +#else +QT_PLUGIN_METADATA_SECTION void *const pluginSection = (void*)0xc0ffee; +#endif +QT_PLUGIN_METADATA_SECTION const char message[] = "QTMETADATA"; diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl b/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl new file mode 100755 index 0000000000..ec0dd980a9 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl @@ -0,0 +1,209 @@ +#!/usr/bin/perl +############################################################################# +## +## Copyright (C) 2013 Intel Corporation. +## Contact: http://www.qt-project.org/legal +## +## This file is the build configuration utility of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and Digia. For licensing terms and +## conditions see http://qt.digia.com/licensing. For further information +## use the contact form at http://qt.digia.com/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Digia gives you certain additional +## rights. These rights are described in the Digia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3.0 as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU General Public License version 3.0 requirements will be +## met: http://www.gnu.org/copyleft/gpl.html. +## +## +## $QT_END_LICENSE$ +## +############################################################################# + +use strict; +use constant FAT_MAGIC => 0xcafebabe; +use constant MH_MAGIC => 0xfeedface; +use constant MH_MAGIC_64 => 0xfeedfacf; +use constant CPU_TYPE_X86 => 7; +use constant CPU_TYPE_X86_64 => CPU_TYPE_X86 | 0x01000000; +use constant CPU_SUBTYPE_I386_ALL => 3; +use constant MH_DYLIB => 6; +use constant LC_SEGMENT => 1; +use constant LC_SEGMENT_64 => 0x19; + +my $good = pack("(L7 L2 Z16 L8 Z16 Z16 L9 . L)>", + MH_MAGIC, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL, MH_DYLIB, # 0-3 + 1, # 4: ncmds + 4 * (37 - 6), # 5: sizeofcmds + 0, # 6: flags + + LC_SEGMENT, # 7: cmd + 4 * (37 - 6), # 8: cmdsize + '__TEXT', # 9-12: segname + 0, # 13: vmaddr + 0x1000, # 14: vmsize + 0, # 15: fileoff + 0x204, # 16: filesize + 7, # 17: maxprot (rwx) + 5, # 18: initprot (r-x) + 1, # 19: nsects + 0, # 20: flags + + 'qtmetadata', # 21-24: sectname + '__TEXT', # 25-28: segname + 0x200, # 29: addr + 4, # 30: size + 0x200, # 31: offset + 2, # 32: align (2^2) + 0, # 33: reloff + 0, # 34: nreloc + 0, # 35: flags + 0, # 36: reserved1 + 0, # 37: reserved2 + + 0x200, + 0xc0ffee # data +); + +my $good64 = pack("(L8 L2 Z16 Q4 L4 Z16 Z16 Q2 L8 . Q)>", + MH_MAGIC_64, CPU_TYPE_X86_64, CPU_SUBTYPE_I386_ALL, MH_DYLIB, # 0-3 + 1, # 4: ncmds + 4 * (45 - 7), # 5: sizeofcmds + 0, # 6: flags + 0, # 7: reserved + + LC_SEGMENT_64, # 8: cmd + 4 * (45 - 7), # 9: cmdsize + '__TEXT', # 10-13: segname + 0, # 14-15: vmaddr + 0x1000, # 16-17: vmsize + 0, # 18-19: fileoff + 0x208, # 20-21: filesize + 7, # 22: maxprot (rwx) + 5, # 23: initprot (r-x) + 1, # 24: nsects + 0, # 25: flags + + 'qtmetadata', # 26-29: sectname + '__TEXT', # 30-33: segname + 0x200, # 34-35: addr + 4, # 36-37: size + 0x200, # 38: offset + 3, # 39: align (2^3) + 0, # 40: reloff + 0, # 41: nreloc + 0, # 42: flags + 0, # 43: reserved1 + 0, # 44: reserved2 + 0, # 45: reserved3 + + 0x200, + 0xc0ffeec0ffee # data +); + +my $fat = pack("L>*", + FAT_MAGIC, # 1: magic + 2, # 2: nfat_arch + + CPU_TYPE_X86, # 3: cputype + CPU_SUBTYPE_I386_ALL, # 4: cpusubtype + 0x1000, # 5: offset + 0x1000, # 6: size + 12, # 7: align (2^12) + + CPU_TYPE_X86_64, # 8: cputype + CPU_SUBTYPE_I386_ALL, # 9: cpusubtype + 0x2000, # 10: offset + 0x1000, # 11: size + 12, # 12: align (2^12) +); + +my $buffer; + +our $badcount = 1; +sub generate($) { + open OUT, ">", "bad$badcount.dylib" or die("Could not open file bad$badcount.dylib: $!\n"); + binmode OUT; + print OUT $_[0]; + close OUT; + ++$badcount; +} + +# Bad file 1-2 +# Except that the cmdsize fields are null +$buffer = $good; +vec($buffer, 5, 32) = 0; +generate $buffer; + +$buffer = $good; +vec($buffer, 8, 32) = 0; +generate $buffer; + +# Bad file 3-4: same as above but 64-bit +$buffer = $good64; +vec($buffer, 5, 32) = 0; +generate $buffer; + +$buffer = $good64; +vec($buffer, 9, 32) = 0; +generate $buffer; + +# Bad file 5-8: same as 1-4, but set cmdsize to bigger than file +$buffer = $good; +vec($buffer, 5, 32) = 0x1000; +generate $buffer; + +$buffer = $good; +vec($buffer, 8, 32) = 0x1000; +generate $buffer; + +$buffer = $good64; +vec($buffer, 5, 32) = 0x1000; +generate $buffer; + +$buffer = $good64; +vec($buffer, 9, 32) = 0x1000; +generate $buffer; + +# Bad file 9-10: overflow size+offset +$buffer = $good; +vec($buffer, 30, 32) = 0xffffffe0; +generate $buffer; + +$buffer = $good64; +vec($buffer, 36, 32) = 0xffffffff; +vec($buffer, 37, 32) = 0xffffffe0; +generate $buffer; + +# Bad file 11: FAT binary with just the header +generate $fat; + +# Bad file 12: FAT binary where the Mach contents don't match the FAT directory +$buffer = pack("a4096 a4096 a4096", $fat, $good64, $good); +generate $buffer; + +# Bad file 13: FAT binary with overflowing size +$buffer = pack("a4096 a4096 a4096", $fat, $good, $good64); +vec($buffer, 5, 32) = 0xfffffffe0; +vec($buffer, 10, 32) = 0xfffffffe0; +generate $buffer; diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro new file mode 100644 index 0000000000..7acddc22ce --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro @@ -0,0 +1,56 @@ +TEMPLATE = aux +OTHER_FILES += \ + ppcconverter.pl \ + generate-bad.pl + +i386.target = good.i386.dylib +i386.commands = $(CXX) $(CXXFLAGS) -shared -arch i386 -o $@ -I$$[QT_INSTALL_HEADERS/get] $< +i386.depends += $$PWD/../fakeplugin.cpp +x86_64.target = good.x86_64.dylib +x86_64.commands = $(CXX) $(CXXFLAGS) -shared -arch x86_64 -o $@ -I$$[QT_INSTALL_HEADERS/get] $< +x86_64.depends += $$PWD/../fakeplugin.cpp + +# Current Mac OS X toolchains have no compiler for PPC anymore +# So we fake it by converting an x86-64 binary to (little-endian!) PPC64 +ppc64.target = good.ppc64.dylib +ppc64.commands = $$PWD/ppcconverter.pl $< $@ +ppc64.depends = x86_64 $$PWD/ppcconverter.pl + +# Generate a fat binary with three architectures +fat_all.target = good.fat.all.dylib +fat_all.commands = lipo -create -output $@ \ + -arch ppc64 $$ppc64.target \ + -arch i386 $$i386.target \ + -arch x86_64 $$x86_64.target +fat_all.depends += i386 x86_64 ppc64 + +fat_no_i386.target = good.fat.no-i386.dylib +fat_no_i386.commands = lipo -create -output $@ -arch x86_64 $$x86_64.target -arch ppc64 $$ppc64.target +fat_no_i386.depends += x86_64 ppc64 + +fat_no_x86_64.target = good.fat.no-x86_64.dylib +fat_no_x86_64.commands = lipo -create -output $@ -arch i386 $$i386.target -arch ppc64 $$ppc64.target +fat_no_x86_64.depends += i386 ppc64 + +fat_stub_i386.target = good.fat.stub-i386.dylib +fat_stub_i386.commands = lipo -create -output $@ -arch ppc64 $$ppc64.target -arch_blank i386 +fat_stub_i386.depends += x86_64 ppc64 + +fat_stub_x86_64.target = good.fat.stub-x86_64.dylib +fat_stub_x86_64.commands = lipo -create -output $@ -arch ppc64 $$ppc64.target -arch_blank x86_64 +fat_stub_x86_64.depends += i386 ppc64 + +bad.commands = $$PWD/generate-bad.pl +bad.depends += $$PWD/generate-bad.pl + +MYTARGETS = $$fat_all.depends fat_all fat_no_x86_64 fat_no_i386 \ + fat_stub_i386 fat_stub_x86_64 bad +all.depends += $$MYTARGETS +QMAKE_EXTRA_TARGETS += $$MYTARGETS all + +QMAKE_CLEAN += $$i386.target $$x86_64.target $$ppc64.target $$fat_all.target \ + $$fat_no_i386.target $$fat_no_x86_64.target \ + $$fat_stub_i386.target $$fat_stub_x86_64.target \ + "bad*.dylib" + + diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl b/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl new file mode 100755 index 0000000000..86943161b7 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl @@ -0,0 +1,112 @@ +#!/usr/bin/perl +############################################################################# +## +## Copyright (C) 2013 Intel Corporation. +## Contact: http://www.qt-project.org/legal +## +## This file is the build configuration utility of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and Digia. For licensing terms and +## conditions see http://qt.digia.com/licensing. For further information +## use the contact form at http://qt.digia.com/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Digia gives you certain additional +## rights. These rights are described in the Digia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3.0 as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU General Public License version 3.0 requirements will be +## met: http://www.gnu.org/copyleft/gpl.html. +## +## +## $QT_END_LICENSE$ +## +############################################################################# + +# Changes the Mach-O file type header to PowerPC. +# +# The header is (from mach-o/loader.h): +# struct mach_header { +# uint32_t magic; /* mach magic number identifier */ +# cpu_type_t cputype; /* cpu specifier */ +# cpu_subtype_t cpusubtype; /* machine specifier */ +# uint32_t filetype; /* type of file */ +# uint32_t ncmds; /* number of load commands */ +# uint32_t sizeofcmds; /* the size of all the load commands */ +# uint32_t flags; /* flags */ +# }; +# +# The 64-bit header is identical in the first three fields, except for a different +# magic number. We will not touch the magic number, we'll just reset the cputype +# field to the PowerPC type and the subtype field to zero. +# +# We will not change the file's endianness. That means we might create a little-endian +# PowerPC binary, which could not be run in real life. +# +# We will also not change the 64-bit ABI flag, which is found in the cputype's high +# byte. That means we'll create a PPC64 binary if fed a 64-bit input. +# +use strict; +use constant MH_MAGIC => 0xfeedface; +use constant MH_CIGAM => 0xcefaedfe; +use constant MH_MAGIC_64 => 0xfeedfacf; +use constant MH_CIGAM_64 => 0xcffaedfe; +use constant CPU_TYPE_POWERPC => 18; +use constant CPU_SUBTYPE_POWERPC_ALL => 0; + +my $infile = shift @ARGV or die("Missing input filename"); +my $outfile = shift @ARGV or die("Missing output filename"); + +open IN, "<$infile" or die("Can't open $infile for reading: $!\n"); +open OUT, ">$outfile" or die("Can't open $outfile for writing: $!\n"); + +binmode IN; +binmode OUT; + +# Read the first 12 bytes, which includes the interesting fields of the header +my $buffer; +read(IN, $buffer, 12); + +my $magic = vec($buffer, 0, 32); +if ($magic == MH_MAGIC || $magic == MH_MAGIC_64) { + # Big endian + # The low byte of cputype is at offset 7 + vec($buffer, 7, 8) = CPU_TYPE_POWERPC; +} elsif ($magic == MH_CIGAM || $magic == MH_CIGAM_64) { + # Little endian + # The low byte of cpytype is at offset 4 + vec($buffer, 4, 8) = CPU_TYPE_POWERPC; +} else { + $magic = ''; + $magic .= sprintf("%02X ", $_) for unpack("CCCC", $buffer); + die("Invalid input. Unknown magic $magic\n"); +} +vec($buffer, 2, 32) = CPU_SUBTYPE_POWERPC_ALL; + +print OUT $buffer; + +# Copy the rest +while (!eof(IN)) { + read(IN, $buffer, 4096) and + print OUT $buffer or + die("Problem copying: $!\n"); +} +close(IN); +close(OUT); diff --git a/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro b/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro index 0cba19887e..8d117793bf 100644 --- a/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro +++ b/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro @@ -5,6 +5,7 @@ SUBDIRS = lib \ theplugin \ tst !win32: !mac: SUBDIRS += almostplugin +macx-*: SUBDIRS += machtest TARGET = tst_qpluginloader # no special install rule for subdir diff --git a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro b/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro index a7a9661a54..3894c90ae3 100644 --- a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro +++ b/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro @@ -2,7 +2,8 @@ CONFIG += testcase CONFIG += parallel_test TARGET = ../tst_qpluginloader QT = core testlib -SOURCES = ../tst_qpluginloader.cpp +contains(QT_CONFIG, private_tests): QT += core-private +SOURCES = ../tst_qpluginloader.cpp ../fakeplugin.cpp HEADERS = ../theplugin/plugininterface.h CONFIG -= app_bundle @@ -14,5 +15,5 @@ win32 { } } -TESTDATA += ../elftest +TESTDATA += ../elftest ../machtest DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp index cef4f53101..351e3a23e0 100644 --- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp @@ -44,6 +44,10 @@ #include <qpluginloader.h> #include "theplugin/plugininterface.h" +#if defined(QT_BUILD_INTERNAL) && defined(Q_OF_MACH_O) +# include <QtCore/private/qmachparser_p.h> +#endif + // Helper macros to let us know if some suffixes are valid #define bundle_VALID false #define dylib_VALID false @@ -118,6 +122,8 @@ private slots: void deleteinstanceOnUnload(); void loadDebugObj(); void loadCorruptElf(); + void loadMachO_data(); + void loadMachO(); #if defined (Q_OS_UNIX) void loadGarbage(); #endif @@ -311,6 +317,78 @@ void tst_QPluginLoader::loadCorruptElf() #endif } +void tst_QPluginLoader::loadMachO_data() +{ +#ifdef Q_OF_MACH_O + QTest::addColumn<int>("parseResult"); + + QTest::newRow("/dev/null") << int(QMachOParser::NotSuitable); + QTest::newRow("elftest/debugobj.so") << int(QMachOParser::NotSuitable); + QTest::newRow("tst_qpluginloader.cpp") << int(QMachOParser::NotSuitable); + QTest::newRow("tst_qpluginloader") << int(QMachOParser::NotSuitable); + +# ifdef Q_PROCESSOR_X86_64 + QTest::newRow("machtest/good.x86_64.dylib") << int(QMachOParser::QtMetaDataSection); + QTest::newRow("machtest/good.i386.dylib") << int(QMachOParser::NotSuitable); + QTest::newRow("machtest/good.fat.no-x86_64.dylib") << int(QMachOParser::NotSuitable); + QTest::newRow("machtest/good.fat.no-i386.dylib") << int(QMachOParser::QtMetaDataSection); +# elif defined(Q_PROCESSOR_X86_32) + QTest::newRow("machtest/good.i386.dylib") << int(QMachOParser::QtMetaDataSection); + QTest::newRow("machtest/good.x86_64.dylib") << int(QMachOParser::NotSuitable); + QTest::newRow("machtest/good.fat.no-i386.dylib") << int(QMachOParser::NotSuitable); + QTest::newRow("machtest/good.fat.no-x86_64.dylib") << int(QMachOParser::QtMetaDataSection); +# endif +# ifndef Q_PROCESSOR_POWER_64 + QTest::newRow("machtest/good.ppc64.dylib") << int(QMachOParser::NotSuitable); +# endif + + QTest::newRow("machtest/good.fat.all.dylib") << int(QMachOParser::QtMetaDataSection); + QTest::newRow("machtest/good.fat.stub-x86_64.dylib") << int(QMachOParser::NotSuitable); + QTest::newRow("machtest/good.fat.stub-i386.dylib") << int(QMachOParser::NotSuitable); + + QDir d(QFINDTESTDATA("machtest")); + QStringList badlist = d.entryList(QStringList() << "bad*.dylib"); + foreach (const QString &bad, badlist) + QTest::newRow(qPrintable("machtest/" + bad)) << int(QMachOParser::NotSuitable); +#endif +} + +void tst_QPluginLoader::loadMachO() +{ +#ifdef Q_OF_MACH_O + QFile f(QFINDTESTDATA(QTest::currentDataTag())); + QVERIFY(f.open(QIODevice::ReadOnly)); + QByteArray data = f.readAll(); + + long pos; + ulong len; + QString errorString; + int r = QMachOParser::parse(data.constData(), data.size(), f.fileName(), &errorString, &pos, &len); + + QFETCH(int, parseResult); + QCOMPARE(r, parseResult); + + if (r == QMachOParser::NotSuitable) + return; + + QVERIFY(pos > 0); + QVERIFY(len >= sizeof(void*)); + QVERIFY(pos + long(len) < data.size()); + QCOMPARE(pos & (sizeof(void*) - 1), 0UL); + + void *value = *(void**)(data.constData() + pos); + QCOMPARE(value, sizeof(void*) > 4 ? (void*)(0xc0ffeec0ffeeL) : (void*)0xc0ffee); + + // now that we know it's valid, let's try to make it invalid + ulong offeredlen = pos; + do { + --offeredlen; + r = QMachOParser::parse(data.constData(), offeredlen, f.fileName(), &errorString, &pos, &len); + QVERIFY2(r == QMachOParser::NotSuitable, qPrintable(QString("Failed at size 0x%1").arg(offeredlen, 0, 16))); + } while (offeredlen); +#endif +} + #if defined (Q_OS_UNIX) void tst_QPluginLoader::loadGarbage() { diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index 3c0e132a0a..fb34afb880 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -214,22 +214,22 @@ void tst_QThreadPool::waitcomplete() QCOMPARE(testFunctionCount, runs); } -volatile bool ran; +QAtomicInt ran; // bool class TestTask : public QRunnable { public: void run() { - ran = true; + ran.store(true); } }; void tst_QThreadPool::runTask() { QThreadPool manager; - ran = false; + ran.store(false); manager.start(new TestTask()); - QTRY_VERIFY(ran); + QTRY_VERIFY(ran.load()); } /* @@ -237,19 +237,19 @@ void tst_QThreadPool::runTask() */ void tst_QThreadPool::singleton() { - ran = false; + ran.store(false); QThreadPool::globalInstance()->start(new TestTask()); - QTRY_VERIFY(ran); + QTRY_VERIFY(ran.load()); } -int *value = 0; +QAtomicInt *value = 0; class IntAccessor : public QRunnable { public: void run() { for (int i = 0; i < 100; ++i) { - ++(*value); + value->ref(); QTest::qSleep(1); } } @@ -261,7 +261,7 @@ public: */ void tst_QThreadPool::destruction() { - value = new int; + value = new QAtomicInt; QThreadPool *threadManager = new QThreadPool(); threadManager->start(new IntAccessor()); threadManager->start(new IntAccessor()); @@ -681,8 +681,8 @@ void tst_QThreadPool::tryStart() } QMutex mutex; -int activeThreads = 0; -int peakActiveThreads = 0; +QAtomicInt activeThreads; +QAtomicInt peakActiveThreads; void tst_QThreadPool::tryStartPeakThreadCount() { class CounterTask : public QRunnable @@ -694,14 +694,14 @@ void tst_QThreadPool::tryStartPeakThreadCount() { { QMutexLocker lock(&mutex); - ++activeThreads; - peakActiveThreads = qMax(peakActiveThreads, activeThreads); + activeThreads.ref(); + peakActiveThreads.store(qMax(peakActiveThreads.load(), activeThreads.load())); } QTest::qWait(100); { QMutexLocker lock(&mutex); - --activeThreads; + activeThreads.deref(); } } }; @@ -713,13 +713,13 @@ void tst_QThreadPool::tryStartPeakThreadCount() if (threadPool.tryStart(&task) == false) QTest::qWait(10); } - QCOMPARE(peakActiveThreads, QThread::idealThreadCount()); + QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount()); for (int i = 0; i < 20; ++i) { if (threadPool.tryStart(&task) == false) QTest::qWait(10); } - QCOMPARE(peakActiveThreads, QThread::idealThreadCount()); + QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount()); } void tst_QThreadPool::tryStartCount() diff --git a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp index 72bf5c58ca..c18ba4d05c 100644 --- a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp +++ b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp @@ -78,10 +78,22 @@ private slots: void qCountContainer() const; void binaryFindOnLargeContainer() const; -#if Q_TEST_PERFORMANCE + void popCount08_data() { popCount_data_impl(sizeof(quint8 )); } + void popCount16_data() { popCount_data_impl(sizeof(quint16)); } + void popCount32_data() { popCount_data_impl(sizeof(quint32)); } + void popCount64_data() { popCount_data_impl(sizeof(quint64)); } + void popCount08() { popCount_impl<quint8 >(); } + void popCount16() { popCount_impl<quint16>(); } + void popCount32() { popCount_impl<quint32>(); } + void popCount64() { popCount_impl<quint64>(); } + private: +#if Q_TEST_PERFORMANCE void performance(); #endif + void popCount_data_impl(size_t sizeof_T_Int); + template <typename T_Int> + void popCount_impl(); }; class TestInt @@ -1007,6 +1019,72 @@ void tst_QAlgorithms::binaryFindOnLargeContainer() const QCOMPARE(foundIt.pos(), 1073987655); } +// alternative implementation of qPopulationCount for comparison: +static const uint bitsSetInNibble[] = { + 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4, +}; +Q_STATIC_ASSERT(sizeof bitsSetInNibble / sizeof *bitsSetInNibble == 16); + +static Q_DECL_CONSTEXPR uint bitsSetInByte(quint8 byte) +{ + return bitsSetInNibble[byte & 0xF] + bitsSetInNibble[byte >> 4]; +} +static Q_DECL_CONSTEXPR uint bitsSetInShort(quint16 word) +{ + return bitsSetInByte(word & 0xFF) + bitsSetInByte(word >> 8); +} +static Q_DECL_CONSTEXPR uint bitsSetInInt(quint32 word) +{ + return bitsSetInShort(word & 0xFFFF) + bitsSetInShort(word >> 16); +} +static Q_DECL_CONSTEXPR uint bitsSetInInt64(quint64 word) +{ + return bitsSetInInt(word & 0xFFFFFFFF) + bitsSetInInt(word >> 32); +} + + +void tst_QAlgorithms::popCount_data_impl(size_t sizeof_T_Int) +{ + using namespace QTest; + addColumn<quint64>("input"); + addColumn<uint>("expected"); + + for (uint i = 0; i < UCHAR_MAX; ++i) { + const uchar byte = static_cast<uchar>(i); + const uint bits = bitsSetInByte(byte); + const quint64 value = static_cast<quint64>(byte); + const quint64 input = value << ((i % sizeof_T_Int) * 8U); + newRow(qPrintable(QString().sprintf("0x%016llx", input))) << input << bits; + } + + // and some random ones: + if (sizeof_T_Int >= 8) + for (size_t i = 0; i < 1000; ++i) { + const quint64 input = quint64(qrand()) << 32 | quint32(qrand()); + newRow(qPrintable(QString().sprintf("0x%016llx", input))) << input << bitsSetInInt64(input); + } + else if (sizeof_T_Int >= 2) + for (size_t i = 0; i < 1000 ; ++i) { + const quint32 input = qrand(); + if (sizeof_T_Int >= 4) + newRow(qPrintable(QString().sprintf("0x%08x", input))) << quint64(input) << bitsSetInInt(input); + else + newRow(qPrintable(QString().sprintf("0x%04x", quint16(input & 0xFFFF)))) << quint64(input & 0xFFFF) << bitsSetInShort(input & 0xFFFF); + } +} + +template <typename T_Int> +void tst_QAlgorithms::popCount_impl() +{ + QFETCH(quint64, input); + QFETCH(uint, expected); + + const T_Int value = static_cast<T_Int>(input); + + QCOMPARE(qPopulationCount(value), expected); +} + QTEST_APPLESS_MAIN(tst_QAlgorithms) #include "tst_qalgorithms.moc" diff --git a/tests/auto/corelib/tools/qdate/tst_qdate.cpp b/tests/auto/corelib/tools/qdate/tst_qdate.cpp index 310528ba27..728a4244a1 100644 --- a/tests/auto/corelib/tools/qdate/tst_qdate.cpp +++ b/tests/auto/corelib/tools/qdate/tst_qdate.cpp @@ -944,6 +944,61 @@ void tst_QDate::fromStringDateFormat_data() QTest::newRow("iso2") << QDate(1999, 11, 14).toString(Qt::ISODate) << Qt::ISODate << QDate(1999, 11, 14); QTest::newRow("iso3") << QString("0999-01-01") << Qt::ISODate << QDate(999, 1, 1); QTest::newRow("iso3b") << QString("0999-01-01") << Qt::ISODate << QDate(999, 1, 1); + + // Test Qt::RFC2822Date format (RFC 2822). + QTest::newRow("RFC 2822") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100") + << Qt::RFC2822Date << QDate(1987, 2, 13); + QTest::newRow("RFC 2822 with day") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000") + << Qt::RFC2822Date << QDate(1970, 1, 1); + // No timezone + QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34") + << Qt::RFC2822Date << QDate(1970, 1, 1); + // No time specified + QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002") + << Qt::RFC2822Date << QDate(2002, 11, 1); + QTest::newRow("RFC 2822 with day date only") << QString::fromLatin1("Fri, 01 Nov 2002") + << Qt::RFC2822Date << QDate(2002, 11, 1); + // Test invalid month, day, year + QTest::newRow("RFC 2822 invalid month name") << QString::fromLatin1("13 Fev 1987 13:24:51 +0100") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 2822 invalid day") << QString::fromLatin1("36 Fev 1987 13:24:51 +0100") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 2822 invalid year") << QString::fromLatin1("13 Fev 0000 13:24:51 +0100") + << Qt::RFC2822Date << QDate(); + // Test invalid characters (should ignore invalid characters at end of string). + QTest::newRow("RFC 2822 invalid character at end") << QString::fromLatin1("01 Jan 2012 08:00:00 +0100!") + << Qt::RFC2822Date << QDate(2012, 1, 1); + QTest::newRow("RFC 2822 invalid character at front") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 2822 invalid character both ends") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000!") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 2822 invalid character at front, 2 at back") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000..") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 2822 invalid character 2 at front") << QString::fromLatin1("!!01 Jan 2012 08:00:00 +0000") + << Qt::RFC2822Date << QDate(); + + // Test Qt::RFC2822Date format (RFC 850 and 1036). + QTest::newRow("RFC 850 and 1036") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 +0100") + << Qt::RFC2822Date << QDate(1987, 2, 13); + // No timezone + QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970") + << Qt::RFC2822Date << QDate(1970, 1, 1); + // No time specified + QTest::newRow("RFC 850 and 1036 date only") << QString::fromLatin1("Fri Nov 01 2002") + << Qt::RFC2822Date << QDate(2002, 11, 1); + // Test invalid characters (should ignore invalid characters at end of string). + QTest::newRow("RFC 850 and 1036 invalid character at end") << QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100!") + << Qt::RFC2822Date << QDate(2012, 1, 1); + QTest::newRow("RFC 850 and 1036 invalid character at front") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 850 and 1036 invalid character both ends") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000!") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 850 and 1036 invalid character at front, 2 at back") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000..") + << Qt::RFC2822Date << QDate(); + QTest::newRow("RFC 850 and 1036 invalid character 2 at front") << QString::fromLatin1("!!Sun Jan 01 08:00:00 2012 +0000") + << Qt::RFC2822Date << QDate(); + + QTest::newRow("RFC empty") << QString::fromLatin1("") << Qt::RFC2822Date << QDate(); } void tst_QDate::fromStringDateFormat() @@ -1072,6 +1127,7 @@ void tst_QDate::toStringDateFormat_data() QTest::newRow("data3") << QDate(1974,12,1) << Qt::ISODate << QString("1974-12-01"); QTest::newRow("year < 0") << QDate(-1,1,1) << Qt::ISODate << QString(); QTest::newRow("year > 9999") << QDate(-1,1,1) << Qt::ISODate << QString(); + QTest::newRow("RFC2822Date") << QDate(1974,12,1) << Qt::RFC2822Date << QString("01 Dec 1974"); } void tst_QDate::toStringDateFormat() diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 0ec3f64020..a0e55e9ae1 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -85,6 +85,8 @@ private slots: void fromMSecsSinceEpoch(); void toString_isoDate_data(); void toString_isoDate(); + void toString_rfcDate_data(); + void toString_rfcDate(); void toString_enumformat(); void toString_strformat_data(); void toString_strformat(); @@ -556,22 +558,25 @@ void tst_QDateTime::toString_isoDate_data() QTest::newRow("localtime") << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34)) - << QString("1978-11-09T13:28:34"); + << QString("1978-11-09T13:28:34.000"); QTest::newRow("UTC") << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC) - << QString("1978-11-09T13:28:34Z"); + << QString("1978-11-09T13:28:34.000Z"); QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34)); dt.setUtcOffset(19800); QTest::newRow("positive OffsetFromUTC") << dt - << QString("1978-11-09T13:28:34+05:30"); + << QString("1978-11-09T13:28:34.000+05:30"); dt.setUtcOffset(-7200); QTest::newRow("negative OffsetFromUTC") << dt - << QString("1978-11-09T13:28:34-02:00"); + << QString("1978-11-09T13:28:34.000-02:00"); QTest::newRow("invalid") << QDateTime(QDate(-1, 11, 9), QTime(13, 28, 34), Qt::UTC) << QString(); + QTest::newRow("999 milliseconds UTC") + << QDateTime(QDate(2000, 1, 1), QTime(13, 28, 34, 999), Qt::UTC) + << QString("2000-01-01T13:28:34.999Z"); } void tst_QDateTime::toString_isoDate() @@ -582,6 +587,44 @@ void tst_QDateTime::toString_isoDate() QCOMPARE(dt.toString(Qt::ISODate), formatted); } +void tst_QDateTime::toString_rfcDate_data() +{ + QTest::addColumn<QDateTime>("dt"); + QTest::addColumn<QString>("formatted"); + + if (europeanTimeZone) { + QTest::newRow("localtime") + << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34)) + << QString("09 Nov 1978 13:28:34 +0100"); + } + QTest::newRow("UTC") + << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC) + << QString("09 Nov 1978 13:28:34 +0000"); + QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34)); + dt.setUtcOffset(19800); + QTest::newRow("positive OffsetFromUTC") + << dt + << QString("09 Nov 1978 13:28:34 +0530"); + dt.setUtcOffset(-7200); + QTest::newRow("negative OffsetFromUTC") + << dt + << QString("09 Nov 1978 13:28:34 -0200"); + QTest::newRow("invalid") + << QDateTime(QDate(1978, 13, 9), QTime(13, 28, 34), Qt::UTC) + << QString(); + QTest::newRow("999 milliseconds UTC") + << QDateTime(QDate(2000, 1, 1), QTime(13, 28, 34, 999), Qt::UTC) + << QString("01 Jan 2000 13:28:34 +0000"); +} + +void tst_QDateTime::toString_rfcDate() +{ + QFETCH(QDateTime, dt); + QFETCH(QString, formatted); + + QCOMPARE(dt.toString(Qt::RFC2822Date), formatted); +} + void tst_QDateTime::toString_enumformat() { QDateTime dt1(QDate(1995, 5, 20), QTime(12, 34, 56)); @@ -591,7 +634,7 @@ void tst_QDateTime::toString_enumformat() QVERIFY(!str1.isEmpty()); // It's locale dependent everywhere QString str2 = dt1.toString(Qt::ISODate); - QCOMPARE(str2, QString("1995-05-20T12:34:56")); + QCOMPARE(str2, QString("1995-05-20T12:34:56.000")); QString str3 = dt1.toString(Qt::LocalDate); QVERIFY(!str3.isEmpty()); @@ -1611,6 +1654,8 @@ void tst_QDateTime::fromStringDateFormat_data() << Qt::TextDate << invalidDateTime(); QTest::newRow("text invalid gmt minute") << QString::fromLatin1("Thu 1. Jan 1970 00:00:00 GMT+000X") << Qt::TextDate << invalidDateTime(); + QTest::newRow("text second fraction") << QString::fromLatin1("Mon 6. May 2013 01:02:03.456") + << Qt::TextDate << QDateTime(QDate(2013, 5, 6), QTime(1, 2, 3, 456)); // Test Qt::ISODate format. QTest::newRow("ISO +01:00") << QString::fromLatin1("1987-02-13T13:24:51+01:00") @@ -1697,6 +1742,79 @@ void tst_QDateTime::fromStringDateFormat_data() QTest::newRow("ISO .99999 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,99999") << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999), Qt::LocalTime); QTest::newRow("ISO empty") << QString::fromLatin1("") << Qt::ISODate << invalidDateTime(); + + // Test Qt::RFC2822Date format (RFC 2822). + QTest::newRow("RFC 2822 +0100") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100") + << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC); + QTest::newRow("RFC 2822 with day +0100") << QString::fromLatin1("Fri, 13 Feb 1987 13:24:51 +0100") + << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC); + QTest::newRow("RFC 2822 -0100") << QString::fromLatin1("13 Feb 1987 13:24:51 -0100") + << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC); + QTest::newRow("RFC 2822 with day -0100") << QString::fromLatin1("Fri, 13 Feb 1987 13:24:51 -0100") + << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC); + QTest::newRow("RFC 2822 +0000") << QString::fromLatin1("01 Jan 1970 00:12:34 +0000") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + QTest::newRow("RFC 2822 with day +0000") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + QTest::newRow("RFC 2822 +0000") << QString::fromLatin1("01 Jan 1970 00:12:34 +0000") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + QTest::newRow("RFC 2822 with day +0000") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + // No timezone assume UTC + QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + // No time specified + QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 2822 with day date only") << QString::fromLatin1("Fri, 01 Nov 2002") + << Qt::RFC2822Date << invalidDateTime(); + // Test invalid month, day, year + QTest::newRow("RFC 2822 invalid month name") << QString::fromLatin1("13 Fev 1987 13:24:51 +0100") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 2822 invalid day") << QString::fromLatin1("36 Fev 1987 13:24:51 +0100") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 2822 invalid year") << QString::fromLatin1("13 Fev 0000 13:24:51 +0100") + << Qt::RFC2822Date << invalidDateTime(); + // Test invalid characters (should ignore invalid characters at end of string). + QTest::newRow("RFC 2822 invalid character at end") << QString::fromLatin1("01 Jan 2012 08:00:00 +0100!") + << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0, 0, 0), Qt::UTC); + QTest::newRow("RFC 2822 invalid character at front") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 2822 invalid character both ends") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000!") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 2822 invalid character at front, 2 at back") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000..") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 2822 invalid character 2 at front") << QString::fromLatin1("!!01 Jan 2012 08:00:00 +0000") + << Qt::RFC2822Date << invalidDateTime(); + + // Test Qt::RFC2822Date format (RFC 850 and 1036). + QTest::newRow("RFC 850 and 1036 +0100") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 +0100") + << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC); + QTest::newRow("RFC 850 and 1036 -0100") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 -0100") + << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC); + QTest::newRow("RFC 850 and 1036 +0000") << QString::fromLatin1("Thu Jan 01 00:12:34 1970 +0000") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + QTest::newRow("RFC 850 and 1036 +0000") << QString::fromLatin1("Thu Jan 01 00:12:34 1970 +0000") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + // No timezone assume UTC + QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970") + << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC); + // No time specified + QTest::newRow("RFC 850 and 1036 date only") << QString::fromLatin1("Fri Nov 01 2002") + << Qt::RFC2822Date << invalidDateTime(); + // Test invalid characters (should ignore invalid characters at end of string). + QTest::newRow("RFC 850 and 1036 invalid character at end") << QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100!") + << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0, 0, 0), Qt::UTC); + QTest::newRow("RFC 850 and 1036 invalid character at front") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 850 and 1036 invalid character both ends") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000!") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 850 and 1036 invalid character at front, 2 at back") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000..") + << Qt::RFC2822Date << invalidDateTime(); + QTest::newRow("RFC 850 and 1036 invalid character 2 at front") << QString::fromLatin1("!!Sun Jan 01 08:00:00 2012 +0000") + << Qt::RFC2822Date << invalidDateTime(); + + QTest::newRow("RFC empty") << QString::fromLatin1("") << Qt::RFC2822Date << invalidDateTime(); } void tst_QDateTime::fromStringDateFormat() diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp index fa747b3c18..3348b49110 100644 --- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp +++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp @@ -730,14 +730,16 @@ double static inline _fast_cbrt(double d) void tst_QEasingCurve::testCbrtDouble() { - const qreal errorBound = 0.0001; + const double errorBound = 0.0001; for (int i = 0; i < 100000; i++) { double d = double(i) / 1000.0; double t = _fast_cbrt(d); const double t_cubic = t * t * t; - t = t * (t_cubic + d + d) / (t_cubic + t_cubic + d); + const double f = t_cubic + t_cubic + d; + if (f != 0.0) + t = t * (t_cubic + d + d) / f; double expected = pow(d, 1.0/3.0); @@ -754,14 +756,16 @@ void tst_QEasingCurve::testCbrtDouble() void tst_QEasingCurve::testCbrtFloat() { - const qreal errorBound = 0.0005; + const float errorBound = 0.0005; - for (int i = 1; i < 100000; i++) { + for (int i = 0; i < 100000; i++) { float f = float(i) / 1000.0f; float t = _fast_cbrt(f); const float t_cubic = t * t * t; - t = t * (t_cubic + f + f) / (t_cubic + t_cubic + f); + const float fac = t_cubic + t_cubic + f; + if (fac != 0.0f) + t = t * (t_cubic + f + f) / fac; float expected = pow(f, float(1.0/3.0)); diff --git a/tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro b/tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro index 5fa529e175..48a3b9ee9c 100644 --- a/tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro +++ b/tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro @@ -1,4 +1,5 @@ CONFIG += testcase parallel_test +contains(QT_CONFIG, c++11):CONFIG += c++11 TARGET = tst_qscopedpointer QT = core testlib SOURCES = tst_qscopedpointer.cpp diff --git a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp index 66ea3e940c..cb0382eb66 100644 --- a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp +++ b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp @@ -42,6 +42,8 @@ #include <QtTest/QtTest> #include <QtCore/QScopedPointer> +#include <utility> + /*! \class tst_QScopedPointer \internal @@ -73,6 +75,7 @@ private Q_SLOTS: void objectSize(); void comparison(); void array(); + void move(); // TODO instanciate on const object }; @@ -458,6 +461,158 @@ void tst_QScopedPointer::array() QCOMPARE(instCount, RefCounted::instanceCount.load()); } +#ifdef Q_COMPILER_RVALUE_REFS +struct CountedInteger +{ + CountedInteger(int i) : i(i) + { + ++instanceCount; + } + ~CountedInteger() + { + --instanceCount; + } + CountedInteger(const CountedInteger &c) + : i(c.i) + { + ++instanceCount; + } + + static int instanceCount; + int i; +}; + +int CountedInteger::instanceCount = 0; + +QScopedPointer<CountedInteger> returnScopedPointer(int i) +{ + return QScopedPointer<CountedInteger>(new CountedInteger(i)); +} +#endif + +void tst_QScopedPointer::move() +{ +#ifndef Q_COMPILER_RVALUE_REFS + QSKIP("This test requires rvalues refs"); +#else + QCOMPARE(CountedInteger::instanceCount, 0); + + { + QScopedPointer<CountedInteger> p = returnScopedPointer(42); + QVERIFY(!p.isNull()); + QCOMPARE(p->i, 42); + QCOMPARE(CountedInteger::instanceCount, 1); + + QScopedPointer<CountedInteger> q = returnScopedPointer(51); + QVERIFY(!q.isNull()); + QCOMPARE(q->i, 51); + QCOMPARE(CountedInteger::instanceCount, 2); + + q = returnScopedPointer(123); + QVERIFY(!q.isNull()); + QCOMPARE(q->i, 123); + QCOMPARE(CountedInteger::instanceCount, 2); + + p = std::move(q); + QVERIFY(!p.isNull()); + QCOMPARE(p->i, 123); + QVERIFY(q.isNull()); + QCOMPARE(CountedInteger::instanceCount, 1); + + p = std::move(q); + QVERIFY(p.isNull()); + QVERIFY(q.isNull()); + QCOMPARE(CountedInteger::instanceCount, 0); + } + + QCOMPARE(CountedInteger::instanceCount, 0); + + { + QScopedPointer<CountedInteger> p = returnScopedPointer(1024); + QVERIFY(!p.isNull()); + QCOMPARE(p->i, 1024); + QCOMPARE(CountedInteger::instanceCount, 1); + + p.reset(); + QVERIFY(p.isNull()); + QCOMPARE(CountedInteger::instanceCount, 0); + + p = returnScopedPointer(1024); + const CountedInteger * const rawPtr = p.data(); + p = std::move(p); + // now p is in a "valid, but unspecified state". so the test must not crash. + // we do actually know that this move should've been a noop. + QVERIFY(!p.isNull()); + QCOMPARE(p.data(), rawPtr); + QCOMPARE(p->i, 1024); + QCOMPARE(CountedInteger::instanceCount, 1); + + p.reset(); + QVERIFY(p.isNull()); + QCOMPARE(CountedInteger::instanceCount, 0); + } + + QCOMPARE(CountedInteger::instanceCount, 0); + + { + QScopedPointer<CountedInteger> p = returnScopedPointer(-1); + QVERIFY(!p.isNull()); + QCOMPARE(p->i, -1); + QCOMPARE(CountedInteger::instanceCount, 1); + } + + QCOMPARE(CountedInteger::instanceCount, 0); + + { + QScopedPointer<CountedInteger> p = returnScopedPointer(0); + QVERIFY(!p.isNull()); + QCOMPARE(p->i, 0); + QCOMPARE(CountedInteger::instanceCount, 1); + + QScopedPointer<CountedInteger> q; + QVERIFY(q.isNull()); + + p = std::move(q); + QVERIFY(p.isNull()); + QVERIFY(q.isNull()); + QCOMPARE(CountedInteger::instanceCount, 0); + } + + QCOMPARE(CountedInteger::instanceCount, 0); + + { + QScopedPointer<CountedInteger> p; + QVERIFY(p.isNull()); + QCOMPARE(CountedInteger::instanceCount, 0); + + QScopedPointer<CountedInteger> q = returnScopedPointer(123); + QVERIFY(!q.isNull()); + QCOMPARE(q->i, 123); + QCOMPARE(CountedInteger::instanceCount, 1); + + p = std::move(q); + QVERIFY(!p.isNull()); + QCOMPARE(p->i, 123); + QVERIFY(q.isNull()); + QCOMPARE(CountedInteger::instanceCount, 1); + } + + QCOMPARE(CountedInteger::instanceCount, 0); + + { + QScopedPointer<CountedInteger> p; + QVERIFY(p.isNull()); + QCOMPARE(CountedInteger::instanceCount, 0); + + p = returnScopedPointer(2001); + QVERIFY(!p.isNull()); + QCOMPARE(p->i, 2001); + QCOMPARE(CountedInteger::instanceCount, 1); + } + + QCOMPARE(CountedInteger::instanceCount, 0); +#endif +} QTEST_MAIN(tst_QScopedPointer) #include "tst_qscopedpointer.moc" diff --git a/tests/auto/corelib/tools/qtime/tst_qtime.cpp b/tests/auto/corelib/tools/qtime/tst_qtime.cpp index 97645ea7f6..675aeafc06 100644 --- a/tests/auto/corelib/tools/qtime/tst_qtime.cpp +++ b/tests/auto/corelib/tools/qtime/tst_qtime.cpp @@ -600,6 +600,59 @@ void tst_QTime::fromStringDateFormat_data() QTest::newRow("IsoDate - data2") << QString("19:03:54.998601") << Qt::ISODate << QTime(19, 3, 54, 999); QTest::newRow("IsoDate - data3") << QString("19:03:54.999601") << Qt::ISODate << QTime(19, 3, 54, 999); QTest::newRow("IsoDate - minute fraction midnight") << QString("24:00,0") << Qt::ISODate << QTime(0, 0, 0, 0); + + // Test Qt::RFC2822Date format (RFC 2822). + QTest::newRow("RFC 2822") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100") + << Qt::RFC2822Date << QTime(13, 24, 51); + QTest::newRow("RFC 2822 with day") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000") + << Qt::RFC2822Date << QTime(0, 12, 34); + // No timezone + QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34") + << Qt::RFC2822Date << QTime(0, 12, 34); + // No time specified + QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002") + << Qt::RFC2822Date << invalidTime(); + QTest::newRow("RFC 2822 with day date only") << QString::fromLatin1("Fri, 01 Nov 2002") + << Qt::RFC2822Date << invalidTime(); + // Test invalid month, day, year + QTest::newRow("RFC 2822 invalid month name") << QString::fromLatin1("13 Fev 1987 13:24:51 +0100") + << Qt::RFC2822Date << QTime(13, 24, 51); + QTest::newRow("RFC 2822 invalid day") << QString::fromLatin1("36 Fev 1987 13:24:51 +0100") + << Qt::RFC2822Date << QTime(13, 24, 51); + QTest::newRow("RFC 2822 invalid year") << QString::fromLatin1("13 Fev 0000 13:24:51 +0100") + << Qt::RFC2822Date << QTime(13, 24, 51); + // Test invalid characters (should ignore invalid characters at end of string). + QTest::newRow("RFC 2822 invalid character at end") << QString::fromLatin1("01 Jan 2012 08:00:00 +0100!") + << Qt::RFC2822Date << QTime(8, 0, 0); + QTest::newRow("RFC 2822 invalid character at front") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000") + << Qt::RFC2822Date << invalidTime(); + QTest::newRow("RFC 2822 invalid character both ends") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000!") + << Qt::RFC2822Date << invalidTime(); + QTest::newRow("RFC 2822 invalid character at front, 2 at back") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000..") + << Qt::RFC2822Date << invalidTime(); + QTest::newRow("RFC 2822 invalid character 2 at front") << QString::fromLatin1("!!01 Jan 2012 08:00:00 +0000") + << Qt::RFC2822Date << invalidTime(); + + // Test Qt::RFC2822Date format (RFC 850 and 1036). + QTest::newRow("RFC 850 and 1036") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 +0100") + << Qt::RFC2822Date << QTime(13, 24, 51); + // No timezone + QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970") + << Qt::RFC2822Date << QTime(0, 12, 34); + // No time specified + QTest::newRow("RFC 850 and 1036 date only") << QString::fromLatin1("Fri Nov 01 2002") + << Qt::RFC2822Date << invalidTime(); + // Test invalid characters (should ignore invalid characters at end of string). + QTest::newRow("RFC 850 and 1036 invalid character at end") << QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100!") + << Qt::RFC2822Date << QTime(8, 0, 0); + QTest::newRow("RFC 850 and 1036 invalid character at front") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000") + << Qt::RFC2822Date << invalidTime(); + QTest::newRow("RFC 850 and 1036 invalid character both ends") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000!") + << Qt::RFC2822Date << invalidTime(); + QTest::newRow("RFC 850 and 1036 invalid character at front, 2 at back") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000..") + << Qt::RFC2822Date << invalidTime(); + + QTest::newRow("RFC empty") << QString::fromLatin1("") << Qt::RFC2822Date << invalidTime(); } void tst_QTime::fromStringDateFormat() @@ -614,25 +667,28 @@ void tst_QTime::fromStringDateFormat() void tst_QTime::toStringDateFormat_data() { - // Since we can't define an element of Qt::DateFormat, str1 will be the string - // in TextDate format, and str2 will be the time in ISODate format. - - QTest::addColumn<QTime>("t"); - QTest::addColumn<QString>("str1"); - QTest::addColumn<QString>("str2"); - - QTest::newRow( "data0" ) << QTime(0,0,0,0) << QString("00:00:00") << QString("00:00:00"); - QTest::newRow( "data1" ) << QTime(10,12,34,0) << QString("10:12:34") << QString("10:12:34"); + QTest::addColumn<QTime>("time"); + QTest::addColumn<Qt::DateFormat>("format"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("00:00:00.000") << QTime(0, 0, 0, 0) << Qt::TextDate << QString("00:00:00.000"); + QTest::newRow("ISO 00:00:00.000") << QTime(0, 0, 0, 0) << Qt::ISODate << QString("00:00:00.000"); + QTest::newRow("Text 10:12:34.000") << QTime(10, 12, 34, 0) << Qt::TextDate << QString("10:12:34.000"); + QTest::newRow("ISO 10:12:34.000") << QTime(10, 12, 34, 0) << Qt::ISODate << QString("10:12:34.000"); + QTest::newRow("Text 10:12:34.001") << QTime(10, 12, 34, 001) << Qt::TextDate << QString("10:12:34.001"); + QTest::newRow("ISO 10:12:34.001") << QTime(10, 12, 34, 001) << Qt::ISODate << QString("10:12:34.001"); + QTest::newRow("Text 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::TextDate << QString("10:12:34.999"); + QTest::newRow("ISO 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::ISODate << QString("10:12:34.999"); + QTest::newRow("RFC2822Date") << QTime(10, 12, 34, 999) << Qt::RFC2822Date << QString("10:12:34"); } void tst_QTime::toStringDateFormat() { - QFETCH( QTime, t ); - QFETCH( QString, str1 ); - QFETCH( QString, str2 ); + QFETCH(QTime, time); + QFETCH(Qt::DateFormat, format); + QFETCH(QString, expected); - QCOMPARE( str1, t.toString( Qt::TextDate ) ); - QCOMPARE( str2, t.toString( Qt::ISODate ) ); + QCOMPARE(time.toString(format), expected); } void tst_QTime::toStringFormat_data() diff --git a/tests/auto/dbus/qdbusabstractinterface/interface.h b/tests/auto/dbus/qdbusabstractinterface/interface.h index 5db59b19eb..ecf732ce2d 100644 --- a/tests/auto/dbus/qdbusabstractinterface/interface.h +++ b/tests/auto/dbus/qdbusabstractinterface/interface.h @@ -43,6 +43,7 @@ #define INTERFACE_H #include <QtCore/QObject> +#include <QtCore/QHash> #include <QtDBus/QDBusArgument> struct RegisteredType @@ -103,7 +104,7 @@ public slots: Q_SCRIPTABLE void voidMethod() {} Q_SCRIPTABLE int sleepMethod(int); Q_SCRIPTABLE QString stringMethod() { return "Hello, world"; } - Q_SCRIPTABLE RegisteredType complexMethod() { return RegisteredType("Hello, world"); } + Q_SCRIPTABLE RegisteredType complexMethod(const QVariantHash &vars) { return RegisteredType(vars.value("arg1").toString()); } Q_SCRIPTABLE QString multiOutMethod(int &value) { value = 42; return "Hello, world"; } signals: diff --git a/tests/auto/dbus/qdbusabstractinterface/org.qtproject.QtDBus.Pinger.xml b/tests/auto/dbus/qdbusabstractinterface/org.qtproject.QtDBus.Pinger.xml index 845e7be5b4..ad61351cb2 100644 --- a/tests/auto/dbus/qdbusabstractinterface/org.qtproject.QtDBus.Pinger.xml +++ b/tests/auto/dbus/qdbusabstractinterface/org.qtproject.QtDBus.Pinger.xml @@ -8,7 +8,7 @@ </property> <signal name="voidSignal"/> <signal name="stringSignal"> - <arg type="s"/> + <arg type="s" name="string-data"/> </signal> <signal name="complexSignal"> <arg name="" type="(s)"/> @@ -23,6 +23,8 @@ <arg type="s" direction="out"/> </method> <method name="complexMethod"> + <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QHash<QString,QVariant>"/> + <arg type='a{sv}' name='platform_data' direction='in'/> <arg type="(s)" direction="out"/> <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="RegisteredType"/> </method> diff --git a/tests/auto/dbus/qdbusabstractinterface/pinger.h b/tests/auto/dbus/qdbusabstractinterface/pinger.h deleted file mode 100644 index 6bed72c203..0000000000 --- a/tests/auto/dbus/qdbusabstractinterface/pinger.h +++ /dev/null @@ -1,152 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtDBus module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/* - * This file was generated by qdbusxml2cpp version 0.7 - * Command line was: qdbusxml2cpp -i interface.h -p pinger org.qtproject.QtDBus.Pinger.xml - * - * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). - * - * This is an auto-generated file. - * Do not edit! All changes made to it will be lost. - */ - -#ifndef PINGER_H_1246463415 -#define PINGER_H_1246463415 - -#include <QtCore/QObject> -#include <QtCore/QByteArray> -#include <QtCore/QList> -#include <QtCore/QMap> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVariant> -#include <QtDBus/QtDBus> -#include "interface.h" - -/* - * Proxy class for interface org.qtproject.QtDBus.Pinger - */ -class ComTrolltechQtDBusPingerInterface: public QDBusAbstractInterface -{ - Q_OBJECT -public: - static inline const char *staticInterfaceName() - { return "org.qtproject.QtDBus.Pinger"; } - -public: - ComTrolltechQtDBusPingerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); - - ~ComTrolltechQtDBusPingerInterface(); - - Q_PROPERTY(RegisteredType complexProp READ complexProp WRITE setComplexProp) - inline RegisteredType complexProp() const - { return qvariant_cast< RegisteredType >(property("complexProp")); } - inline void setComplexProp(RegisteredType value) - { setProperty("complexProp", QVariant::fromValue(value)); } - - Q_PROPERTY(QString stringProp READ stringProp WRITE setStringProp) - inline QString stringProp() const - { return qvariant_cast< QString >(property("stringProp")); } - inline void setStringProp(const QString &value) - { setProperty("stringProp", QVariant::fromValue(value)); } - - Q_PROPERTY(QDBusVariant variantProp READ variantProp WRITE setVariantProp) - inline QDBusVariant variantProp() const - { return qvariant_cast< QDBusVariant >(property("variantProp")); } - inline void setVariantProp(const QDBusVariant &value) - { setProperty("variantProp", QVariant::fromValue(value)); } - -public Q_SLOTS: // METHODS - inline QDBusPendingReply<RegisteredType> complexMethod() - { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QLatin1String("complexMethod"), argumentList); - } - - inline QDBusPendingReply<QString, int> multiOutMethod() - { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QLatin1String("multiOutMethod"), argumentList); - } - inline QDBusReply<QString> multiOutMethod(int &out1) - { - QList<QVariant> argumentList; - QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("multiOutMethod"), argumentList); - if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) { - out1 = qdbus_cast<int>(reply.arguments().at(1)); - } - return reply; - } - - inline QDBusPendingReply<int> sleepMethod(int in0) - { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QLatin1String("sleepMethod"), argumentList); - } - - inline QDBusPendingReply<QString> stringMethod() - { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QLatin1String("stringMethod"), argumentList); - } - - inline QDBusPendingReply<> voidMethod() - { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QLatin1String("voidMethod"), argumentList); - } - -Q_SIGNALS: // SIGNALS - void complexSignal(RegisteredType in0); - void stringSignal(const QString &in0); - void voidSignal(); -}; - -namespace com { - namespace trolltech { - namespace QtDBus { - typedef ::ComTrolltechQtDBusPingerInterface Pinger; - } - } -} -#endif diff --git a/tests/auto/dbus/qdbusabstractinterface/test/test.pro b/tests/auto/dbus/qdbusabstractinterface/test/test.pro index 363d5fdf9c..66744b9252 100644 --- a/tests/auto/dbus/qdbusabstractinterface/test/test.pro +++ b/tests/auto/dbus/qdbusabstractinterface/test/test.pro @@ -2,13 +2,11 @@ CONFIG += testcase SOURCES += ../tst_qdbusabstractinterface.cpp ../interface.cpp HEADERS += ../interface.h -# These are generated sources -# To regenerate, see the command-line at the top of the files -SOURCES += ../pinger.cpp -HEADERS += ../pinger.h - TARGET = ../tst_qdbusabstractinterface QT = core testlib QT += dbus DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 + +DBUS_INTERFACES = ../org.qtproject.QtDBus.Pinger.xml +QDBUSXML2CPP_INTERFACE_HEADER_FLAGS += -i ../interface.h diff --git a/tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp b/tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp index 5f3cf539e9..91e69fcdb7 100644 --- a/tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp +++ b/tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp @@ -47,13 +47,13 @@ #include <QtDBus> #include "interface.h" -#include "pinger.h" +#include "pinger_interface.h" static const char serviceName[] = "org.qtproject.autotests.qpinger"; static const char objectPath[] = "/org/qtproject/qpinger"; static const char *interfaceName = serviceName; -typedef QSharedPointer<com::trolltech::QtDBus::Pinger> Pinger; +typedef QSharedPointer<org::qtproject::QtDBus::Pinger> Pinger; class tst_QDBusAbstractInterface: public QObject { @@ -67,7 +67,7 @@ class tst_QDBusAbstractInterface: public QObject return Pinger(); if (service.isEmpty() && !service.isNull()) service = con.baseService(); - return Pinger(new com::trolltech::QtDBus::Pinger(service, path, con)); + return Pinger(new org::qtproject::QtDBus::Pinger(service, path, con)); } Pinger getPingerPeer(const QString &path = "/", const QString &service = "") @@ -75,7 +75,7 @@ class tst_QDBusAbstractInterface: public QObject QDBusConnection con = QDBusConnection("peer"); if (!con.isConnected()) return Pinger(); - return Pinger(new com::trolltech::QtDBus::Pinger(service, path, con)); + return Pinger(new org::qtproject::QtDBus::Pinger(service, path, con)); } void resetServer() @@ -308,14 +308,22 @@ void tst_QDBusAbstractInterface::makeStringCall() QCOMPARE(r.value(), targetObj.stringMethod()); } +static QHash<QString, QVariant> complexMethodArgs() +{ + QHash<QString, QVariant> args; + args.insert("arg1", "Hello world"); + args.insert("arg2", 12345); + return args; +} + void tst_QDBusAbstractInterface::makeComplexCall() { Pinger p = getPinger(); QVERIFY2(p, "Not connected to D-Bus"); - QDBusReply<RegisteredType> r = p->complexMethod(); + QDBusReply<RegisteredType> r = p->complexMethod(complexMethodArgs()); QVERIFY(r.isValid()); - QCOMPARE(r.value(), targetObj.complexMethod()); + QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs())); } void tst_QDBusAbstractInterface::makeMultiOutCall() @@ -356,9 +364,9 @@ void tst_QDBusAbstractInterface::makeComplexCallPeer() Pinger p = getPingerPeer(); QVERIFY2(p, "Not connected to D-Bus"); - QDBusReply<RegisteredType> r = p->complexMethod(); + QDBusReply<RegisteredType> r = p->complexMethod(complexMethodArgs()); QVERIFY(r.isValid()); - QCOMPARE(r.value(), targetObj.complexMethod()); + QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs())); } void tst_QDBusAbstractInterface::makeMultiOutCallPeer() @@ -401,10 +409,10 @@ void tst_QDBusAbstractInterface::makeAsyncComplexCall() Pinger p = getPinger(); QVERIFY2(p, "Not connected to D-Bus"); - QDBusPendingReply<RegisteredType> r = p->complexMethod(); + QDBusPendingReply<RegisteredType> r = p->complexMethod(complexMethodArgs()); r.waitForFinished(); QVERIFY(r.isValid()); - QCOMPARE(r.value(), targetObj.complexMethod()); + QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs())); } void tst_QDBusAbstractInterface::makeAsyncMultiOutCall() @@ -449,10 +457,10 @@ void tst_QDBusAbstractInterface::makeAsyncComplexCallPeer() Pinger p = getPingerPeer(); QVERIFY2(p, "Not connected to D-Bus"); - QDBusPendingReply<RegisteredType> r = p->complexMethod(); + QDBusPendingReply<RegisteredType> r = p->complexMethod(complexMethodArgs()); r.waitForFinished(); QVERIFY(r.isValid()); - QCOMPARE(r.value(), targetObj.complexMethod()); + QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs())); } void tst_QDBusAbstractInterface::makeAsyncMultiOutCallPeer() @@ -551,7 +559,7 @@ void tst_QDBusAbstractInterface::callWithTimeout() } // Now using generated code - com::trolltech::QtDBus::Pinger p(server_serviceName, server_objectPath, QDBusConnection::sessionBus()); + org::qtproject::QtDBus::Pinger p(server_serviceName, server_objectPath, QDBusConnection::sessionBus()); { // Call with no timeout QDBusReply<int> reply = p.sleepMethod(100); diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 2cd5216c59..7fdb2f4cba 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -728,6 +728,24 @@ void tst_QImage::convertToFormat_data() << int(QImage::Format_RGB888) << 0xffffffffu; QTest::newRow("semiblack pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u << int(QImage::Format_RGB888) << 0xff000000u; + + QTest::newRow("red rgba8888 -> argb32") << int(QImage::Format_RGBA8888) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green rgba8888 -> argb32") << int(QImage::Format_RGBA8888) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue rgba8888 -> argb32") << int(QImage::Format_RGBA8888) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + + QTest::newRow("semired rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7fff0000u + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u; + QTest::newRow("semigreen rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7f00ff00u + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u; + QTest::newRow("semiblue rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7f0000ffu + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu; + QTest::newRow("semiwhite rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7fffffffu + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu; + QTest::newRow("semiblack rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7f000000u + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u; } @@ -953,6 +971,10 @@ void tst_QImage::rotate_data() << QImage::Format_RGB888 << d; QTest::newRow(qPrintable(title.arg("Format_Indexed8"))) << QImage::Format_Indexed8 << d; + QTest::newRow(qPrintable(title.arg("Format_RGBX8888"))) + << QImage::Format_RGBX8888 << d; + QTest::newRow(qPrintable(title.arg("Format_RGBA8888_Premultiplied"))) + << QImage::Format_RGBA8888_Premultiplied << d; } } @@ -1161,6 +1183,21 @@ void tst_QImage::setPixel_data() << 0xff00ff00 << 0x00ff00u; QTest::newRow("RGB888 blue") << int(QImage::Format_RGB888) << 0xff0000ff << 0x0000ffu; +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + QTest::newRow("RGBA8888 red") << int(QImage::Format_RGBA8888) + << 0xffff0000u << 0xff0000ffu; + QTest::newRow("RGBA8888 green") << int(QImage::Format_RGBA8888) + << 0xff00ff00u << 0x00ff00ffu; + QTest::newRow("RGBA8888 blue") << int(QImage::Format_RGBA8888) + << 0xff0000ffu << 0x0000ffffu; +#else + QTest::newRow("RGBA8888 red") << int(QImage::Format_RGBA8888) + << 0xffff0000u << 0xff0000ffu; + QTest::newRow("RGBA8888 green") << int(QImage::Format_RGBA8888) + << 0xff00ff00u << 0xff00ff00u; + QTest::newRow("RGBA8888 blue") << int(QImage::Format_RGBA8888) + << 0xff0000ffu << 0xffff0000u; +#endif } void tst_QImage::setPixel() @@ -1184,6 +1221,9 @@ void tst_QImage::setPixel() case int(QImage::Format_RGB32): case int(QImage::Format_ARGB32): case int(QImage::Format_ARGB32_Premultiplied): + case int(QImage::Format_RGBX8888): + case int(QImage::Format_RGBA8888): + case int(QImage::Format_RGBA8888_Premultiplied): { for (int y = 0; y < h; ++y) { const quint32 *row = (const quint32*)(img.scanLine(y)); @@ -1901,6 +1941,8 @@ void tst_QImage::fillColor_data() "RGB888", "RGB444", "ARGB4444pm", + "RGBx8888", + "RGBA8888pm", 0 }; @@ -1917,7 +1959,9 @@ void tst_QImage::fillColor_data() QImage::Format_ARGB8555_Premultiplied, QImage::Format_RGB888, QImage::Format_RGB444, - QImage::Format_ARGB4444_Premultiplied + QImage::Format_ARGB4444_Premultiplied, + QImage::Format_RGBX8888, + QImage::Format_RGBA8888_Premultiplied, }; for (int i=0; names[i] != 0; ++i) { @@ -1935,6 +1979,7 @@ void tst_QImage::fillColor_data() QTest::newRow("RGB32, transparent") << QImage::Format_RGB32 << Qt::transparent << 0xff000000; QTest::newRow("ARGB32, transparent") << QImage::Format_ARGB32 << Qt::transparent << 0x00000000u; QTest::newRow("ARGB32pm, transparent") << QImage::Format_ARGB32_Premultiplied << Qt::transparent << 0x00000000u; + QTest::newRow("RGBA8888pm, transparent") << QImage::Format_RGBA8888_Premultiplied << Qt::transparent << 0x00000000u; } void tst_QImage::fillColor() @@ -2013,6 +2058,8 @@ void tst_QImage::rgbSwapped_data() QTest::newRow("Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; QTest::newRow("Format_RGB888") << QImage::Format_RGB888; QTest::newRow("Format_RGB444") << QImage::Format_RGB444; + QTest::newRow("Format_RGBX8888") << QImage::Format_RGBX8888; + QTest::newRow("Format_RGBA8888_Premultiplied") << QImage::Format_RGBA8888_Premultiplied; } void tst_QImage::rgbSwapped() diff --git a/tests/auto/gui/kernel/qbackingstore/qbackingstore.pro b/tests/auto/gui/kernel/qbackingstore/qbackingstore.pro index c3113ed4b1..211be4c1c0 100644 --- a/tests/auto/gui/kernel/qbackingstore/qbackingstore.pro +++ b/tests/auto/gui/kernel/qbackingstore/qbackingstore.pro @@ -1,5 +1,4 @@ CONFIG += testcase -CONFIG += parallel_test TARGET = tst_qbackingstore QT += core-private gui-private testlib diff --git a/tests/auto/gui/kernel/qinputmethod/qinputmethod.pro b/tests/auto/gui/kernel/qinputmethod/qinputmethod.pro index ff491c1e25..015cc782eb 100644 --- a/tests/auto/gui/kernel/qinputmethod/qinputmethod.pro +++ b/tests/auto/gui/kernel/qinputmethod/qinputmethod.pro @@ -1,5 +1,4 @@ CONFIG += testcase -CONFIG += parallel_test TARGET = tst_qinputmethod SOURCES += tst_qinputmethod.cpp QT += core-private gui-private testlib diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp index 6fe7961545..1b1f5575b1 100644 --- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp +++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp @@ -61,6 +61,8 @@ private slots: void name_data(); void name(); + void namehex_data(); + void namehex(); void setNamedColor(); void constructNamedColorWithSpace(); @@ -254,36 +256,75 @@ void tst_QColor::isValid() QVERIFY(color.isValid() == isValid); } +Q_DECLARE_METATYPE(QColor::NameFormat); + void tst_QColor::name_data() { QTest::addColumn<QColor>("color"); QTest::addColumn<QString>("name"); - - QTest::newRow("invalid") << QColor() << "#000000"; - QTest::newRow("global color black") << QColor(Qt::black) << "#000000"; - QTest::newRow("global color white") << QColor(Qt::white) << "#ffffff"; - QTest::newRow("global color darkGray") << QColor(Qt::darkGray) << "#808080"; - QTest::newRow("global color gray") << QColor(Qt::gray) << "#a0a0a4"; - QTest::newRow("global color lightGray") << QColor(Qt::lightGray) << "#c0c0c0"; - QTest::newRow("global color red") << QColor(Qt::red) << "#ff0000"; - QTest::newRow("global color green") << QColor(Qt::green) << "#00ff00"; - QTest::newRow("global color blue") << QColor(Qt::blue) << "#0000ff"; - QTest::newRow("global color cyan") << QColor(Qt::cyan) << "#00ffff"; - QTest::newRow("global color magenta") << QColor(Qt::magenta) << "#ff00ff"; - QTest::newRow("global color yellow") << QColor(Qt::yellow) << "#ffff00"; - QTest::newRow("global color darkRed") << QColor(Qt::darkRed) << "#800000"; - QTest::newRow("global color darkGreen") << QColor(Qt::darkGreen) << "#008000"; - QTest::newRow("global color darkBlue") << QColor(Qt::darkBlue) << "#000080"; - QTest::newRow("global color darkCyan") << QColor(Qt::darkCyan) << "#008080"; - QTest::newRow("global color darkMagenta") << QColor(Qt::darkMagenta) << "#800080"; - QTest::newRow("global color darkYellow") << QColor(Qt::darkYellow) << "#808000"; + QTest::addColumn<QColor::NameFormat>("nameFormat"); + + QTest::newRow("invalid") << QColor() << "#000000" << QColor::HexRgb; + QTest::newRow("global color black") << QColor(Qt::black) << "#000000" << QColor::HexRgb; + QTest::newRow("global color white") << QColor(Qt::white) << "#ffffff" << QColor::HexRgb; + QTest::newRow("global color darkGray") << QColor(Qt::darkGray) << "#808080" << QColor::HexRgb; + QTest::newRow("global color gray") << QColor(Qt::gray) << "#a0a0a4" << QColor::HexRgb; + QTest::newRow("global color lightGray") << QColor(Qt::lightGray) << "#c0c0c0" << QColor::HexRgb; + QTest::newRow("global color red") << QColor(Qt::red) << "#ff0000" << QColor::HexRgb; + QTest::newRow("global color green") << QColor(Qt::green) << "#00ff00" << QColor::HexRgb; + QTest::newRow("global color blue") << QColor(Qt::blue) << "#0000ff" << QColor::HexRgb; + QTest::newRow("global color cyan") << QColor(Qt::cyan) << "#00ffff" << QColor::HexRgb; + QTest::newRow("global color magenta") << QColor(Qt::magenta) << "#ff00ff" << QColor::HexRgb; + QTest::newRow("global color yellow") << QColor(Qt::yellow) << "#ffff00" << QColor::HexRgb; + QTest::newRow("global color darkRed") << QColor(Qt::darkRed) << "#800000" << QColor::HexRgb; + QTest::newRow("global color darkGreen") << QColor(Qt::darkGreen) << "#008000" << QColor::HexRgb; + QTest::newRow("global color darkBlue") << QColor(Qt::darkBlue) << "#000080" << QColor::HexRgb; + QTest::newRow("global color darkCyan") << QColor(Qt::darkCyan) << "#008080" << QColor::HexRgb; + QTest::newRow("global color darkMagenta") << QColor(Qt::darkMagenta) << "#800080" << QColor::HexRgb; + QTest::newRow("global color darkYellow") << QColor(Qt::darkYellow) << "#808000" << QColor::HexRgb; + QTest::newRow("transparent red") << QColor(255, 0, 0, 102) << "#66ff0000" << QColor::HexArgb; } void tst_QColor::name() { QFETCH(QColor, color); QFETCH(QString, name); - QCOMPARE(color.name(), name); + QFETCH(QColor::NameFormat, nameFormat); + QCOMPARE(color.name(nameFormat), name); +} + +void tst_QColor::namehex_data() +{ + QTest::addColumn<QString>("hexcolor"); + QTest::addColumn<QColor>("color"); + + QTest::newRow("global color black") << "#000000" << QColor(Qt::black); + QTest::newRow("global color white") << "#ffffff" << QColor(Qt::white); + QTest::newRow("global color darkGray") << "#808080" << QColor(Qt::darkGray); + QTest::newRow("global color gray") << "#a0a0a4" << QColor(Qt::gray); + QTest::newRow("global color lightGray") << "#c0c0c0" << QColor(Qt::lightGray); + QTest::newRow("global color red") << "#ff0000" << QColor(Qt::red); + QTest::newRow("global color green") << "#00ff00" << QColor(Qt::green); + QTest::newRow("global color blue") << "#0000ff" << QColor(Qt::blue); + QTest::newRow("global color cyan") << "#00ffff" << QColor(Qt::cyan); + QTest::newRow("global color magenta") << "#ff00ff" << QColor(Qt::magenta); + QTest::newRow("global color yellow") << "#ffff00" << QColor(Qt::yellow); + QTest::newRow("global color darkRed") << "#800000" << QColor(Qt::darkRed); + QTest::newRow("global color darkGreen") << "#008000" << QColor(Qt::darkGreen); + QTest::newRow("global color darkBlue") << "#000080" << QColor(Qt::darkBlue); + QTest::newRow("global color darkCyan") << "#008080" << QColor(Qt::darkCyan); + QTest::newRow("global color darkMagenta") << "#800080" << QColor(Qt::darkMagenta); + QTest::newRow("global color darkYellow") << "#808000" << QColor(Qt::darkYellow); + QTest::newRow("transparent red") << "#66ff0000" << QColor(255, 0, 0, 102); + QTest::newRow("invalid red") << "#gg0000" << QColor(); + QTest::newRow("invalid transparent") << "#gg00ff00" << QColor(); +} + +void tst_QColor::namehex() +{ + QFETCH(QString, hexcolor); + QFETCH(QColor, color); + QCOMPARE(QColor(hexcolor), color); } void tst_QColor::globalColors_data() diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index 4f1213dff9..5a1ca855a1 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -122,10 +122,15 @@ private slots: void drawRect(); void drawRect2(); + void fillRect_data(); void fillRect(); + void fillRect2_data(); void fillRect2(); + void fillRect3_data() { fillRect2_data(); } void fillRect3(); + void fillRect4_data() { fillRect2_data(); } void fillRect4(); + void fillRectNonPremul(); void drawEllipse_data(); void drawEllipse(); @@ -1079,9 +1084,19 @@ void tst_QPainter::drawRect2() } } +void tst_QPainter::fillRect_data() +{ + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("argb32pm") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("rgba8888pm") << QImage::Format_RGBA8888_Premultiplied; +} + void tst_QPainter::fillRect() { - QImage image(100, 100, QImage::Format_ARGB32_Premultiplied); + QFETCH(QImage::Format, format); + + QImage image(100, 100, format); image.fill(QColor(0, 0, 0, 0).rgba()); QPainter p(&image); @@ -1103,17 +1118,29 @@ void tst_QPainter::fillRect() QRect(0, 0, 50, 100)); } +void tst_QPainter::fillRect2_data() +{ + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("argb32") << QImage::Format_ARGB32; + QTest::newRow("argb32pm") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("rgba8888") << QImage::Format_RGBA8888; + QTest::newRow("rgba8888pm") << QImage::Format_RGBA8888_Premultiplied; +} + void tst_QPainter::fillRect2() { + QFETCH(QImage::Format, format); + QRgb background = 0x0; - QImage img(1, 20, QImage::Format_ARGB32_Premultiplied); + QImage img(1, 20, format); img.fill(background); QPainter p(&img); QRectF rect(0, 1, 1.2, 18); - p.fillRect(rect, Qt::black); + p.fillRect(rect, Qt::yellow); p.end(); @@ -1122,11 +1149,14 @@ void tst_QPainter::fillRect2() QCOMPARE(img.pixel(0, 1), img.pixel(0, 2)); QCOMPARE(img.pixel(0, img.height() - 2), img.pixel(0, img.height() - 3)); + QCOMPARE(img.pixel(0, 1), QColor(Qt::yellow).rgba()); } void tst_QPainter::fillRect3() { - QImage img(1, 1, QImage::Format_ARGB32_Premultiplied); + QFETCH(QImage::Format, format); + + QImage img(1, 1, format); img.fill(QColor(Qt::black).rgba()); QPainter p(&img); @@ -1139,7 +1169,9 @@ void tst_QPainter::fillRect3() void tst_QPainter::fillRect4() { - QImage image(100, 1, QImage::Format_ARGB32_Premultiplied); + QFETCH(QImage::Format, format); + + QImage image(100, 1, format); image.fill(0x0); QImage expected = image; @@ -1157,6 +1189,24 @@ void tst_QPainter::fillRect4() QCOMPARE(image, expected); } +void tst_QPainter::fillRectNonPremul() +{ + QImage img1(1, 1, QImage::Format_ARGB32); + QImage img2(1, 1, QImage::Format_RGBA8888); + + QPainter p1(&img1); + QPainter p2(&img2); + + QRectF rect(0, 0, 1, 1); + p1.fillRect(rect, qRgba(31, 63, 127, 127)); + p2.fillRect(rect, qRgba(31, 63, 127, 127)); + + p1.end(); + p2.end(); + + QCOMPARE(img1.pixel(0, 0), img2.pixel(0,0)); +} + void tst_QPainter::drawPath_data() { QTest::addColumn<QPainterPath>("path"); @@ -2265,6 +2315,27 @@ void tst_QPainter::setOpacity_data() QTest::newRow("RGB444 on RGB444") << QImage::Format_RGB444 << QImage::Format_RGB444; + + QTest::newRow("RGBA8888P on RGBA8888P") << QImage::Format_RGBA8888_Premultiplied + << QImage::Format_RGBA8888_Premultiplied; + + QTest::newRow("RGBA8888 on RGBA8888") << QImage::Format_RGBA8888 + << QImage::Format_RGBA8888; + + QTest::newRow("RGBx8888 on RGBx8888") << QImage::Format_RGBX8888 + << QImage::Format_RGBX8888; + + QTest::newRow("RGBA8888P on ARGB32P") << QImage::Format_RGBA8888_Premultiplied + << QImage::Format_ARGB32_Premultiplied; + + QTest::newRow("RGBx8888 on ARGB32P") << QImage::Format_RGBX8888 + << QImage::Format_ARGB32_Premultiplied; + + QTest::newRow("ARGB32P on RGBA8888P") << QImage::Format_ARGB32_Premultiplied + << QImage::Format_RGBA8888_Premultiplied; + + QTest::newRow("RGB32 on RGBx8888") << QImage::Format_RGB32 + << QImage::Format_RGBX8888; } void tst_QPainter::setOpacity() diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp index ca6c42c9bd..86e282fad2 100644 --- a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp +++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp @@ -344,8 +344,6 @@ void tst_QCssParser::term_data() val.variant = QVariant(QColor("#ffbb00")); QTest::newRow("hexcolor2") << true << "#fb0" << val; - QTest::newRow("hexcolor_failure") << false << "#cafebabe" << val; - val.type = QCss::Value::Uri; val.variant = QString("www.kde.org"); QTest::newRow("uri1") << true << "url(\"www.kde.org\")" << val; @@ -367,9 +365,6 @@ void tst_QCssParser::term() QFETCH(QString, css); QFETCH(QCss::Value, expectedValue); - if (strcmp(QTest::currentDataTag(), "hexcolor_failure") == 0) - QTest::ignoreMessage(QtWarningMsg, "QCssParser::parseHexColor: Unknown color name '#cafebabe'"); - QCss::Parser parser(css); QCss::Value val; QVERIFY(parser.testTerm()); diff --git a/tests/auto/gui/text/qfontdatabase/qfontdatabase.pro b/tests/auto/gui/text/qfontdatabase/qfontdatabase.pro index 37868dcfde..6975c4088b 100644 --- a/tests/auto/gui/text/qfontdatabase/qfontdatabase.pro +++ b/tests/auto/gui/text/qfontdatabase/qfontdatabase.pro @@ -2,8 +2,7 @@ CONFIG += testcase CONFIG += parallel_test TARGET = tst_qfontdatabase SOURCES += tst_qfontdatabase.cpp -QT += testlib -!mac: QT += core-private gui-private +QT += testlib core-private gui-private wince* { additionalFiles.files = FreeMono.ttf diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index 9cf4082287..104d3465f2 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -44,6 +44,7 @@ #include <qfontdatabase.h> #include <qfontinfo.h> #include <qfontmetrics.h> +#include <qpa/qplatformfontdatabase.h> class tst_QFontDatabase : public QObject { @@ -252,11 +253,8 @@ void tst_QFontDatabase::addAppFont() return; #endif QCOMPARE(fontDbChangedSpy.count(), 1); -// addApplicationFont is supported on Mac, don't skip the test if it breaks. -#ifndef Q_OS_MAC if (id == -1) QSKIP("Skip the test since app fonts are not supported on this system"); -#endif const QStringList addedFamilies = QFontDatabase::applicationFontFamilies(id); QVERIFY(!addedFamilies.isEmpty()); @@ -271,16 +269,9 @@ void tst_QFontDatabase::addAppFont() QVERIFY(QFontDatabase::removeApplicationFont(id)); QCOMPARE(fontDbChangedSpy.count(), 2); -#ifdef Q_OS_MAC - QEXPECT_FAIL("font file", "QTBUG-23062", Continue); -#endif QCOMPARE(db.families(), oldFamilies); } -QT_BEGIN_NAMESPACE -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); -QT_END_NAMESPACE - void tst_QFontDatabase::aliases() { QFontDatabase db; @@ -290,7 +281,7 @@ void tst_QFontDatabase::aliases() QVERIFY(db.hasFamily(firstFont)); const QString alias = QStringLiteral("AliasToFirstFont") + firstFont; QVERIFY(!db.hasFamily(alias)); - qt_registerAliasToFontFamily(firstFont, alias); + QPlatformFontDatabase::registerAliasToFontFamily(firstFont, alias); QVERIFY(db.hasFamily(alias)); } diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp index 25301feee4..125eab2f8c 100644 --- a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp +++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp @@ -77,30 +77,43 @@ void tst_QNetworkAccessManager::networkAccessible() QSignalSpy spy(&manager, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility))); - QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::UnknownAccessibility); + // if there is no session, we cannot know in which state we are in + QNetworkAccessManager::NetworkAccessibility initialAccessibility = + manager.networkAccessible(); + QCOMPARE(manager.networkAccessible(), initialAccessibility); manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible); - QCOMPARE(spy.count(), 1); - QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), - QNetworkAccessManager::NotAccessible); + int expectedCount = (initialAccessibility == QNetworkAccessManager::Accessible) ? 1 : 0; + QCOMPARE(spy.count(), expectedCount); + if (expectedCount > 0) + QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), + QNetworkAccessManager::NotAccessible); QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible); manager.setNetworkAccessible(QNetworkAccessManager::Accessible); - QCOMPARE(spy.count(), 1); - QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), - QNetworkAccessManager::UnknownAccessibility); - QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::UnknownAccessibility); + QCOMPARE(spy.count(), expectedCount); + if (expectedCount > 0) + QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), + initialAccessibility); + QCOMPARE(manager.networkAccessible(), initialAccessibility); QNetworkConfigurationManager configManager; + bool sessionRequired = (configManager.capabilities() + & QNetworkConfigurationManager::NetworkSessionRequired); QNetworkConfiguration defaultConfig = configManager.defaultConfiguration(); if (defaultConfig.isValid()) { manager.setConfiguration(defaultConfig); - QCOMPARE(spy.count(), 1); - QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), - QNetworkAccessManager::Accessible); + // the accessibility has not changed if no session is required + if (sessionRequired) { + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), + QNetworkAccessManager::Accessible); + } else { + QCOMPARE(spy.count(), 0); + } QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible); manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index ce8293edbc..eb9ad81101 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -368,6 +368,8 @@ private Q_SLOTS: #ifdef QT_BUILD_INTERNAL void sslSessionSharing_data(); void sslSessionSharing(); + void sslSessionSharingFromPersistentSession_data(); + void sslSessionSharingFromPersistentSession(); #endif #endif @@ -5964,7 +5966,7 @@ void tst_QNetworkReply::sslSessionSharing() warmupRequest.setAttribute(QNetworkRequest::User, sessionSharingEnabled); // so we can read it from the slot if (! sessionSharingEnabled) { QSslConfiguration configuration(QSslConfiguration::defaultConfiguration()); - configuration.setSslOption(QSsl::SslOptionDisableSessionTickets, true); + configuration.setSslOption(QSsl::SslOptionDisableSessionSharing, true); warmupRequest.setSslConfiguration(configuration); } QNetworkReply *reply = manager.get(warmupRequest); @@ -6010,6 +6012,63 @@ void tst_QNetworkReply::sslSessionSharingHelperSlot() } } +void tst_QNetworkReply::sslSessionSharingFromPersistentSession_data() +{ + QTest::addColumn<bool>("sessionPersistenceEnabled"); + QTest::newRow("enabled") << true; + QTest::newRow("disabled") << false; +} + +void tst_QNetworkReply::sslSessionSharingFromPersistentSession() +{ + QString urlString("https://" + QtNetworkSettings::serverName()); + + // warm up SSL session cache to get a working session + QNetworkRequest warmupRequest(urlString); + QFETCH(bool, sessionPersistenceEnabled); + if (sessionPersistenceEnabled) { + QSslConfiguration warmupConfiguration(QSslConfiguration::defaultConfiguration()); + warmupConfiguration.setSslOption(QSsl::SslOptionDisableSessionPersistence, false); + warmupRequest.setSslConfiguration(warmupConfiguration); + } + QNetworkReply *warmupReply = manager.get(warmupRequest); + warmupReply->ignoreSslErrors(); + connect(warmupReply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(20); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(warmupReply->error(), QNetworkReply::NoError); + QByteArray sslSession = warmupReply->sslConfiguration().session(); + QCOMPARE(!sslSession.isEmpty(), sessionPersistenceEnabled); + + // test server sends a life time hint of 0, which is not common + // practice; however it is good enough because the default is -1 + int expectedSessionTicketLifeTimeHint = sessionPersistenceEnabled ? 0 : -1; + QCOMPARE(warmupReply->sslConfiguration().sessionTicketLifeTimeHint(), + expectedSessionTicketLifeTimeHint); + + warmupReply->deleteLater(); + + // now send another request with a new QNAM and the persisted session, + // to verify it can be resumed without any internal state + QNetworkRequest request(warmupRequest); + if (sessionPersistenceEnabled) { + QSslConfiguration configuration = request.sslConfiguration(); + configuration.setSession(sslSession); + request.setSslConfiguration(configuration); + } + QNetworkAccessManager newManager; + QNetworkReply *reply = newManager.get(request); + reply->ignoreSslErrors(); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(20); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + bool sslSessionSharingWasUsedInReply = QSslConfigurationPrivate::peerSessionWasShared( + reply->sslConfiguration()); + QCOMPARE(sessionPersistenceEnabled, sslSessionSharingWasUsedInReply); +} + #endif // QT_BUILD_INTERNAL #endif // QT_NO_SSL diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp index 40f22d6d1e..f474f97f5d 100644 --- a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp @@ -56,6 +56,10 @@ #include <sys/socket.h> #endif +#ifdef Q_OS_VXWORKS +#include <sockLib.h> +#endif + #include <stddef.h> #define PLATFORMSOCKETENGINE QNativeSocketEngine diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index 2b9dfc5081..ee5c7e42d8 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -513,7 +513,7 @@ void tst_QTcpSocket::bind() { QFETCH_GLOBAL(bool, setProxy); if (setProxy) - QSKIP("QTBUG-22964"); + return; // QTBUG-22964 for proxies, QTBUG-29972 for QSKIP QFETCH(QString, stringAddr); QFETCH(bool, successExpected); QFETCH(QString, stringExpectedLocalAddress); diff --git a/tests/auto/other/exceptionsafety/.gitignore b/tests/auto/other/exceptionsafety/.gitignore deleted file mode 100644 index 9a854c4c26..0000000000 --- a/tests/auto/other/exceptionsafety/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_exceptionsafety diff --git a/tests/auto/other/exceptionsafety/exceptionsafety.pro b/tests/auto/other/exceptionsafety/exceptionsafety.pro deleted file mode 100644 index 3e9c996cd8..0000000000 --- a/tests/auto/other/exceptionsafety/exceptionsafety.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase -TARGET = tst_exceptionsafety -SOURCES += tst_exceptionsafety.cpp -QT = core testlib -CONFIG += parallel_test insignificant_test -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/other/exceptionsafety/tst_exceptionsafety.cpp b/tests/auto/other/exceptionsafety/tst_exceptionsafety.cpp deleted file mode 100644 index 94360adb0e..0000000000 --- a/tests/auto/other/exceptionsafety/tst_exceptionsafety.cpp +++ /dev/null @@ -1,846 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qplatformdefs.h" -#include <stdlib.h> - -void* internalMalloc(size_t bytes); -#define malloc internalMalloc -#include <QVarLengthArray> -#undef malloc - -#include <QtTest/QtTest> - -QT_USE_NAMESPACE - -class tst_ExceptionSafety: public QObject -{ - Q_OBJECT -private slots: -#ifdef QT_NO_EXCEPTIONS - void initTestCase(); -#else - void exceptionInSlot(); - void exceptionVector(); - void exceptionHash(); - void exceptionMap(); - void exceptionList(); - void exceptionLinkedList(); -// void exceptionEventLoop(); -// void exceptionSignalSlot(); - void exceptionOOMQVarLengthArray(); -#endif -}; - -#ifdef QT_NO_EXCEPTIONS -void tst_ExceptionSafety::initTestCase() -{ - QSKIP("This test requires exception support"); -} - -#else - -class Emitter : public QObject -{ - Q_OBJECT -public: - inline void emitTestSignal() { emit testSignal(); } -signals: - void testSignal(); -}; - -class ExceptionThrower : public QObject -{ - Q_OBJECT -public slots: - void thrower() { throw 5; } -}; - -class Receiver : public QObject -{ - Q_OBJECT -public: - Receiver() - : received(0) {} - int received; - -public slots: - void receiver() { ++received; } -}; - -enum ThrowType { ThrowNot = 0, ThrowAtCreate = 1, ThrowAtCopy = 2, ThrowLater = 3, ThrowAtComparison = 4 }; - -ThrowType throwType = ThrowNot; // global flag to indicate when an exception should be throw. Will be reset when the exception has been generated. - -int objCounter = 0; - -/*! Class that does not throw any exceptions. Used as baseclass for all the other ones. - */ -template <int T> -class FlexibleThrower -{ - public: - FlexibleThrower() : _value(-1) { - if( throwType == ThrowAtCreate ) { - throwType = ThrowNot; - throw ThrowAtCreate; - } - objCounter++; - } - - FlexibleThrower( short value ) : _value(value) { - if( throwType == ThrowAtCreate ) { - throwType = ThrowNot; - throw ThrowAtCreate; - } - objCounter++; - } - - FlexibleThrower(FlexibleThrower const& other ) { - // qDebug("cc"); - - if( throwType == ThrowAtCopy ) { - throwType = ThrowNot; - throw ThrowAtCopy; - - } else if( throwType == ThrowLater ) { - throwType = ThrowAtCopy; - } - - objCounter++; - _value = other.value(); - } - - ~FlexibleThrower() { objCounter--; } - - bool operator==(const FlexibleThrower<T> &t) const - { - // qDebug("vv == %d %d", value(), t.value()); - if( throwType == ThrowAtComparison ) { - throwType = ThrowNot; - throw ThrowAtComparison; - } - return value()==t.value(); - } - - bool operator<(const FlexibleThrower<T> &t) const - { - // qDebug("vv < %d %d", value(), t.value()); - if( throwType == ThrowAtComparison ) { - throwType = ThrowNot; - throw ThrowAtComparison; - } - return value()<t.value(); - } - - int value() const - { return (int)_value; } - - short _value; - char dummy[T]; -}; - -uint qHash(const FlexibleThrower<2>& t) -{ - // qDebug("ha"); - if( throwType == ThrowAtComparison ) { - throwType = ThrowNot; - throw ThrowAtComparison; - } - return (uint)t.value(); -} - -typedef FlexibleThrower<2> FlexibleThrowerSmall; -typedef QMap<FlexibleThrowerSmall,FlexibleThrowerSmall> MyMap; -typedef QHash<FlexibleThrowerSmall,FlexibleThrowerSmall> MyHash; - -// connect a signal to a slot that throws an exception -// run this through valgrind to make sure it doesn't corrupt -void tst_ExceptionSafety::exceptionInSlot() -{ - Emitter emitter; - ExceptionThrower thrower; - - connect(&emitter, SIGNAL(testSignal()), &thrower, SLOT(thrower())); - - try { - emitter.emitTestSignal(); - } catch (int i) { - QCOMPARE(i, 5); - } -} - -void tst_ExceptionSafety::exceptionList() -{ - const int intancesCount = objCounter; - { - int instances; - QList<FlexibleThrowerSmall> list; - QList<FlexibleThrowerSmall> list2; - QList<FlexibleThrowerSmall> list3; - - for( int i = 0; i<10; i++ ) - list.append( FlexibleThrowerSmall(i) ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list.append( FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list.prepend( FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.at(0).value(), 0 ); - QCOMPARE( list.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list.insert( 8, FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.at(7).value(), 7 ); - QCOMPARE( list.at(8).value(), 8 ); - QCOMPARE( list.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - FlexibleThrowerSmall t = list.takeAt( 6 ); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.at(6).value(), 6 ); - QCOMPARE( list.at(7).value(), 7 ); - QCOMPARE( list.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list3 = list; - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.at(0).value(), 0 ); - QCOMPARE( list.at(7).value(), 7 ); - QCOMPARE( list.size(), 10 ); - QCOMPARE( list3.at(0).value(), 0 ); - QCOMPARE( list3.at(7).value(), 7 ); - QCOMPARE( list3.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list3.append( FlexibleThrowerSmall(11) ); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.at(0).value(), 0 ); - QCOMPARE( list.at(7).value(), 7 ); - QCOMPARE( list.size(), 10 ); - QCOMPARE( list3.at(0).value(), 0 ); - QCOMPARE( list3.at(7).value(), 7 ); - QCOMPARE( list3.size(), 10 ); - - try { - list2.clear(); - list2.append( FlexibleThrowerSmall(11)); - throwType = ThrowAtCopy; - instances = objCounter; - list3 = list+list2; - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.at(0).value(), 0 ); - QCOMPARE( list.at(7).value(), 7 ); - QCOMPARE( list.size(), 10 ); - - // check that copy on write works atomar - list2.clear(); - list2.append( FlexibleThrowerSmall(11)); - list3 = list+list2; - instances = objCounter; - try { - throwType = ThrowAtCreate; - list3[7]=FlexibleThrowerSmall(12); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.at(7).value(), 7 ); - QCOMPARE( list.size(), 10 ); - QCOMPARE( list3.at(7).value(), 7 ); - QCOMPARE( list3.size(), 11 ); - - } - QCOMPARE(objCounter, intancesCount); // check that every object has been freed -} - -void tst_ExceptionSafety::exceptionLinkedList() -{ - const int intancesCount = objCounter; - { - int instances; - QLinkedList<FlexibleThrowerSmall> list; - QLinkedList<FlexibleThrowerSmall> list2; - QLinkedList<FlexibleThrowerSmall> list3; - - for( int i = 0; i<10; i++ ) - list.append( FlexibleThrowerSmall(i) ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list.append( FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list.prepend( FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.first().value(), 0 ); - QCOMPARE( list.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - list3 = list; - list3.append( FlexibleThrowerSmall(11) ); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( list.first().value(), 0 ); - QCOMPARE( list.size(), 10 ); - QCOMPARE( list3.size(), 10 ); - } - QCOMPARE(objCounter, intancesCount); // check that every object has been freed -} - -void tst_ExceptionSafety::exceptionVector() -{ - const int intancesCount = objCounter; - { - int instances; - QVector<FlexibleThrowerSmall> vector; - QVector<FlexibleThrowerSmall> vector2; - QVector<FlexibleThrowerSmall> vector3; - - for (int i = 0; i<10; i++) - vector.append( FlexibleThrowerSmall(i) ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - vector.append( FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - vector.prepend( FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(0).value(), 0 ); - QCOMPARE( vector.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - vector.insert( 8, FlexibleThrowerSmall(10)); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(7).value(), 7 ); - QCOMPARE( vector.at(8).value(), 8 ); - QCOMPARE( vector.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - vector3 = vector; - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(0).value(), 0 ); - QCOMPARE( vector.at(7).value(), 7 ); - QCOMPARE( vector.size(), 10 ); - QCOMPARE( vector3.at(0).value(), 0 ); - QCOMPARE( vector3.at(7).value(), 7 ); - QCOMPARE( vector3.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCopy; - vector3.append( FlexibleThrowerSmall(11) ); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(0).value(), 0 ); - QCOMPARE( vector.at(7).value(), 7 ); - QCOMPARE( vector.size(), 10 ); - QCOMPARE( vector3.at(0).value(), 0 ); - QCOMPARE( vector3.at(7).value(), 7 ); - - try { - vector2.clear(); - vector2.append( FlexibleThrowerSmall(11)); - instances = objCounter; - throwType = ThrowAtCopy; - vector3 = vector+vector2; - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(0).value(), 0 ); - QCOMPARE( vector.at(7).value(), 7 ); - QCOMPARE( vector.size(), 10 ); - - // check that copy on write works atomar - vector2.clear(); - vector2.append( FlexibleThrowerSmall(11)); - vector3 = vector+vector2; - instances = objCounter; - try { - throwType = ThrowAtCreate; - vector3[7]=FlexibleThrowerSmall(12); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(7).value(), 7 ); - QCOMPARE( vector.size(), 10 ); - QCOMPARE( vector3.at(7).value(), 7 ); - QCOMPARE( vector3.size(), 11 ); - - instances = objCounter; - try { - throwType = ThrowAtCreate; - vector.resize(15); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(7).value(), 7 ); - QCOMPARE( vector.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowAtCreate; - vector.resize(15); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(7).value(), 7 ); - QCOMPARE( vector.size(), 10 ); - - instances = objCounter; - try { - throwType = ThrowLater; - vector.fill(FlexibleThrowerSmall(1), 15); - } catch (...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( vector.at(0).value(), 0 ); - QCOMPARE( vector.size(), 10 ); - } - QCOMPARE(objCounter, intancesCount); // check that every object has been freed -} - - -void tst_ExceptionSafety::exceptionMap() -{ - const int intancesCount = objCounter; - { - int instances; - MyMap map; - MyMap map2; - MyMap map3; - - throwType = ThrowNot; - for (int i = 0; i<10; i++) - map[ FlexibleThrowerSmall(i) ] = FlexibleThrowerSmall(i); - - return; // further test are deactivated until Map is fixed. - - for( int i = ThrowAtCopy; i<=ThrowAtComparison; i++ ) { - instances = objCounter; - try { - throwType = (ThrowType)i; - map[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); - } catch(...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( map.size(), 10 ); - QCOMPARE( map[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); - } - - map2 = map; - instances = objCounter; - try { - throwType = ThrowLater; - map2[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); - } catch(...) { - QCOMPARE(instances, objCounter); - } - /* qDebug("%d %d", map.size(), map2.size() ); - for( int i=0; i<map.size(); i++ ) - qDebug( "Value at %d: %d",i, map.value(FlexibleThrowerSmall(i), FlexibleThrowerSmall()).value() ); - QCOMPARE( map.value(FlexibleThrowerSmall(1), FlexibleThrowerSmall()), FlexibleThrowerSmall(1) ); - qDebug( "Value at %d: %d",1, map[FlexibleThrowerSmall(1)].value() ); - qDebug("%d %d", map.size(), map2.size() ); - */ - QCOMPARE( map[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); - QCOMPARE( map.size(), 10 ); - QCOMPARE( map2[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); - QCOMPARE( map2.size(), 10 ); - - } - QCOMPARE(objCounter, intancesCount); // check that every object has been freed -} - -void tst_ExceptionSafety::exceptionHash() -{ - const int intancesCount = objCounter; - { - int instances; - MyHash hash; - MyHash hash2; - MyHash hash3; - - for( int i = 0; i<10; i++ ) - hash[ FlexibleThrowerSmall(i) ] = FlexibleThrowerSmall(i); - - for( int i = ThrowAtCopy; i<=ThrowAtComparison; i++ ) { - instances = objCounter; - try { - throwType = (ThrowType)i; - hash[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); - } catch(...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( hash.size(), 10 ); - } - - hash2 = hash; - instances = objCounter; - try { - throwType = ThrowLater; - hash2[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); - } catch(...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( hash[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); - QCOMPARE( hash.size(), 10 ); - QCOMPARE( hash2[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); - QCOMPARE( hash2.size(), 10 ); - - hash2.clear(); - instances = objCounter; - try { - throwType = ThrowLater; - hash2.reserve(30); - } catch(...) { - QCOMPARE(instances, objCounter); - } - QCOMPARE( hash2.size(), 0 ); - - /* - try { - throwType = ThrowAtCopy; - hash.prepend( FlexibleThrowerSmall(10)); - } catch (...) { - } - QCOMPARE( hash.at(0).value(), 0 ); - QCOMPARE( hash.size(), 10 ); - - try { - throwType = ThrowAtCopy; - hash.insert( 8, FlexibleThrowerSmall(10)); - } catch (...) { - } - QCOMPARE( hash.at(7).value(), 7 ); - QCOMPARE( hash.at(8).value(), 8 ); - QCOMPARE( hash.size(), 10 ); - - qDebug("val"); - try { - throwType = ThrowAtCopy; - hash3 = hash; - } catch (...) { - } - QCOMPARE( hash.at(0).value(), 0 ); - QCOMPARE( hash.at(7).value(), 7 ); - QCOMPARE( hash.size(), 10 ); - QCOMPARE( hash3.at(0).value(), 0 ); - QCOMPARE( hash3.at(7).value(), 7 ); - QCOMPARE( hash3.size(), 10 ); - - try { - throwType = ThrowAtCopy; - hash3.append( FlexibleThrowerSmall(11) ); - } catch (...) { - } - QCOMPARE( hash.at(0).value(), 0 ); - QCOMPARE( hash.at(7).value(), 7 ); - QCOMPARE( hash.size(), 10 ); - QCOMPARE( hash3.at(0).value(), 0 ); - QCOMPARE( hash3.at(7).value(), 7 ); - QCOMPARE( hash3.at(11).value(), 11 ); - - try { - hash2.clear(); - hash2.append( FlexibleThrowerSmall(11)); - throwType = ThrowAtCopy; - hash3 = hash+hash2; - } catch (...) { - } - QCOMPARE( hash.at(0).value(), 0 ); - QCOMPARE( hash.at(7).value(), 7 ); - QCOMPARE( hash.size(), 10 ); - - // check that copy on write works atomar - hash2.clear(); - hash2.append( FlexibleThrowerSmall(11)); - hash3 = hash+hash2; - try { - throwType = ThrowAtCopy; - hash3[7]=FlexibleThrowerSmall(12); - } catch (...) { - } - QCOMPARE( hash.at(7).value(), 7 ); - QCOMPARE( hash.size(), 10 ); - QCOMPARE( hash3.at(7).value(), 7 ); - QCOMPARE( hash3.size(), 11 ); - */ - - - } - QCOMPARE(objCounter, intancesCount); // check that every object has been freed -} - -// Disable these tests until the level of exception safety in event loops is clear -#if 0 -enum -{ - ThrowEventId = QEvent::User + 42, - NoThrowEventId = QEvent::User + 43 -}; - -class ThrowEvent : public QEvent -{ -public: - ThrowEvent() - : QEvent(static_cast<QEvent::Type>(ThrowEventId)) - { - } -}; - -class NoThrowEvent : public QEvent -{ -public: - NoThrowEvent() - : QEvent(static_cast<QEvent::Type>(NoThrowEventId)) - {} -}; - -struct IntEx : public std::exception -{ - IntEx(int aEx) : ex(aEx) {} - int ex; -}; - -class TestObject : public QObject -{ -public: - TestObject() - : throwEventCount(0), noThrowEventCount(0) {} - - int throwEventCount; - int noThrowEventCount; - -protected: - bool event(QEvent *event) - { - if (int(event->type()) == ThrowEventId) { - throw IntEx(++throwEventCount); - } else if (int(event->type()) == NoThrowEventId) { - ++noThrowEventCount; - } - return QObject::event(event); - } -}; - -void tst_ExceptionSafety::exceptionEventLoop() -{ - // send an event that throws - TestObject obj; - ThrowEvent throwEvent; - try { - qApp->sendEvent(&obj, &throwEvent); - } catch (IntEx code) { - QCOMPARE(code.ex, 1); - } - QCOMPARE(obj.throwEventCount, 1); - - // post an event that throws - qApp->postEvent(&obj, new ThrowEvent); - - try { - qApp->processEvents(); - } catch (IntEx code) { - QCOMPARE(code.ex, 2); - } - QCOMPARE(obj.throwEventCount, 2); - - // post a normal event, then a throwing event, then a normal event - // run this in valgrind to ensure that it doesn't leak. - - qApp->postEvent(&obj, new NoThrowEvent); - qApp->postEvent(&obj, new ThrowEvent); - qApp->postEvent(&obj, new NoThrowEvent); - - try { - qApp->processEvents(); - } catch (IntEx code) { - QCOMPARE(code.ex, 3); - } - // here, we should have received on non-throwing event and one throwing one - QCOMPARE(obj.throwEventCount, 3); - QCOMPARE(obj.noThrowEventCount, 1); - - // spin the event loop again - qApp->processEvents(); - - // now, we should have received the second non-throwing event - QCOMPARE(obj.noThrowEventCount, 2); -} - -void tst_ExceptionSafety::exceptionSignalSlot() -{ - Emitter e; - ExceptionThrower thrower; - Receiver r1; - Receiver r2; - - // connect a signal to a normal object, a thrower and a normal object again - connect(&e, SIGNAL(testSignal()), &r1, SLOT(receiver())); - connect(&e, SIGNAL(testSignal()), &thrower, SLOT(thrower())); - connect(&e, SIGNAL(testSignal()), &r2, SLOT(receiver())); - - int code = 0; - try { - e.emitTestSignal(); - } catch (int c) { - code = c; - } - - // 5 is the magic number that's thrown by thrower - QCOMPARE(code, 5); - - // assumption: slots are called in the connection order - QCOMPARE(r1.received, 1); - QCOMPARE(r2.received, 0); -} -#endif - - -static bool outOfMemory = false; -void* internalMalloc(size_t bytes) { return outOfMemory ? 0 : malloc(bytes); } - -struct OutOfMemory -{ - OutOfMemory() { outOfMemory = true; } - ~OutOfMemory() { outOfMemory = false; } -}; - -void tst_ExceptionSafety::exceptionOOMQVarLengthArray() -{ -#ifdef QT_NO_EXCEPTIONS - // it will crash by design - Q_STATIC_ASSERT(false); -#else - QVarLengthArray<char> arr0; - int minSize = arr0.capacity(); - - // constructor throws - bool success = false; - try { - OutOfMemory oom; - QVarLengthArray<char> arr(minSize * 2); - } catch (const std::bad_alloc&) { - success = true; - } - QVERIFY(success); - - QVarLengthArray<char> arr; - - // resize throws - success = false; - try { - OutOfMemory oom; - arr.resize(minSize * 2); - } catch(const std::bad_alloc&) { - arr.resize(1); - success = true; - } - QVERIFY(success); -#endif -} - -#endif - -QTEST_MAIN(tst_ExceptionSafety) -#include "tst_exceptionsafety.moc" diff --git a/tests/auto/other/exceptionsafety_objects/3rdparty/memcheck.h b/tests/auto/other/exceptionsafety_objects/3rdparty/memcheck.h deleted file mode 100644 index 72a02ca9ba..0000000000 --- a/tests/auto/other/exceptionsafety_objects/3rdparty/memcheck.h +++ /dev/null @@ -1,319 +0,0 @@ - -/* - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (memcheck.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of MemCheck, a heavyweight Valgrind tool for - detecting memory errors. - - Copyright (C) 2000-2008 Julian Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. 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. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (memcheck.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - - -#ifndef __MEMCHECK_H -#define __MEMCHECK_H - - -/* This file is for inclusion into client (your!) code. - - You can use these macros to manipulate and query memory permissions - inside your own programs. - - See comment near the top of valgrind.h on how to use them. -*/ - -#include "valgrind.h" - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. */ -typedef - enum { - VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'), - VG_USERREQ__MAKE_MEM_UNDEFINED, - VG_USERREQ__MAKE_MEM_DEFINED, - VG_USERREQ__DISCARD, - VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, - VG_USERREQ__CHECK_MEM_IS_DEFINED, - VG_USERREQ__DO_LEAK_CHECK, - VG_USERREQ__COUNT_LEAKS, - - VG_USERREQ__GET_VBITS, - VG_USERREQ__SET_VBITS, - - VG_USERREQ__CREATE_BLOCK, - - VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, - - VG_USERREQ__ENABLE_OOM, - VG_USERREQ__GET_ALLOC_INDEX, - - /* This is just for memcheck's internal use - don't use it */ - _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR - = VG_USERREQ_TOOL_BASE('M','C') + 256, - - /* This is just for memcheck's internal use - don't use it */ - _VG_USERREQ__EXCEPTION - = VG_USERREQ_TOOL_BASE('M','C') + 512, - } Vg_MemCheckClientRequest; - - - -/* Client-code macros to manipulate the state of memory. */ - -/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \ - (__extension__({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__MAKE_MEM_NOACCESS, \ - _qzz_addr, _qzz_len, 0, 0, 0); \ - _qzz_res; \ - })) - -/* Similarly, mark memory at _qzz_addr as addressable but undefined - for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \ - (__extension__({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__MAKE_MEM_UNDEFINED, \ - _qzz_addr, _qzz_len, 0, 0, 0); \ - _qzz_res; \ - })) - -/* Similarly, mark memory at _qzz_addr as addressable and defined - for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \ - (__extension__({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__MAKE_MEM_DEFINED, \ - _qzz_addr, _qzz_len, 0, 0, 0); \ - _qzz_res; \ - })) - -/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is - not altered: bytes which are addressable are marked as defined, - but those which are not addressable are left unchanged. */ -#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \ - (__extension__({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \ - _qzz_addr, _qzz_len, 0, 0, 0); \ - _qzz_res; \ - })) - -/* Create a block-description handle. The description is an ascii - string which is included in any messages pertaining to addresses - within the specified memory range. Has no other effect on the - properties of the memory range. */ -#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \ - (__extension__({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__CREATE_BLOCK, \ - _qzz_addr, _qzz_len, _qzz_desc, \ - 0, 0); \ - _qzz_res; \ - })) - -/* Discard a block-description-handle. Returns 1 for an - invalid handle, 0 for a valid handle. */ -#define VALGRIND_DISCARD(_qzz_blkindex) \ - (__extension__ ({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__DISCARD, \ - 0, _qzz_blkindex, 0, 0, 0); \ - _qzz_res; \ - })) - - -/* Client-code macros to check the state of memory. */ - -/* Check that memory at _qzz_addr is addressable for _qzz_len bytes. - If suitable addressibility is not established, Valgrind prints an - error message and returns the address of the first offending byte. - Otherwise it returns zero. */ -#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \ - (__extension__({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,\ - _qzz_addr, _qzz_len, 0, 0, 0); \ - _qzz_res; \ - })) - -/* Check that memory at _qzz_addr is addressable and defined for - _qzz_len bytes. If suitable addressibility and definedness are not - established, Valgrind prints an error message and returns the - address of the first offending byte. Otherwise it returns zero. */ -#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \ - (__extension__({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__CHECK_MEM_IS_DEFINED, \ - _qzz_addr, _qzz_len, 0, 0, 0); \ - _qzz_res; \ - })) - -/* Use this macro to force the definedness and addressibility of an - lvalue to be checked. If suitable addressibility and definedness - are not established, Valgrind prints an error message and returns - the address of the first offending byte. Otherwise it returns - zero. */ -#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \ - VALGRIND_CHECK_MEM_IS_DEFINED( \ - (volatile unsigned char *)&(__lvalue), \ - (unsigned long)(sizeof (__lvalue))) - - -/* Do a memory leak check mid-execution. */ -#define VALGRIND_DO_LEAK_CHECK \ - {unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__DO_LEAK_CHECK, \ - 0, 0, 0, 0, 0); \ - } - -/* Just display summaries of leaked memory, rather than all the - details */ -#define VALGRIND_DO_QUICK_LEAK_CHECK \ - {unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__DO_LEAK_CHECK, \ - 1, 0, 0, 0, 0); \ - } - -/* Return number of leaked, dubious, reachable and suppressed bytes found by - all previous leak checks. They must be lvalues. */ -#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \ - /* For safety on 64-bit platforms we assign the results to private - unsigned long variables, then assign these to the lvalues the user - specified, which works no matter what type 'leaked', 'dubious', etc - are. We also initialise '_qzz_leaked', etc because - VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as - initialised. */ \ - {unsigned long _qzz_res; \ - unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ - unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__COUNT_LEAKS, \ - &_qzz_leaked, &_qzz_dubious, \ - &_qzz_reachable, &_qzz_suppressed, 0); \ - leaked = _qzz_leaked; \ - dubious = _qzz_dubious; \ - reachable = _qzz_reachable; \ - suppressed = _qzz_suppressed; \ - } - - -/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it - into the provided zzvbits array. Return values: - 0 if not running on valgrind - 1 success - 2 [previously indicated unaligned arrays; these are now allowed] - 3 if any parts of zzsrc/zzvbits are not addressable. - The metadata is not copied in cases 0, 2 or 3 so it should be - impossible to segfault your system by using this call. -*/ -#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \ - (__extension__({unsigned long _qzz_res; \ - char* czza = (char*)zza; \ - char* czzvbits = (char*)zzvbits; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__GET_VBITS, \ - czza, czzvbits, zznbytes, 0, 0 ); \ - _qzz_res; \ - })) - -/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it - from the provided zzvbits array. Return values: - 0 if not running on valgrind - 1 success - 2 [previously indicated unaligned arrays; these are now allowed] - 3 if any parts of zza/zzvbits are not addressable. - The metadata is not copied in cases 0, 2 or 3 so it should be - impossible to segfault your system by using this call. -*/ -#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \ - (__extension__({unsigned int _qzz_res; \ - char* czza = (char*)zza; \ - char* czzvbits = (char*)zzvbits; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__SET_VBITS, \ - czza, czzvbits, zznbytes, 0, 0 ); \ - _qzz_res; \ - })) - -/* Enable or disable OOM simulation. */ -#define VALGRIND_ENABLE_OOM_AT_ALLOC_INDEX(index) \ - (__extension__ ({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__ENABLE_OOM, \ - 1, index, 0, 0, 0); \ - _qzz_res; \ - })) - -#define VALGRIND_DISABLE_OOM_AT_ALLOC_INDEX(index) \ - (__extension__ ({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \ - VG_USERREQ__ENABLE_OOM, \ - 0, index, 0, 0, 0); \ - _qzz_res; \ - })) - -/* Get the current allocation index. */ -#define VALGRIND_GET_ALLOC_INDEX \ - (__extension__ ({unsigned long _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, -1 /* default return */, \ - VG_USERREQ__GET_ALLOC_INDEX, \ - 0, 0, 0, 0, 0); \ - _qzz_res; \ - })) - - -#endif - diff --git a/tests/auto/other/exceptionsafety_objects/3rdparty/valgrind.h b/tests/auto/other/exceptionsafety_objects/3rdparty/valgrind.h deleted file mode 100644 index bb054b5fd1..0000000000 --- a/tests/auto/other/exceptionsafety_objects/3rdparty/valgrind.h +++ /dev/null @@ -1,3924 +0,0 @@ -/* -*- c -*- - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (valgrind.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of Valgrind, a dynamic binary instrumentation - framework. - - Copyright (C) 2000-2008 Julian Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. 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. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (valgrind.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - - -/* This file is for inclusion into client (your!) code. - - You can use these macros to manipulate and query Valgrind's - execution inside your own programs. - - The resulting executables will still run without Valgrind, just a - little bit more slowly than they otherwise would, but otherwise - unchanged. When not running on valgrind, each client request - consumes very few (eg. 7) instructions, so the resulting performance - loss is negligible unless you plan to execute client requests - millions of times per second. Nevertheless, if that is still a - problem, you can compile with the NVALGRIND symbol defined (gcc - -DNVALGRIND) so that client requests are not even compiled in. */ - -#ifndef __VALGRIND_H -#define __VALGRIND_H - -#include <stdarg.h> - -/* Nb: this file might be included in a file compiled with -ansi. So - we can't use C++ style "//" comments nor the "asm" keyword (instead - use "__asm__"). */ - -/* Derive some tags indicating what the target platform is. Note - that in this file we're using the compiler's CPP symbols for - identifying architectures, which are different to the ones we use - within the rest of Valgrind. Note, __powerpc__ is active for both - 32 and 64-bit PPC, whereas __powerpc64__ is only active for the - latter (on Linux, that is). */ -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64_linux -#undef PLAT_ppc32_aix5 -#undef PLAT_ppc64_aix5 - -#if !defined(_AIX) && defined(__i386__) -# define PLAT_x86_linux 1 -#elif !defined(_AIX) && defined(__x86_64__) -# define PLAT_amd64_linux 1 -#elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__) -# define PLAT_ppc32_linux 1 -#elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__) -# define PLAT_ppc64_linux 1 -#elif defined(_AIX) && defined(__64BIT__) -# define PLAT_ppc64_aix5 1 -#elif defined(_AIX) && !defined(__64BIT__) -# define PLAT_ppc32_aix5 1 -#endif - - -/* If we're not compiling for our target platform, don't generate - any inline asms. */ -#if !defined(PLAT_x86_linux) && !defined(PLAT_amd64_linux) \ - && !defined(PLAT_ppc32_linux) && !defined(PLAT_ppc64_linux) \ - && !defined(PLAT_ppc32_aix5) && !defined(PLAT_ppc64_aix5) -# if !defined(NVALGRIND) -# define NVALGRIND 1 -# endif -#endif - - -/* ------------------------------------------------------------------ */ -/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ -/* in here of use to end-users -- skip to the next section. */ -/* ------------------------------------------------------------------ */ - -#if defined(NVALGRIND) - -/* Define NVALGRIND to completely remove the Valgrind magic sequence - from the compiled code (analogous to NDEBUG's effects on - assert()) */ -#define VALGRIND_DO_CLIENT_REQUEST( \ - _zzq_rlval, _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - { \ - (_zzq_rlval) = (_zzq_default); \ - } - -#else /* ! NVALGRIND */ - -/* The following defines the magic code sequences which the JITter - spots and handles magically. Don't look too closely at them as - they will rot your brain. - - The assembly code sequences for all architectures is in this one - file. This is because this file must be stand-alone, and we don't - want to have multiple files. - - For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default - value gets put in the return slot, so that everything works when - this is executed not under Valgrind. Args are passed in a memory - block, and so there's no intrinsic limit to the number that could - be passed, but it's currently five. - - The macro args are: - _zzq_rlval result lvalue - _zzq_default default value (result returned when running on real CPU) - _zzq_request request code - _zzq_arg1..5 request params - - The other two macros are used to support function wrapping, and are - a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the - guest's NRADDR pseudo-register and whatever other information is - needed to safely run the call original from the wrapper: on - ppc64-linux, the R2 value at the divert point is also needed. This - information is abstracted into a user-visible type, OrigFn. - - VALGRIND_CALL_NOREDIR_* behaves the same as the following on the - guest, but guarantees that the branch instruction will not be - redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: - branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a - complete inline asm, since it needs to be combined with more magic - inline asm stuff to be useful. -*/ - -/* ------------------------- x86-linux ------------------------- */ - -#if defined(PLAT_x86_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "roll $3, %%edi ; roll $13, %%edi\n\t" \ - "roll $29, %%edi ; roll $19, %%edi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST( \ - _zzq_rlval, _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - { volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EDX = client_request ( %EAX ) */ \ - "xchgl %%ebx,%%ebx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_rlval = _zzq_result; \ - } - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EAX = guest_NRADDR */ \ - "xchgl %%ecx,%%ecx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_EAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%EAX */ \ - "xchgl %%edx,%%edx\n\t" -#endif /* PLAT_x86_linux */ - -/* ------------------------ amd64-linux ------------------------ */ - -#if defined(PLAT_amd64_linux) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ - "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST( \ - _zzq_rlval, _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - { volatile unsigned long long int _zzq_args[6]; \ - volatile unsigned long long int _zzq_result; \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RDX = client_request ( %RAX ) */ \ - "xchgq %%rbx,%%rbx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_rlval = _zzq_result; \ - } - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RAX = guest_NRADDR */ \ - "xchgq %%rcx,%%rcx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_RAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%RAX */ \ - "xchgq %%rdx,%%rdx\n\t" -#endif /* PLAT_amd64_linux */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ - "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST( \ - _zzq_rlval, _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - { unsigned int _zzq_args[6]; \ - unsigned int _zzq_result; \ - unsigned int* _zzq_ptr; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_rlval = _zzq_result; \ - } - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64_linux) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - unsigned long long int r2; /* what tocptr do we need? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ - "rotldi 0,0,61 ; rotldi 0,0,51\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST( \ - _zzq_rlval, _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - { unsigned long long int _zzq_args[6]; \ - register unsigned long long int _zzq_result __asm__("r3"); \ - register unsigned long long int* _zzq_ptr __asm__("r4"); \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1" \ - : "=r" (_zzq_result) \ - : "0" (_zzq_default), "r" (_zzq_ptr) \ - : "cc", "memory"); \ - _zzq_rlval = _zzq_result; \ - } - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - register unsigned long long int __addr __asm__("r3"); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2" \ - : "=r" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR_GPR2 */ \ - "or 4,4,4" \ - : "=r" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->r2 = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" - -#endif /* PLAT_ppc64_linux */ - -/* ------------------------ ppc32-aix5 ------------------------- */ - -#if defined(PLAT_ppc32_aix5) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - unsigned int r2; /* what tocptr do we need? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ - "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST( \ - _zzq_rlval, _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - { unsigned int _zzq_args[7]; \ - register unsigned int _zzq_result; \ - register unsigned int* _zzq_ptr; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - _zzq_args[6] = (unsigned int)(_zzq_default); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 4,%1\n\t" \ - "lwz 3, 24(4)\n\t" \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" \ - : "=b" (_zzq_result) \ - : "b" (_zzq_ptr) \ - : "r3", "r4", "cc", "memory"); \ - _zzq_rlval = _zzq_result; \ - } - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - register unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "r3", "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR_GPR2 */ \ - "or 4,4,4\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "r3", "cc", "memory" \ - ); \ - _zzq_orig->r2 = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" - -#endif /* PLAT_ppc32_aix5 */ - -/* ------------------------ ppc64-aix5 ------------------------- */ - -#if defined(PLAT_ppc64_aix5) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - unsigned long long int r2; /* what tocptr do we need? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ - "rotldi 0,0,61 ; rotldi 0,0,51\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST( \ - _zzq_rlval, _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - { unsigned long long int _zzq_args[7]; \ - register unsigned long long int _zzq_result; \ - register unsigned long long int* _zzq_ptr; \ - _zzq_args[0] = (unsigned int long long)(_zzq_request); \ - _zzq_args[1] = (unsigned int long long)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int long long)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int long long)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int long long)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int long long)(_zzq_arg5); \ - _zzq_args[6] = (unsigned int long long)(_zzq_default); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 4,%1\n\t" \ - "ld 3, 48(4)\n\t" \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" \ - : "=b" (_zzq_result) \ - : "b" (_zzq_ptr) \ - : "r3", "r4", "cc", "memory"); \ - _zzq_rlval = _zzq_result; \ - } - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - register unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "r3", "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR_GPR2 */ \ - "or 4,4,4\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "r3", "cc", "memory" \ - ); \ - _zzq_orig->r2 = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" - -#endif /* PLAT_ppc64_aix5 */ - -/* Insert assembly code for other platforms here... */ - -#endif /* NVALGRIND */ - - -/* ------------------------------------------------------------------ */ -/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ -/* ugly. It's the least-worst tradeoff I can think of. */ -/* ------------------------------------------------------------------ */ - -/* This section defines magic (a.k.a appalling-hack) macros for doing - guaranteed-no-redirection macros, so as to get from function - wrappers to the functions they are wrapping. The whole point is to - construct standard call sequences, but to do the call itself with a - special no-redirect call pseudo-instruction that the JIT - understands and handles specially. This section is long and - repetitious, and I can't see a way to make it shorter. - - The naming scheme is as follows: - - CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} - - 'W' stands for "word" and 'v' for "void". Hence there are - different macros for calling arity 0, 1, 2, 3, 4, etc, functions, - and for each, the possibility of returning a word-typed result, or - no result. -*/ - -/* Use these to write the name of your wrapper. NOTE: duplicates - VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */ - -#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ - _vgwZU_##soname##_##fnname - -#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ - _vgwZZ_##soname##_##fnname - -/* Use this macro from within a wrapper function to collect the - context (address and possibly other info) of the original function. - Once you have that you can then use it in one of the CALL_FN_ - macros. The type of the argument _lval is OrigFn. */ -#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) - -/* Derivatives of the main macros below, for calling functions - returning void. */ - -#define CALL_FN_v_v(fnptr) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_v(_junk,fnptr); } while (0) - -#define CALL_FN_v_W(fnptr, arg1) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_W(_junk,fnptr,arg1); } while (0) - -#define CALL_FN_v_WW(fnptr, arg1,arg2) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) - -#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) - -/* ------------------------- x86-linux ------------------------- */ - -#if defined(PLAT_x86_linux) - -/* These regs are trashed by the hidden call. No need to mention eax - as gcc can already see that, plus causes gcc to bomb. */ -#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" - -/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $4, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $8, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $12, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $16, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $20, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $24, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $28, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $32, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $36, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $40, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $44, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - "pushl 48(%%eax)\n\t" \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - "addl $48, %%esp\n" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_x86_linux */ - -/* ------------------------ amd64-linux ------------------------ */ - -#if defined(PLAT_amd64_linux) - -/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ - "rdi", "r8", "r9", "r10", "r11" - -/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned - long) == 8. */ - -/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ - macros. In order not to trash the stack redzone, we need to drop - %rsp by 128 before the hidden call, and restore afterwards. The - nastyness is that it is only by luck that the stack still appears - to be unwindable during the hidden call - since then the behaviour - of any routine using this macro does not match what the CFI data - says. Sigh. - - Why is this important? Imagine that a wrapper has a stack - allocated local, and passes to the hidden call, a pointer to it. - Because gcc does not know about the hidden call, it may allocate - that local in the redzone. Unfortunately the hidden call may then - trash it before it comes to use it. So we must step clear of the - redzone, for the duration of the hidden call, to make it safe. - - Probably the same problem afflicts the other redzone-style ABIs too - (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is - self describing (none of this CFI nonsense) so at least messing - with the stack pointer doesn't give a danger of non-unwindable - stack. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - "addq $128,%%rsp\n\t" \ - VALGRIND_CALL_NOREDIR_RAX \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $8, %%rsp\n" \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $16, %%rsp\n" \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $24, %%rsp\n" \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $32, %%rsp\n" \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $40, %%rsp\n" \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - "subq $128,%%rsp\n\t" \ - "pushq 96(%%rax)\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - "addq $48, %%rsp\n" \ - "addq $128,%%rsp\n\t" \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_amd64_linux */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -/* This is useful for finding out about the on-stack stuff: - - extern int f9 ( int,int,int,int,int,int,int,int,int ); - extern int f10 ( int,int,int,int,int,int,int,int,int,int ); - extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); - extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); - - int g9 ( void ) { - return f9(11,22,33,44,55,66,77,88,99); - } - int g10 ( void ) { - return f10(11,22,33,44,55,66,77,88,99,110); - } - int g11 ( void ) { - return f11(11,22,33,44,55,66,77,88,99,110,121); - } - int g12 ( void ) { - return f12(11,22,33,44,55,66,77,88,99,110,121,132); - } -*/ - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* These CALL_FN_ macros assume that on ppc32-linux, - sizeof(unsigned long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "addi 1,1,16\n\t" \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "addi 1,1,16\n\t" \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "addi 1,1,32\n\t" \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - _argvec[12] = (unsigned long)arg12; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg12 */ \ - "lwz 3,48(11)\n\t" \ - "stw 3,20(1)\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "addi 1,1,32\n\t" \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64_linux) - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned - long) == 8. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+0]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+1]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+2]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+3]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+4]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+5]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+6]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+7]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+8]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)" /* restore tocptr */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+9]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - "addi 1,1,128" /* restore frame */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+10]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - "addi 1,1,128" /* restore frame */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+11]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - "addi 1,1,144" /* restore frame */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+12]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - _argvec[2+12] = (unsigned long)arg12; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg12 */ \ - "ld 3,96(11)\n\t" \ - "std 3,136(1)\n\t" \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - "addi 1,1,144" /* restore frame */ \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc64_linux */ - -/* ------------------------ ppc32-aix5 ------------------------- */ - -#if defined(PLAT_ppc32_aix5) - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Expand the stack frame, copying enough info that unwinding - still works. Trashes r3. */ - -#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ - "addi 1,1,-" #_n_fr "\n\t" \ - "lwz 3," #_n_fr "(1)\n\t" \ - "stw 3,0(1)\n\t" - -#define VG_CONTRACT_FRAME_BY(_n_fr) \ - "addi 1,1," #_n_fr "\n\t" - -/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+0]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+1]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+2]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+3]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+4]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+5]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+6]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+7]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ - "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+8]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ - "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ - "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+9]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(64) \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,56(1)\n\t" \ - /* args1-8 */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ - "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ - "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(64) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+10]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(64) \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,60(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,56(1)\n\t" \ - /* args1-8 */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ - "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ - "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(64) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+11]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(72) \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,64(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,60(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,56(1)\n\t" \ - /* args1-8 */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ - "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ - "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(72) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+12]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - _argvec[2+12] = (unsigned long)arg12; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "stw 2,-8(11)\n\t" /* save tocptr */ \ - "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(72) \ - /* arg12 */ \ - "lwz 3,48(11)\n\t" \ - "stw 3,68(1)\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,64(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,60(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,56(1)\n\t" \ - /* args1-8 */ \ - "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ - "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ - "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ - "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ - "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ - "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ - "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ - "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ - "lwz 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "lwz 2,-8(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(72) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc32_aix5 */ - -/* ------------------------ ppc64-aix5 ------------------------- */ - -#if defined(PLAT_ppc64_aix5) - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Expand the stack frame, copying enough info that unwinding - still works. Trashes r3. */ - -#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ - "addi 1,1,-" #_n_fr "\n\t" \ - "ld 3," #_n_fr "(1)\n\t" \ - "std 3,0(1)\n\t" - -#define VG_CONTRACT_FRAME_BY(_n_fr) \ - "addi 1,1," #_n_fr "\n\t" - -/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned - long) == 8. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+0]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+1]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+2]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+3]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+4]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+5]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+6]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+7]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+8]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+9]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(128) \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(128) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+10]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(128) \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(128) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+11]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(144) \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(144) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+12]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - _argvec[2+12] = (unsigned long)arg12; \ - __asm__ volatile( \ - "mr 11,%1\n\t" \ - VG_EXPAND_FRAME_BY_trashes_r3(512) \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - VG_EXPAND_FRAME_BY_trashes_r3(144) \ - /* arg12 */ \ - "ld 3,96(11)\n\t" \ - "std 3,136(1)\n\t" \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VG_CONTRACT_FRAME_BY(144) \ - VG_CONTRACT_FRAME_BY(512) \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc64_aix5 */ - - -/* ------------------------------------------------------------------ */ -/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ -/* */ -/* ------------------------------------------------------------------ */ - -/* Some request codes. There are many more of these, but most are not - exposed to end-user view. These are the public ones, all of the - form 0x1000 + small_number. - - Core ones are in the range 0x00000000--0x0000ffff. The non-public - ones start at 0x2000. -*/ - -/* These macros are used by tools -- they must be public, but don't - embed them into other programs. */ -#define VG_USERREQ_TOOL_BASE(a,b) \ - ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) -#define VG_IS_TOOL_USERREQ(a, b, v) \ - (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. */ -typedef - enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, - VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, - - /* These allow any function to be called from the simulated - CPU but run on the real CPU. Nb: the first arg passed to - the function is always the ThreadId of the running - thread! So CLIENT_CALL0 actually requires a 1 arg - function, etc. */ - VG_USERREQ__CLIENT_CALL0 = 0x1101, - VG_USERREQ__CLIENT_CALL1 = 0x1102, - VG_USERREQ__CLIENT_CALL2 = 0x1103, - VG_USERREQ__CLIENT_CALL3 = 0x1104, - - /* Can be useful in regression testing suites -- eg. can - send Valgrind's output to /dev/null and still count - errors. */ - VG_USERREQ__COUNT_ERRORS = 0x1201, - - /* These are useful and can be interpreted by any tool that - tracks malloc() et al, by using vg_replace_malloc.c. */ - VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, - VG_USERREQ__FREELIKE_BLOCK = 0x1302, - /* Memory pool support. */ - VG_USERREQ__CREATE_MEMPOOL = 0x1303, - VG_USERREQ__DESTROY_MEMPOOL = 0x1304, - VG_USERREQ__MEMPOOL_ALLOC = 0x1305, - VG_USERREQ__MEMPOOL_FREE = 0x1306, - VG_USERREQ__MEMPOOL_TRIM = 0x1307, - VG_USERREQ__MOVE_MEMPOOL = 0x1308, - VG_USERREQ__MEMPOOL_CHANGE = 0x1309, - VG_USERREQ__MEMPOOL_EXISTS = 0x130a, - - /* Allow printfs to valgrind log. */ - VG_USERREQ__PRINTF = 0x1401, - VG_USERREQ__PRINTF_BACKTRACE = 0x1402, - - /* Stack support. */ - VG_USERREQ__STACK_REGISTER = 0x1501, - VG_USERREQ__STACK_DEREGISTER = 0x1502, - VG_USERREQ__STACK_CHANGE = 0x1503 - } Vg_ClientRequest; - -#if !defined(__GNUC__) -# define __extension__ /* */ -#endif - -/* Returns the number of Valgrinds this code is running under. That - is, 0 if running natively, 1 if running under Valgrind, 2 if - running under Valgrind which is running under another Valgrind, - etc. */ -#define RUNNING_ON_VALGRIND __extension__ \ - ({unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */, \ - VG_USERREQ__RUNNING_ON_VALGRIND, \ - 0, 0, 0, 0, 0); \ - _qzz_res; \ - }) - - -/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + - _qzz_len - 1]. Useful if you are debugging a JITter or some such, - since it provides a way to make sure valgrind will retranslate the - invalidated area. Returns no value. */ -#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__DISCARD_TRANSLATIONS, \ - _qzz_addr, _qzz_len, 0, 0, 0); \ - } - - -/* These requests are for getting Valgrind itself to print something. - Possibly with a backtrace. This is a really ugly hack. */ - -#if defined(NVALGRIND) - -# define VALGRIND_PRINTF(...) -# define VALGRIND_PRINTF_BACKTRACE(...) - -#else /* NVALGRIND */ - -/* Modern GCC will optimize the static routine out if unused, - and unused attribute will shut down warnings about it. */ -static int VALGRIND_PRINTF(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -static int -VALGRIND_PRINTF(const char *format, ...) -{ - unsigned long _qzz_res; - va_list vargs; - va_start(vargs, format); - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF, - (unsigned long)format, (unsigned long)vargs, - 0, 0, 0); - va_end(vargs); - return (int)_qzz_res; -} - -static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -static int -VALGRIND_PRINTF_BACKTRACE(const char *format, ...) -{ - unsigned long _qzz_res; - va_list vargs; - va_start(vargs, format); - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE, - (unsigned long)format, (unsigned long)vargs, - 0, 0, 0); - va_end(vargs); - return (int)_qzz_res; -} - -#endif /* NVALGRIND */ - - -/* These requests allow control to move from the simulated CPU to the - real CPU, calling an arbitrary function. - - Note that the current ThreadId is inserted as the first argument. - So this call: - - VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) - - requires f to have this signature: - - Word f(Word tid, Word arg1, Word arg2) - - where "Word" is a word-sized type. - - Note that these client requests are not entirely reliable. For example, - if you call a function with them that subsequently calls printf(), - there's a high chance Valgrind will crash. Generally, your prospects of - these working are made higher if the called function does not refer to - any global variables, and does not refer to any libc or other functions - (printf et al). Any kind of entanglement with libc or dynamic linking is - likely to have a bad outcome, for tricky reasons which we've grappled - with a lot in the past. -*/ -#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ - __extension__ \ - ({unsigned long _qyy_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ - VG_USERREQ__CLIENT_CALL0, \ - _qyy_fn, \ - 0, 0, 0, 0); \ - _qyy_res; \ - }) - -#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ - __extension__ \ - ({unsigned long _qyy_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ - VG_USERREQ__CLIENT_CALL1, \ - _qyy_fn, \ - _qyy_arg1, 0, 0, 0); \ - _qyy_res; \ - }) - -#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ - __extension__ \ - ({unsigned long _qyy_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ - VG_USERREQ__CLIENT_CALL2, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, 0, 0); \ - _qyy_res; \ - }) - -#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ - __extension__ \ - ({unsigned long _qyy_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ - VG_USERREQ__CLIENT_CALL3, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, \ - _qyy_arg3, 0); \ - _qyy_res; \ - }) - - -/* Counts the number of errors that have been recorded by a tool. Nb: - the tool must record the errors with VG_(maybe_record_error)() or - VG_(unique_error)() for them to be counted. */ -#define VALGRIND_COUNT_ERRORS \ - __extension__ \ - ({unsigned int _qyy_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ - VG_USERREQ__COUNT_ERRORS, \ - 0, 0, 0, 0, 0); \ - _qyy_res; \ - }) - -/* Mark a block of memory as having been allocated by a malloc()-like - function. `addr' is the start of the usable block (ie. after any - redzone) `rzB' is redzone size if the allocator can apply redzones; - use '0' if not. Adding redzones makes it more likely Valgrind will spot - block overruns. `is_zeroed' indicates if the memory is zeroed, as it is - for calloc(). Put it immediately after the point where a block is - allocated. - - If you're using Memcheck: If you're allocating memory via superblocks, - and then handing out small chunks of each superblock, if you don't have - redzones on your small blocks, it's worth marking the superblock with - VALGRIND_MAKE_MEM_NOACCESS when it's created, so that block overruns are - detected. But if you can put redzones on, it's probably better to not do - this, so that messages for small overruns are described in terms of the - small block rather than the superblock (but if you have a big overrun - that skips over a redzone, you could miss an error this way). See - memcheck/tests/custom_alloc.c for an example. - - WARNING: if your allocator uses malloc() or 'new' to allocate - superblocks, rather than mmap() or brk(), this will not work properly -- - you'll likely get assertion failures during leak detection. This is - because Valgrind doesn't like seeing overlapping heap blocks. Sorry. - - Nb: block must be freed via a free()-like function specified - with VALGRIND_FREELIKE_BLOCK or mismatch errors will occur. */ -#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__MALLOCLIKE_BLOCK, \ - addr, sizeB, rzB, is_zeroed, 0); \ - } - -/* Mark a block of memory as having been freed by a free()-like function. - `rzB' is redzone size; it must match that given to - VALGRIND_MALLOCLIKE_BLOCK. Memory not freed will be detected by the leak - checker. Put it immediately after the point where the block is freed. */ -#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__FREELIKE_BLOCK, \ - addr, rzB, 0, 0, 0); \ - } - -/* Create a memory pool. */ -#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__CREATE_MEMPOOL, \ - pool, rzB, is_zeroed, 0, 0); \ - } - -/* Destroy a memory pool. */ -#define VALGRIND_DESTROY_MEMPOOL(pool) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__DESTROY_MEMPOOL, \ - pool, 0, 0, 0, 0); \ - } - -/* Associate a piece of memory with a memory pool. */ -#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__MEMPOOL_ALLOC, \ - pool, addr, size, 0, 0); \ - } - -/* Disassociate a piece of memory from a memory pool. */ -#define VALGRIND_MEMPOOL_FREE(pool, addr) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__MEMPOOL_FREE, \ - pool, addr, 0, 0, 0); \ - } - -/* Disassociate any pieces outside a particular range. */ -#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__MEMPOOL_TRIM, \ - pool, addr, size, 0, 0); \ - } - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__MOVE_MEMPOOL, \ - poolA, poolB, 0, 0, 0); \ - } - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__MEMPOOL_CHANGE, \ - pool, addrA, addrB, size, 0); \ - } - -/* Return 1 if a mempool exists, else 0. */ -#define VALGRIND_MEMPOOL_EXISTS(pool) \ - ({unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__MEMPOOL_EXISTS, \ - pool, 0, 0, 0, 0); \ - _qzz_res; \ - }) - -/* Mark a piece of memory as being a stack. Returns a stack id. */ -#define VALGRIND_STACK_REGISTER(start, end) \ - ({unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__STACK_REGISTER, \ - start, end, 0, 0, 0); \ - _qzz_res; \ - }) - -/* Unmark the piece of memory associated with a stack id as being a - stack. */ -#define VALGRIND_STACK_DEREGISTER(id) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__STACK_DEREGISTER, \ - id, 0, 0, 0, 0); \ - } - -/* Change the start and end address of the stack id. */ -#define VALGRIND_STACK_CHANGE(id, start, end) \ - {unsigned int _qzz_res; \ - VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ - VG_USERREQ__STACK_CHANGE, \ - id, start, end, 0, 0); \ - } - - -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64_linux -#undef PLAT_ppc32_aix5 -#undef PLAT_ppc64_aix5 - -#endif /* __VALGRIND_H */ diff --git a/tests/auto/other/exceptionsafety_objects/exceptionsafety_objects.pro b/tests/auto/other/exceptionsafety_objects/exceptionsafety_objects.pro deleted file mode 100644 index 665ca99e41..0000000000 --- a/tests/auto/other/exceptionsafety_objects/exceptionsafety_objects.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase -TARGET = tst_exceptionsafety_objects -QT += widgets testlib -HEADERS += oomsimulator.h 3rdparty/valgrind.h 3rdparty/memcheck.h -SOURCES += tst_exceptionsafety_objects.cpp -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/other/exceptionsafety_objects/oomsimulator.h b/tests/auto/other/exceptionsafety_objects/oomsimulator.h deleted file mode 100644 index 23a7f3839a..0000000000 --- a/tests/auto/other/exceptionsafety_objects/oomsimulator.h +++ /dev/null @@ -1,293 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <malloc.h> -#include <limits.h> -#include <stdio.h> -#include <exception> - -#if !defined(Q_OS_WIN) -# include "3rdparty/memcheck.h" -#endif - -static bool mallocFailActive = false; -static int mallocFailIndex = 0; -static int mallocCount = 0; - -static void my_terminate_handler() -{ - // set a breakpoint here to get a backtrace for your uncaught exceptions - fprintf(stderr, "Uncaught Exception Detected. Set a breakpoint in my_terminate_handler()\n"); - exit(1); -} - -#if defined(__GLIBC__) && !defined(__UCLIBC__) -/* Use glibc's memory allocation hooks */ - -// From glibc 2.14, the malloc hook variables are declared volatile. -// Note: The malloc hook implementation is marked as deprecated. - -#if !defined(__MALLOC_HOOK_VOLATILE) -# define __MALLOC_HOOK_VOLATILE -#endif - -/* our hooks */ -static void *my_malloc_hook(size_t, const void *); -static void *my_realloc_hook(void *, size_t, const void *); -static void *my_memalign_hook(size_t, size_t, const void *); -static void my_free_hook(void *, const void *); - -/* original hooks. */ -static void *(*__MALLOC_HOOK_VOLATILE old_malloc_hook)(size_t, const void *); -static void *(*__MALLOC_HOOK_VOLATILE old_realloc_hook)(void *, size_t, const void *); -static void *(*__MALLOC_HOOK_VOLATILE old_memalign_hook)(size_t, size_t, const void *); -static void (*__MALLOC_HOOK_VOLATILE old_free_hook)(void *, const void *); - -/* initializer function */ -static void my_init_hook(); - -/* Override initialising hook from the C library. */ - -void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) (void) = my_init_hook; - -static void disableHooks() -{ - __malloc_hook = old_malloc_hook; - __realloc_hook = old_realloc_hook; - __memalign_hook = old_memalign_hook; - __free_hook = old_free_hook; -} - -static void enableHooks() -{ - __malloc_hook = my_malloc_hook; - __realloc_hook = my_realloc_hook; - __memalign_hook = my_memalign_hook; - __free_hook = my_free_hook; -} - -void my_init_hook() -{ - old_malloc_hook = __malloc_hook; - old_realloc_hook = __realloc_hook; - old_memalign_hook = __memalign_hook; - old_free_hook = __free_hook; - enableHooks(); -} - -void *my_malloc_hook(size_t size, const void *) -{ - ++mallocCount; - - if (mallocFailActive && --mallocFailIndex < 0) - return 0; // simulate OOM - - __malloc_hook = old_malloc_hook; - void *result = ::malloc (size); - __malloc_hook = my_malloc_hook; - - return result; -} - -void *my_memalign_hook(size_t alignment, size_t size, const void *) -{ - ++mallocCount; - - if (mallocFailActive && --mallocFailIndex < 0) - return 0; // simulate OOM - - __memalign_hook = old_memalign_hook; - void *result = ::memalign(alignment, size); - __memalign_hook = my_memalign_hook; - - return result; -} - -void *my_realloc_hook(void *ptr, size_t size, const void *) -{ - ++mallocCount; - - if (mallocFailActive && --mallocFailIndex < 0) - return 0; // simulate OOM - - __realloc_hook = old_realloc_hook; - __malloc_hook = old_malloc_hook; - void *result = ::realloc(ptr, size); - __malloc_hook = my_malloc_hook; - __realloc_hook = my_realloc_hook; - - return result; -} - -void my_free_hook(void *ptr, const void *) -{ - __free_hook = old_free_hook; - ::free(ptr); - __free_hook = my_free_hook; -} - -#elif defined(Q_CC_MSVC) - -#include "crtdbg.h" - -static int qCrtAllocHook(int allocType, void * /*userData*/, size_t /*size*/, - int blockType, long /*requestNumber*/, - const unsigned char * /*filename*/, int /*lineNumber*/) -{ - if (blockType == _CRT_BLOCK) - return true; // ignore allocations from the C library - - switch (allocType) { - case _HOOK_ALLOC: - case _HOOK_REALLOC: - ++mallocCount; - if (mallocFailActive && --mallocFailIndex < 0) - return false; // simulate OOM - } - - return true; -} - -static struct QCrtDebugRegistrator -{ - QCrtDebugRegistrator() - { - _CrtSetAllocHook(qCrtAllocHook); - } - -} crtDebugRegistrator; - -#else - -static void disableHooks() -{ -} - -#endif - -struct AllocFailer -{ - inline AllocFailer(int index) { reactivateAt(index); } - inline ~AllocFailer() { deactivate(); } - - inline void reactivateAt(int index) - { -#ifdef RUNNING_ON_VALGRIND - if (RUNNING_ON_VALGRIND) - VALGRIND_ENABLE_OOM_AT_ALLOC_INDEX(VALGRIND_GET_ALLOC_INDEX + index + 1); -#endif - mallocFailIndex = index; - mallocFailActive = true; - } - - inline void deactivate() - { - mallocFailActive = false; -#ifdef RUNNING_ON_VALGRIND - VALGRIND_ENABLE_OOM_AT_ALLOC_INDEX(0); -#endif - } - - inline int currentAllocIndex() const - { -#ifdef RUNNING_ON_VALGRIND - if (RUNNING_ON_VALGRIND) - return VALGRIND_GET_ALLOC_INDEX; -#endif - return mallocCount; - } - - static bool initialize() - { - std::set_terminate(my_terminate_handler); -#ifdef RUNNING_ON_VALGRIND - if (RUNNING_ON_VALGRIND) { - if (VALGRIND_GET_ALLOC_INDEX == -1u) { - qWarning("You must use a valgrind with oom simulation support"); - return false; - } - // running in valgrind - don't use glibc hooks - disableHooks(); - - // never stop simulating OOM - VALGRIND_DISABLE_OOM_AT_ALLOC_INDEX(-1u); - } -#endif - return true; - } -}; - -static void *new_helper(std::size_t size) -{ - void *ptr = malloc(size); -#ifndef QT_NO_EXCEPTIONS - if (!ptr) - throw std::bad_alloc(); -#endif - return ptr; -} - -#ifdef Q_CC_MSVC -# pragma warning(push) -# pragma warning(disable: 4290) -#endif - -// overload operator new -#ifndef QT_NO_EXCEPTIONS -void* operator new(size_t size) throw (std::bad_alloc) { return new_helper(size); } -void* operator new[](size_t size) throw (std::bad_alloc) { return new_helper(size); } -#endif -void* operator new(size_t size, const std::nothrow_t&) throw() { return malloc(size); } -void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); } - -// overload operator delete -void operator delete(void *ptr) throw() { if (ptr) free(ptr); } -void operator delete[](void *ptr) throw() { if (ptr) free(ptr); } -void operator delete(void *ptr, const std::nothrow_t&) throw() { if (ptr) free(ptr); } -void operator delete[](void *ptr, const std::nothrow_t&) throw() { if (ptr) free (ptr); } - -#ifdef Q_CC_MSVC -# pragma warning(pop) -#endif - -// ignore placement new and placement delete - those don't allocate. - - diff --git a/tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp b/tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp deleted file mode 100644 index da715516d7..0000000000 --- a/tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp +++ /dev/null @@ -1,803 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtGui/QtGui> -#include <QtWidgets/QtWidgets> -#include <QtTest/QtTest> - -#include <stddef.h> -#include <exception> - -QT_USE_NAMESPACE - -// this test only works with GLIBC - -#include "oomsimulator.h" -#include "3rdparty/memcheck.h" - -class tst_ExceptionSafety_Objects: public QObject -{ - Q_OBJECT - -public slots: - void initTestCase(); -#ifndef QT_NO_EXCEPTIONS - void cleanupTestCase(); - -private slots: - void objects_data(); - void objects(); - - void widgets_data(); - void widgets(); - - void vector_data(); - void vector(); - - void list_data(); - void list(); - - void linkedList_data(); - void linkedList(); - -private: - static QtMessageHandler testMessageHandler; - static void safeMessageHandler(QtMsgType, const QMessageLogContext&, const QString&); -#endif -}; - -#ifdef QT_NO_EXCEPTIONS -void tst_ExceptionSafety_Objects::initTestCase() -{ - QSKIP("This test requires exception support"); -} - -#else -// helper structs to create an arbitrary widget -struct AbstractTester -{ - virtual ~AbstractTester() {} - virtual void operator()(QObject *parent) = 0; -}; -Q_DECLARE_METATYPE(AbstractTester *) - -typedef void (*TestFunction)(QObject*); -Q_DECLARE_METATYPE(TestFunction) - -template <typename T> -struct ObjectCreator : public AbstractTester -{ - void operator()(QObject *) - { - QScopedPointer<T> ptr(new T); - } -}; - -struct BitArrayCreator : public AbstractTester -{ - void operator()(QObject *) - { QScopedPointer<QBitArray> bitArray(new QBitArray(100, true)); } -}; - -struct ByteArrayMatcherCreator : public AbstractTester -{ - void operator()(QObject *) - { QScopedPointer<QByteArrayMatcher> ptr(new QByteArrayMatcher("ralf test",8)); } -}; - -struct CryptographicHashCreator : public AbstractTester -{ - void operator()(QObject *) - { - QScopedPointer<QCryptographicHash> ptr(new QCryptographicHash(QCryptographicHash::Sha1)); - ptr->addData("ralf test",8); - } -}; - -struct DataStreamCreator : public AbstractTester -{ - void operator()(QObject *) - { - QScopedPointer<QByteArray> arr(new QByteArray("hallo, test")); - QScopedPointer<QDataStream> ptr(new QDataStream(arr.data(), QIODevice::ReadWrite)); - ptr->writeBytes("ralf test",8); - } -}; - -struct DirCreator : public AbstractTester -{ - void operator()(QObject *) - { - QDir::cleanPath("../////././"); - QScopedPointer<QDir> ptr(new QDir(".")); - while( ptr->cdUp() ) - ; // just going up - ptr->count(); - ptr->exists(ptr->path()); - - QStringList filters; - filters << "*.cpp" << "*.cxx" << "*.cc"; - ptr->setNameFilters(filters); - } -}; - -void tst_ExceptionSafety_Objects::objects_data() -{ - QTest::addColumn<AbstractTester *>("objectCreator"); - -#define NEWROW(T) QTest::newRow(#T) << static_cast<AbstractTester *>(new ObjectCreator<T >) - NEWROW(QObject); - NEWROW(QBuffer); - NEWROW(QFile); - NEWROW(QProcess); - NEWROW(QSettings); - NEWROW(QThread); - NEWROW(QThreadPool); - NEWROW(QTranslator); - -#define NEWROW2(T, CREATOR) QTest::newRow(#T) << static_cast<AbstractTester *>(new CREATOR) - NEWROW2(QBitArray, BitArrayCreator); - NEWROW2(QByteArrayMatcher, ByteArrayMatcherCreator); - NEWROW2(QCryptographicHash, CryptographicHashCreator); - NEWROW2(QDataStream, DataStreamCreator); - NEWROW2(QDir, DirCreator); -} - -// create and destructs an object, and lets each and every allocation -// during construction and destruction fail. -template <typename T> -static void doOOMTest(T &testFunc, QObject *parent, int start=0) -{ - int currentOOMIndex = start; - bool caught = false; - bool done = false; - - AllocFailer allocFailer(0); - int allocCountBefore = allocFailer.currentAllocIndex(); - - do { - allocFailer.reactivateAt(++currentOOMIndex); - - caught = false; - - try { - testFunc(parent); - } catch (const std::bad_alloc &) { - caught = true; - } catch (const std::exception &ex) { - if (strcmp(ex.what(), "autotest swallow") != 0) - throw; - caught = true; - } - - if (!caught) { - void *buf = malloc(42); - if (buf) { - // we got memory here - oom test is over. - free(buf); - done = true; - } - } - - // if we get a FAIL, stop executing now - if (QTest::currentTestFailed()) - done = true; - -//#define REALLY_VERBOSE -#ifdef REALLY_VERBOSE - fprintf(stderr, " OOM Index: %d\n", currentOOMIndex); -#endif - - - } while (caught || !done); - - allocFailer.deactivate(); - -//#define VERBOSE -#ifdef VERBOSE - fprintf(stderr, "OOM Test done, checked allocs: %d (range %d - %d)\n", currentOOMIndex, - allocCountBefore, allocFailer.currentAllocIndex()); -#else - Q_UNUSED(allocCountBefore); -#endif -} - -static int alloc1Failed = 0; -static int alloc2Failed = 0; -static int alloc3Failed = 0; -static int alloc4Failed = 0; -static int malloc1Failed = 0; -static int malloc2Failed = 0; - -// Tests that new, new[] and malloc() fail at least once during OOM testing. -class SelfTestObject : public QObject -{ -public: - SelfTestObject(QObject *parent = 0) - : QObject(parent) - { - try { delete new int; } catch (const std::bad_alloc &) { ++alloc1Failed; throw; } - try { delete [] new double[5]; } catch (const std::bad_alloc &) { ++alloc2Failed; throw ;} - void *buf = malloc(42); - if (buf) - free(buf); - else - ++malloc1Failed; - } - - ~SelfTestObject() - { - try { delete new int; } catch (const std::bad_alloc &) { ++alloc3Failed; } - try { delete [] new double[5]; } catch (const std::bad_alloc &) { ++alloc4Failed; } - void *buf = malloc(42); - if (buf) - free(buf); - else - ++malloc2Failed = true; - } -}; - -QtMessageHandler tst_ExceptionSafety_Objects::testMessageHandler; - -void tst_ExceptionSafety_Objects::safeMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, - const QString &msg) -{ - // this temporarily suspends OOM testing while handling a message - int currentIndex = mallocFailIndex; - AllocFailer allocFailer(0); - allocFailer.deactivate(); - (*testMessageHandler)(type, ctxt, msg); - allocFailer.reactivateAt(currentIndex); -} - -typedef void (*PVF)(); -PVF defaultTerminate; -void debugTerminate() -{ - // you can detect uncaught exceptions with a breakpoint in here - (*defaultTerminate)(); -} - -PVF defaultUnexpected; -void debugUnexpected() -{ - // you can detect unexpected exceptions with a breakpoint in here - (*defaultUnexpected)(); -} - -void tst_ExceptionSafety_Objects::initTestCase() -{ - // set handlers for bad exception cases, you might want to step in and breakpoint the default handlers too - defaultTerminate = std::set_terminate(&debugTerminate); - defaultUnexpected = std::set_unexpected(&debugUnexpected); - testMessageHandler = qInstallMessageHandler(safeMessageHandler); - - QVERIFY(AllocFailer::initialize()); - - // sanity check whether OOM simulation works - AllocFailer allocFailer(0); - - // malloc fail index is 0 -> this malloc should fail. - void *buf = malloc(42); - allocFailer.deactivate(); - QVERIFY(!buf); - - // malloc fail index is 1 - second malloc should fail. - allocFailer.reactivateAt(1); - buf = malloc(42); - void *buf2 = malloc(42); - allocFailer.deactivate(); - - QVERIFY(buf); - free(buf); - QVERIFY(!buf2); - - ObjectCreator<SelfTestObject> *selfTest = new ObjectCreator<SelfTestObject>; - doOOMTest(*selfTest, 0); - delete selfTest; - QCOMPARE(alloc1Failed, 1); - QCOMPARE(alloc2Failed, 1); - QCOMPARE(alloc3Failed, 2); - QCOMPARE(alloc4Failed, 3); - QCOMPARE(malloc1Failed, 1); - QCOMPARE(malloc2Failed, 1); -} - -void tst_ExceptionSafety_Objects::cleanupTestCase() -{ - qInstallMessageHandler(testMessageHandler); -} - -void tst_ExceptionSafety_Objects::objects() -{ - QLatin1String tag = QLatin1String(QTest::currentDataTag()); - if (tag == QLatin1String("QFile") - || tag == QLatin1String("QProcess") - || tag == QLatin1String("QSettings") - || tag == QLatin1String("QThread") - || tag == QLatin1String("QThreadPool")) - QSKIP("This type of object is not currently strongly exception safe"); - - QFETCH(AbstractTester *, objectCreator); - - doOOMTest(*objectCreator, 0); - - delete objectCreator; -} - -template <typename T> -struct WidgetCreator : public AbstractTester -{ - void operator()(QObject *parent) - { - if (parent && !parent->isWidgetType()) - qFatal("%s: parent must be either null or a widget type", Q_FUNC_INFO); - QScopedPointer<T> ptr(parent ? new T(static_cast<QWidget *>(parent)) : new T); - } -}; - -// QSizeGrip doesn't have a default constructor - always pass parent (even though it might be 0) -template <> struct WidgetCreator<QSizeGrip> : public AbstractTester -{ - void operator()(QObject *parent) - { - if (parent && !parent->isWidgetType()) - qFatal("%s: parent must be either null or a widget type", Q_FUNC_INFO); - QScopedPointer<QSizeGrip> ptr(new QSizeGrip(static_cast<QWidget *>(parent))); - } -}; - -// QDesktopWidget doesn't need a parent. -template <> struct WidgetCreator<QDesktopWidget> : public AbstractTester -{ - void operator()(QObject *parent) - { - if (parent && !parent->isWidgetType()) - qFatal("%s: parent must be either null or a widget type", Q_FUNC_INFO); - QScopedPointer<QDesktopWidget> ptr(new QDesktopWidget()); - } -}; -void tst_ExceptionSafety_Objects::widgets_data() -{ - QTest::addColumn<AbstractTester *>("widgetCreator"); - -#undef NEWROW -#define NEWROW(T) QTest::newRow(#T) << static_cast<AbstractTester *>(new WidgetCreator<T >) - - NEWROW(QWidget); - - NEWROW(QButtonGroup); - NEWROW(QCheckBox); - NEWROW(QColumnView); - NEWROW(QComboBox); - NEWROW(QCommandLinkButton); - NEWROW(QDateEdit); - NEWROW(QDateTimeEdit); - NEWROW(QDesktopWidget); - NEWROW(QDial); - NEWROW(QDoubleSpinBox); - NEWROW(QFocusFrame); - NEWROW(QFontComboBox); - NEWROW(QFrame); - NEWROW(QGroupBox); - NEWROW(QLabel); - NEWROW(QLCDNumber); - NEWROW(QLineEdit); - NEWROW(QListView); - NEWROW(QListWidget); - NEWROW(QMainWindow); - NEWROW(QMenu); - NEWROW(QMenuBar); - NEWROW(QPlainTextEdit); - NEWROW(QProgressBar); - NEWROW(QPushButton); - NEWROW(QRadioButton); - NEWROW(QScrollArea); - NEWROW(QScrollBar); - NEWROW(QSizeGrip); - NEWROW(QSlider); - NEWROW(QSpinBox); - NEWROW(QSplitter); - NEWROW(QStackedWidget); - NEWROW(QStatusBar); - NEWROW(QTabBar); - NEWROW(QTableView); - NEWROW(QTableWidget); - NEWROW(QTabWidget); - NEWROW(QTextBrowser); - NEWROW(QTextEdit); - NEWROW(QTimeEdit); - NEWROW(QToolBar); - NEWROW(QToolBox); - NEWROW(QToolButton); - NEWROW(QTreeView); - NEWROW(QTreeWidget); -} - -void tst_ExceptionSafety_Objects::widgets() -{ - QLatin1String tag = QLatin1String(QTest::currentDataTag()); - if (tag == QLatin1String("QColumnView") - || tag == QLatin1String("QComboBox") - || tag == QLatin1String("QCommandLinkButton") - || tag == QLatin1String("QDateEdit") - || tag == QLatin1String("QDateTimeEdit") - || tag == QLatin1String("QDesktopWidget") - || tag == QLatin1String("QDoubleSpinBox") - || tag == QLatin1String("QFontComboBox") - || tag == QLatin1String("QGroupBox") - || tag == QLatin1String("QLineEdit") - || tag == QLatin1String("QListView") - || tag == QLatin1String("QListWidget") - || tag == QLatin1String("QMainWindow") - || tag == QLatin1String("QMenu") - || tag == QLatin1String("QMenuBar") - || tag == QLatin1String("QPlainTextEdit") - || tag == QLatin1String("QProgressBar") - || tag == QLatin1String("QPushButton") - || tag == QLatin1String("QScrollArea") - || tag == QLatin1String("QSpinBox") - || tag == QLatin1String("QStackedWidget") - || tag == QLatin1String("QStatusBar") - || tag == QLatin1String("QTableView") - || tag == QLatin1String("QTableWidget") - || tag == QLatin1String("QTabWidget") - || tag == QLatin1String("QTextBrowser") - || tag == QLatin1String("QTextEdit") - || tag == QLatin1String("QTimeEdit") - || tag == QLatin1String("QToolBar") - || tag == QLatin1String("QToolBox") - || tag == QLatin1String("QTreeView") - || tag == QLatin1String("QTreeWidget")) - QSKIP("This type of widget is not currently strongly exception safe"); - - if (tag == QLatin1String("QWidget")) - QSKIP("QTBUG-18927"); - - QFETCH(AbstractTester *, widgetCreator); - - doOOMTest(*widgetCreator, 0, 00000); - - QWidget parent; - doOOMTest(*widgetCreator, &parent, 00000); - - delete widgetCreator; - - // if the test reaches here without crashing, we passed :) - QVERIFY(true); -} - -struct Integer -{ - Integer(int value = 42) - : ptr(new int(value)) - { - ++instanceCount; - } - - Integer(const Integer &other) - : ptr(new int(*other.ptr)) - { - ++instanceCount; - } - - Integer &operator=(const Integer &other) - { - int *newPtr = new int(*other.ptr); - delete ptr; - ptr = newPtr; - return *this; - } - - ~Integer() - { - --instanceCount; - delete ptr; - } - - int value() const - { - return *ptr; - } - - int *ptr; - static int instanceCount; -}; - -int Integer::instanceCount = 0; - -struct IntegerMoveable - { - IntegerMoveable(int value = 42) - : val(value) - { - delete new int; - ++instanceCount; - } - - IntegerMoveable(const IntegerMoveable &other) - : val(other.val) - { - delete new int; - ++instanceCount; - } - - IntegerMoveable &operator=(const IntegerMoveable &other) - { - delete new int; - val = other.val; - return *this; - } - - ~IntegerMoveable() - { - --instanceCount; - } - - int value() const - { - return val; - } - - int val; - static int instanceCount; - }; - -int IntegerMoveable::instanceCount = 0; -QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(IntegerMoveable, Q_MOVABLE_TYPE); -QT_END_NAMESPACE - -template <typename T, template<typename> class Container> -void containerInsertTest(QObject*) -{ - Container<T> container; - - // insert an item in an empty container - try { - container.insert(container.begin(), 41); - } catch (...) { - QVERIFY(container.isEmpty()); - QCOMPARE(T::instanceCount, 0); - return; - } - - QCOMPARE(container.size(), 1); - QCOMPARE(T::instanceCount, 1); - - // insert an item before another item - try { - container.insert(container.begin(), 42); - } catch (...) { - QCOMPARE(container.size(), 1); - QCOMPARE(container.first().value(), 41); - QCOMPARE(T::instanceCount, 1); - return; - } - - QCOMPARE(T::instanceCount, 2); - - // insert an item in between - try { - container.insert(container.begin() + 1, 43); - } catch (...) { - QCOMPARE(container.size(), 2); - QCOMPARE(container.first().value(), 41); - QCOMPARE((container.begin() + 1)->value(), 42); - QCOMPARE(T::instanceCount, 2); - return; - } - - QCOMPARE(T::instanceCount, 3); -} - -template <typename T, template<typename> class Container> -void containerAppendTest(QObject*) -{ - Container<T> container; - - // append to an empty container - try { - container.append(42); - } catch (...) { - QCOMPARE(container.size(), 0); - QCOMPARE(T::instanceCount, 0); - return; - } - - // append to a container with one item - try { - container.append(43); - } catch (...) { - QCOMPARE(container.size(), 1); - QCOMPARE(container.first().value(), 42); - QCOMPARE(T::instanceCount, 1); - return; - } - - Container<T> container2; - - try { - container2.append(44); - } catch (...) { - // don't care - return; - } - QCOMPARE(T::instanceCount, 3); - - // append another container with one item - try { - container += container2; - } catch (...) { - QCOMPARE(container.size(), 2); - QCOMPARE(container.first().value(), 42); - QCOMPARE((container.begin() + 1)->value(), 43); - QCOMPARE(T::instanceCount, 3); - return; - } - - QCOMPARE(T::instanceCount, 4); -} - -template <typename T, template<typename> class Container> -void containerEraseTest(QObject*) -{ - Container<T> container; - - try { - container.append(42); - container.append(43); - container.append(44); - container.append(45); - container.append(46); - } catch (...) { - // don't care - return; - } - - // sanity checks - QCOMPARE(container.size(), 5); - QCOMPARE(T::instanceCount, 5); - - // delete the first one - try { - container.erase(container.begin()); - } catch (...) { - QCOMPARE(container.size(), 5); - QCOMPARE(container.first().value(), 42); - QCOMPARE(T::instanceCount, 5); - return; - } - - QCOMPARE(container.size(), 4); - QCOMPARE(container.first().value(), 43); - QCOMPARE(T::instanceCount, 4); - - // delete the last one - try { - container.erase(container.end() - 1); - } catch (...) { - QCOMPARE(container.size(), 4); - QCOMPARE(T::instanceCount, 4); - return; - } - - QCOMPARE(container.size(), 3); - QCOMPARE(container.first().value(), 43); - QCOMPARE((container.begin() + 1)->value(), 44); - QCOMPARE((container.begin() + 2)->value(), 45); - QCOMPARE(T::instanceCount, 3); - - // delete the middle one - try { - container.erase(container.begin() + 1); - } catch (...) { - QCOMPARE(container.size(), 3); - QCOMPARE(container.first().value(), 43); - QCOMPARE((container.begin() + 1)->value(), 44); - QCOMPARE((container.begin() + 2)->value(), 45); - QCOMPARE(T::instanceCount, 3); - return; - } - - QCOMPARE(container.size(), 2); - QCOMPARE(container.first().value(), 43); - QCOMPARE((container.begin() + 1)->value(), 45); - QCOMPARE(T::instanceCount, 2); -} - -template <template<typename T> class Container> -static void containerData() -{ - QTest::addColumn<TestFunction>("testFunction"); - - QTest::newRow("insert static") << static_cast<TestFunction>(containerInsertTest<Integer, Container>); - QTest::newRow("append static") << static_cast<TestFunction>(containerAppendTest<Integer, Container>); - QTest::newRow("erase static") << static_cast<TestFunction>(containerEraseTest<Integer, Container>); - QTest::newRow("insert moveable") << static_cast<TestFunction>(containerInsertTest<IntegerMoveable, Container>); - QTest::newRow("append moveable") << static_cast<TestFunction>(containerAppendTest<IntegerMoveable, Container>); - QTest::newRow("erase moveable") << static_cast<TestFunction>(containerEraseTest<IntegerMoveable, Container>); -} - -void tst_ExceptionSafety_Objects::vector_data() -{ - containerData<QVector>(); -} - -void tst_ExceptionSafety_Objects::vector() -{ - QFETCH(TestFunction, testFunction); - - if (QLatin1String(QTest::currentDataTag()) == QLatin1String("insert static") - || QLatin1String(QTest::currentDataTag()) == QLatin1String("insert moveable")) - QSKIP("QVector::insert is currently not strongly exception safe"); - - doOOMTest(testFunction, 0); -} - -void tst_ExceptionSafety_Objects::list_data() -{ - containerData<QList>(); -} - -void tst_ExceptionSafety_Objects::list() -{ - QFETCH(TestFunction, testFunction); - - doOOMTest(testFunction, 0); -} - -void tst_ExceptionSafety_Objects::linkedList_data() -{ - containerData<QLinkedList>(); -} - -void tst_ExceptionSafety_Objects::linkedList() -{ - QFETCH(TestFunction, testFunction); - - doOOMTest(testFunction, 0); -} - -#endif - -QTEST_MAIN(tst_ExceptionSafety_Objects) -#include "tst_exceptionsafety_objects.moc" diff --git a/tests/auto/other/other.pro b/tests/auto/other/other.pro index 1d57206a73..63cbca539d 100644 --- a/tests/auto/other/other.pro +++ b/tests/auto/other/other.pro @@ -4,8 +4,6 @@ SUBDIRS=\ baselineexample \ collections \ compiler \ - exceptionsafety \ - # exceptionsafety_objects \ # QObjectPrivate is not safe gestures \ headersclean \ lancelot \ @@ -70,4 +68,3 @@ wince*|!contains(QT_CONFIG, accessibility): SUBDIRS -= qaccessibility !embedded|wince*: SUBDIRS -= \ qdirectpainter -!linux*-g++*:SUBDIRS -= exceptionsafety_objects diff --git a/tests/auto/testlib/selftests/expected_cmptest.lightxml b/tests/auto/testlib/selftests/expected_cmptest.lightxml index 54c5bb85f0..99e2e825c0 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.lightxml +++ b/tests/auto/testlib/selftests/expected_cmptest.lightxml @@ -15,7 +15,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[int, string]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(int,123) + Actual (actual) : QVariant(int,123) Expected (expected): QVariant(QString,hi)]]></Description> </Incident> <Incident type="pass" file="" line="0"> @@ -24,19 +24,19 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[null hash, invalid]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(QVariantHash) + Actual (actual) : QVariant(QVariantHash) Expected (expected): QVariant()]]></Description> </Incident> <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[string, null user type]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(QString,A simple string) + Actual (actual) : QVariant(QString,A simple string) Expected (expected): QVariant(PhonyClass)]]></Description> </Incident> <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[both non-null user type]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(PhonyClass,<value not representable as string>) + Actual (actual) : QVariant(PhonyClass,<value not representable as string>) Expected (expected): QVariant(PhonyClass,<value not representable as string>)]]></Description> </Incident> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_cmptest.txt b/tests/auto/testlib/selftests/expected_cmptest.txt index 9d03a8e3da..504507f032 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.txt +++ b/tests/auto/testlib/selftests/expected_cmptest.txt @@ -4,20 +4,20 @@ PASS : tst_Cmptest::initTestCase() PASS : tst_Cmptest::compare_boolfuncs() PASS : tst_Cmptest::compare_pointerfuncs() FAIL! : tst_Cmptest::compare_tostring(int, string) Compared values are not the same - Actual (actual): QVariant(int,123) + Actual (actual) : QVariant(int,123) Expected (expected): QVariant(QString,hi) Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] PASS : tst_Cmptest::compare_tostring(both invalid) FAIL! : tst_Cmptest::compare_tostring(null hash, invalid) Compared values are not the same - Actual (actual): QVariant(QVariantHash) + Actual (actual) : QVariant(QVariantHash) Expected (expected): QVariant() Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] FAIL! : tst_Cmptest::compare_tostring(string, null user type) Compared values are not the same - Actual (actual): QVariant(QString,A simple string) + Actual (actual) : QVariant(QString,A simple string) Expected (expected): QVariant(PhonyClass) Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] FAIL! : tst_Cmptest::compare_tostring(both non-null user type) Compared values are not the same - Actual (actual): QVariant(PhonyClass,<value not representable as string>) + Actual (actual) : QVariant(PhonyClass,<value not representable as string>) Expected (expected): QVariant(PhonyClass,<value not representable as string>) Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] PASS : tst_Cmptest::compareQStringLists(empty lists) diff --git a/tests/auto/testlib/selftests/expected_cmptest.xml b/tests/auto/testlib/selftests/expected_cmptest.xml index ccab93d7c0..df35058acc 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.xml +++ b/tests/auto/testlib/selftests/expected_cmptest.xml @@ -17,7 +17,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[int, string]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(int,123) + Actual (actual) : QVariant(int,123) Expected (expected): QVariant(QString,hi)]]></Description> </Incident> <Incident type="pass" file="" line="0"> @@ -26,19 +26,19 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[null hash, invalid]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(QVariantHash) + Actual (actual) : QVariant(QVariantHash) Expected (expected): QVariant()]]></Description> </Incident> <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[string, null user type]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(QString,A simple string) + Actual (actual) : QVariant(QString,A simple string) Expected (expected): QVariant(PhonyClass)]]></Description> </Incident> <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="214"> <DataTag><![CDATA[both non-null user type]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (actual): QVariant(PhonyClass,<value not representable as string>) + Actual (actual) : QVariant(PhonyClass,<value not representable as string>) Expected (expected): QVariant(PhonyClass,<value not representable as string>)]]></Description> </Incident> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_cmptest.xunitxml b/tests/auto/testlib/selftests/expected_cmptest.xunitxml index 0cb88147b0..e7d76ac839 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.xunitxml +++ b/tests/auto/testlib/selftests/expected_cmptest.xunitxml @@ -9,16 +9,16 @@ <testcase result="pass" name="compare_pointerfuncs"/> <testcase result="fail" name="compare_tostring"> <failure tag="int, string" message="Compared values are not the same - Actual (actual): QVariant(int,123) + Actual (actual) : QVariant(int,123) Expected (expected): QVariant(QString,hi)" result="fail"/> <failure tag="null hash, invalid" message="Compared values are not the same - Actual (actual): QVariant(QVariantHash) + Actual (actual) : QVariant(QVariantHash) Expected (expected): QVariant()" result="fail"/> <failure tag="string, null user type" message="Compared values are not the same - Actual (actual): QVariant(QString,A simple string) + Actual (actual) : QVariant(QString,A simple string) Expected (expected): QVariant(PhonyClass)" result="fail"/> <failure tag="both non-null user type" message="Compared values are not the same - Actual (actual): QVariant(PhonyClass,<value not representable as string>) + Actual (actual) : QVariant(PhonyClass,<value not representable as string>) Expected (expected): QVariant(PhonyClass,<value not representable as string>)" result="fail"/> </testcase> <testcase result="fail" name="compareQStringLists"> diff --git a/tests/auto/testlib/selftests/expected_datetime.lightxml b/tests/auto/testlib/selftests/expected_datetime.lightxml index d8acae9c26..183744b2e2 100644 --- a/tests/auto/testlib/selftests/expected_datetime.lightxml +++ b/tests/auto/testlib/selftests/expected_datetime.lightxml @@ -9,7 +9,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/datetime/tst_datetime.cpp" line="66"> <Description><![CDATA[Compared values are not the same Actual (local): 2000/05/03 04:03:04.000[local time] - Expected (utc): 2000/05/03 04:03:04.000[UTC]]]></Description> + Expected (utc) : 2000/05/03 04:03:04.000[UTC]]]></Description> </Incident> </TestFunction> <TestFunction name="qurl"> diff --git a/tests/auto/testlib/selftests/expected_datetime.txt b/tests/auto/testlib/selftests/expected_datetime.txt index ce9e1f36b4..0cbc6506d5 100644 --- a/tests/auto/testlib/selftests/expected_datetime.txt +++ b/tests/auto/testlib/selftests/expected_datetime.txt @@ -3,7 +3,7 @@ Config: Using QtTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HER PASS : tst_DateTime::initTestCase() FAIL! : tst_DateTime::dateTime() Compared values are not the same Actual (local): 2000/05/03 04:03:04.000[local time] - Expected (utc): 2000/05/03 04:03:04.000[UTC] + Expected (utc) : 2000/05/03 04:03:04.000[UTC] Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/datetime/tst_datetime.cpp(33)] PASS : tst_DateTime::qurl(empty urls) FAIL! : tst_DateTime::qurl(empty rhs) Compared values are not the same diff --git a/tests/auto/testlib/selftests/expected_datetime.xml b/tests/auto/testlib/selftests/expected_datetime.xml index d7c9afabee..42b566c074 100644 --- a/tests/auto/testlib/selftests/expected_datetime.xml +++ b/tests/auto/testlib/selftests/expected_datetime.xml @@ -11,7 +11,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/datetime/tst_datetime.cpp" line="66"> <Description><![CDATA[Compared values are not the same Actual (local): 2000/05/03 04:03:04.000[local time] - Expected (utc): 2000/05/03 04:03:04.000[UTC]]]></Description> + Expected (utc) : 2000/05/03 04:03:04.000[UTC]]]></Description> </Incident> </TestFunction> <TestFunction name="qurl"> diff --git a/tests/auto/testlib/selftests/expected_datetime.xunitxml b/tests/auto/testlib/selftests/expected_datetime.xunitxml index af0e4db7e8..00bd43f904 100644 --- a/tests/auto/testlib/selftests/expected_datetime.xunitxml +++ b/tests/auto/testlib/selftests/expected_datetime.xunitxml @@ -8,7 +8,7 @@ <testcase result="fail" name="dateTime"> <failure message="Compared values are not the same Actual (local): 2000/05/03 04:03:04.000[local time] - Expected (utc): 2000/05/03 04:03:04.000[UTC]" result="fail"/> + Expected (utc) : 2000/05/03 04:03:04.000[UTC]" result="fail"/> </testcase> <testcase result="fail" name="qurl"> <failure tag="empty rhs" message="Compared values are not the same diff --git a/tests/auto/testlib/selftests/expected_float.txt b/tests/auto/testlib/selftests/expected_float.txt index dc32fd76f1..da98f9c19d 100644 --- a/tests/auto/testlib/selftests/expected_float.txt +++ b/tests/auto/testlib/selftests/expected_float.txt @@ -3,15 +3,15 @@ Config: Using QtTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HER PASS : tst_float::initTestCase() PASS : tst_float::floatComparisons(should SUCCEED 1) FAIL! : tst_float::floatComparisons(should FAIL 1) Compared floats are not the same (fuzzy compare) - Actual (operandLeft): 1 + Actual (operandLeft) : 1 Expected (operandRight): 3 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(61)] FAIL! : tst_float::floatComparisons(should FAIL 2) Compared floats are not the same (fuzzy compare) - Actual (operandLeft): 1e-07 + Actual (operandLeft) : 1e-07 Expected (operandRight): 3e-07 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(61)] FAIL! : tst_float::floatComparisons(should FAIL 3) Compared floats are not the same (fuzzy compare) - Actual (operandLeft): 99998 + Actual (operandLeft) : 99998 Expected (operandRight): 99999 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(61)] PASS : tst_float::floatComparisons(should SUCCEED 2) diff --git a/tests/auto/testlib/selftests/expected_strcmp.lightxml b/tests/auto/testlib/selftests/expected_strcmp.lightxml index d5135fd7df..4c30c9f801 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.lightxml +++ b/tests/auto/testlib/selftests/expected_strcmp.lightxml @@ -35,13 +35,13 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/strcmp/tst_strcmp.cpp" line="121"> <Description><![CDATA[Compared values are not the same Actual (QByteArray("foo")): 66 6F 6F - Expected (QByteArray()): ]]></Description> + Expected (QByteArray()) : ]]></Description> </Incident> </TestFunction> <TestFunction name="failByteArrayEmpty"> <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/strcmp/tst_strcmp.cpp" line="126"> <Description><![CDATA[Compared values are not the same - Actual (QByteArray("")): + Actual (QByteArray("")) : Expected (QByteArray("foo")): 66 6F 6F]]></Description> </Incident> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_strcmp.txt b/tests/auto/testlib/selftests/expected_strcmp.txt index 797aefa82f..f3ad169fb7 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.txt +++ b/tests/auto/testlib/selftests/expected_strcmp.txt @@ -18,10 +18,10 @@ FAIL! : tst_StrCmp::failByteArray() Compared values are not the same Loc: [./tst_strcmp.cpp(82)] FAIL! : tst_StrCmp::failByteArrayNull() Compared values are not the same Actual (QByteArray("foo")): 66 6F 6F - Expected (QByteArray()): + Expected (QByteArray()) : Loc: [./tst_strcmp.cpp(88)] FAIL! : tst_StrCmp::failByteArrayEmpty() Compared values are not the same - Actual (QByteArray("")): + Actual (QByteArray("")) : Expected (QByteArray("foo")): 66 6F 6F Loc: [./tst_strcmp.cpp(93)] FAIL! : tst_StrCmp::failByteArraySingleChars() Compared values are not the same diff --git a/tests/auto/testlib/selftests/expected_strcmp.xml b/tests/auto/testlib/selftests/expected_strcmp.xml index 0c5a73918d..db9ed34bb8 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.xml +++ b/tests/auto/testlib/selftests/expected_strcmp.xml @@ -37,13 +37,13 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/strcmp/tst_strcmp.cpp" line="121"> <Description><![CDATA[Compared values are not the same Actual (QByteArray("foo")): 66 6F 6F - Expected (QByteArray()): ]]></Description> + Expected (QByteArray()) : ]]></Description> </Incident> </TestFunction> <TestFunction name="failByteArrayEmpty"> <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/strcmp/tst_strcmp.cpp" line="126"> <Description><![CDATA[Compared values are not the same - Actual (QByteArray("")): + Actual (QByteArray("")) : Expected (QByteArray("foo")): 66 6F 6F]]></Description> </Incident> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_strcmp.xunitxml b/tests/auto/testlib/selftests/expected_strcmp.xunitxml index a900e2f17a..dde9ff5299 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.xunitxml +++ b/tests/auto/testlib/selftests/expected_strcmp.xunitxml @@ -22,11 +22,11 @@ <testcase result="fail" name="failByteArrayNull"> <failure message="Compared values are not the same Actual (QByteArray("foo")): 66 6F 6F - Expected (QByteArray()): " result="fail"/> + Expected (QByteArray()) : " result="fail"/> </testcase> <testcase result="fail" name="failByteArrayEmpty"> <failure message="Compared values are not the same - Actual (QByteArray("")): + Actual (QByteArray("")) : Expected (QByteArray("foo")): 66 6F 6F" result="fail"/> </testcase> <testcase result="fail" name="failByteArraySingleChars"> diff --git a/tests/auto/testlib/selftests/expected_subtest.lightxml b/tests/auto/testlib/selftests/expected_subtest.lightxml index b156dc3991..5adbb771af 100644 --- a/tests/auto/testlib/selftests/expected_subtest.lightxml +++ b/tests/auto/testlib/selftests/expected_subtest.lightxml @@ -122,7 +122,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp" line="154"> <DataTag><![CDATA[data1]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (str): hello1 + Actual (str) : hello1 Expected (QString("hello0")): hello0]]></Description> </Incident> <Message type="qdebug" file="" line="0"> @@ -140,7 +140,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp" line="154"> <DataTag><![CDATA[data2]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (str): hello2 + Actual (str) : hello2 Expected (QString("hello0")): hello0]]></Description> </Incident> <Message type="qdebug" file="" line="0"> diff --git a/tests/auto/testlib/selftests/expected_subtest.txt b/tests/auto/testlib/selftests/expected_subtest.txt index 4537f983e5..bb88f189ec 100644 --- a/tests/auto/testlib/selftests/expected_subtest.txt +++ b/tests/auto/testlib/selftests/expected_subtest.txt @@ -33,14 +33,14 @@ PASS : tst_Subtest::test3(data0) QDEBUG : tst_Subtest::test3(data1) init test3 data1 QDEBUG : tst_Subtest::test3(data1) test2 test3 data1 FAIL! : tst_Subtest::test3(data1) Compared values are not the same - Actual (str): hello1 + Actual (str) : hello1 Expected (QString("hello0")): hello0 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp(154)] QDEBUG : tst_Subtest::test3(data1) cleanup test3 data1 QDEBUG : tst_Subtest::test3(data2) init test3 data2 QDEBUG : tst_Subtest::test3(data2) test2 test3 data2 FAIL! : tst_Subtest::test3(data2) Compared values are not the same - Actual (str): hello2 + Actual (str) : hello2 Expected (QString("hello0")): hello0 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp(154)] QDEBUG : tst_Subtest::test3(data2) cleanup test3 data2 diff --git a/tests/auto/testlib/selftests/expected_subtest.xml b/tests/auto/testlib/selftests/expected_subtest.xml index 365df51e23..094e22383d 100644 --- a/tests/auto/testlib/selftests/expected_subtest.xml +++ b/tests/auto/testlib/selftests/expected_subtest.xml @@ -124,7 +124,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp" line="154"> <DataTag><![CDATA[data1]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (str): hello1 + Actual (str) : hello1 Expected (QString("hello0")): hello0]]></Description> </Incident> <Message type="qdebug" file="" line="0"> @@ -142,7 +142,7 @@ <Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp" line="154"> <DataTag><![CDATA[data2]]></DataTag> <Description><![CDATA[Compared values are not the same - Actual (str): hello2 + Actual (str) : hello2 Expected (QString("hello0")): hello0]]></Description> </Incident> <Message type="qdebug" file="" line="0"> diff --git a/tests/auto/testlib/selftests/expected_subtest.xunitxml b/tests/auto/testlib/selftests/expected_subtest.xunitxml index 6097000e7f..6f8fc3db45 100644 --- a/tests/auto/testlib/selftests/expected_subtest.xunitxml +++ b/tests/auto/testlib/selftests/expected_subtest.xunitxml @@ -38,13 +38,13 @@ <!-- tag="data1" message="init test3 data1 " type="qdebug" --> <!-- tag="data1" message="test2 test3 data1 " type="qdebug" --> <failure tag="data1" message="Compared values are not the same - Actual (str): hello1 + Actual (str) : hello1 Expected (QString("hello0")): hello0" result="fail"/> <!-- tag="data1" message="cleanup test3 data1 " type="qdebug" --> <!-- tag="data2" message="init test3 data2 " type="qdebug" --> <!-- tag="data2" message="test2 test3 data2 " type="qdebug" --> <failure tag="data2" message="Compared values are not the same - Actual (str): hello2 + Actual (str) : hello2 Expected (QString("hello0")): hello0" result="fail"/> <!-- tag="data2" message="cleanup test3 data2 " type="qdebug" --> </testcase> diff --git a/mkspecs/macx-clang-libc++/qplatformdefs.h b/tests/auto/tools/moc/interface-from-include.h index 2c3a8b1c09..ef8d53684b 100644 --- a/mkspecs/macx-clang-libc++/qplatformdefs.h +++ b/tests/auto/tools/moc/interface-from-include.h @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the qmake spec of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -38,6 +38,18 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef INTERFACE_FROM_INCLUDE_H +#define INTERFACE_FROM_INCLUDE_H -#include "../common/mac/qplatformdefs.h" +#include <testinterface.h> +class TestComponent : public QObject, public TestInterface +{ + Q_OBJECT + Q_INTERFACES(TestInterface) +public: + + virtual void foobar() { } +}; + +#endif diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 3459bede85..e7303d716e 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -523,6 +523,7 @@ private slots: void structQObject(); void namespacedFlags(); void warnOnMultipleInheritance(); + void ignoreOptionClashes(); void forgottenQInterface(); void os9Newline(); void winNewline(); @@ -969,6 +970,46 @@ void tst_Moc::warnOnMultipleInheritance() #endif } +void tst_Moc::ignoreOptionClashes() +{ +#ifdef MOC_CROSS_COMPILED + QSKIP("Not tested when cross-compiled"); +#endif +#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(QT_NO_PROCESS) + QProcess proc; + QStringList args; + const QString header = m_sourceDirectory + QStringLiteral("/interface-from-include.h"); + const QString includeDir = m_sourceDirectory + "/Test.framework/Headers"; + // given --ignore-option-clashes, -pthread should be ignored, but the -I path should not be. + args << "--ignore-option-clashes" << "-pthread" << "-I" << includeDir << "-fno-builtin" << header; + proc.start("moc", args); + bool finished = proc.waitForFinished(); + if (!finished) + qWarning("waitForFinished failed. QProcess error: %d", (int)proc.error()); + QVERIFY(finished); + if (proc.exitCode() != 0) { + qDebug() << proc.readAllStandardError(); + } + QCOMPARE(proc.exitCode(), 0); + QCOMPARE(proc.readAllStandardError(), QByteArray()); + QByteArray mocOut = proc.readAllStandardOutput(); + + // If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation. + QStringList gccArgs; + gccArgs << "-c" << "-x" << "c++" << "-I" << ".." + << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIE" << "-"; + proc.start("gcc", gccArgs); + QVERIFY(proc.waitForStarted()); + proc.write(mocOut); + proc.closeWriteChannel(); + + QVERIFY(proc.waitForFinished()); + QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()), QString()); +#else + QSKIP("Only tested on linux/gcc"); +#endif +} + void tst_Moc::forgottenQInterface() { #ifdef MOC_CROSS_COMPILED diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index 65d36247f6..81b69f6b89 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -612,6 +612,8 @@ void tst_QFiledialog::defaultSuffix() QCOMPARE(fd.defaultSuffix(), QString()); fd.setDefaultSuffix("txt"); QCOMPARE(fd.defaultSuffix(), QString("txt")); + fd.setDefaultSuffix(".txt"); + QCOMPARE(fd.defaultSuffix(), QString("txt")); fd.setDefaultSuffix(QString()); QCOMPARE(fd.defaultSuffix(), QString()); } @@ -1334,6 +1336,38 @@ QString saveName(QWidget *, const QString &, const QString &, const QString &, Q return "saveName"; } +QT_BEGIN_NAMESPACE +typedef QUrl (*_qt_filedialog_existing_directory_url_hook)(QWidget *parent, const QString &caption, const QUrl &dir, QFileDialog::Options options, const QStringList &supportedSchemes); +extern Q_WIDGETS_EXPORT _qt_filedialog_existing_directory_url_hook qt_filedialog_existing_directory_url_hook; +QT_END_NAMESPACE +QUrl existingUrl(QWidget *, const QString &, const QUrl &, QFileDialog::Options, const QStringList &) { + return QUrl("http://dirUrl"); +} + +QT_BEGIN_NAMESPACE +typedef QUrl (*_qt_filedialog_open_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes); +extern Q_WIDGETS_EXPORT _qt_filedialog_open_file_url_hook qt_filedialog_open_file_url_hook; +QT_END_NAMESPACE +QUrl openUrl(QWidget *, const QString &, const QUrl &, const QString &, QString *, QFileDialog::Options, const QStringList &) { + return QUrl("http://openUrl"); +} + +QT_BEGIN_NAMESPACE +typedef QList<QUrl> (*_qt_filedialog_open_file_urls_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes); +extern Q_WIDGETS_EXPORT _qt_filedialog_open_file_urls_hook qt_filedialog_open_file_urls_hook; +QT_END_NAMESPACE +QList<QUrl> openUrls(QWidget *, const QString &, const QUrl &, const QString &, QString *, QFileDialog::Options, const QStringList &) { + return QList<QUrl>() << QUrl("http://openUrls"); +} + +QT_BEGIN_NAMESPACE +typedef QUrl (*_qt_filedialog_save_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes); +extern Q_WIDGETS_EXPORT _qt_filedialog_save_file_url_hook qt_filedialog_save_file_url_hook; +QT_END_NAMESPACE +QUrl saveUrl(QWidget *, const QString &, const QUrl &, const QString &, QString *, QFileDialog::Options, const QStringList &) { + return QUrl("http://saveUrl"); +} + void tst_QFiledialog::hooks() { @@ -1346,6 +1380,20 @@ void tst_QFiledialog::hooks() QCOMPARE(QFileDialog::getOpenFileName(), QString("openName")); QCOMPARE(QFileDialog::getOpenFileNames(), QStringList("openNames")); QCOMPARE(QFileDialog::getSaveFileName(), QString("saveName")); + QCOMPARE(QFileDialog::getExistingDirectoryUrl(), QUrl::fromLocalFile("dir")); + QCOMPARE(QFileDialog::getOpenFileUrl(), QUrl::fromLocalFile("openName")); + QCOMPARE(QFileDialog::getOpenFileUrls(), QList<QUrl>() << QUrl::fromLocalFile("openNames")); + QCOMPARE(QFileDialog::getSaveFileUrl(), QUrl::fromLocalFile("saveName")); + + qt_filedialog_existing_directory_url_hook = &existingUrl; + qt_filedialog_save_file_url_hook = &saveUrl; + qt_filedialog_open_file_url_hook = &openUrl; + qt_filedialog_open_file_urls_hook = &openUrls; + + QCOMPARE(QFileDialog::getExistingDirectoryUrl(), QUrl("http://dirUrl")); + QCOMPARE(QFileDialog::getOpenFileUrl(), QUrl("http://openUrl")); + QCOMPARE(QFileDialog::getOpenFileUrls(), QList<QUrl>() << QUrl("http://openUrls")); + QCOMPARE(QFileDialog::getSaveFileUrl(), QUrl("http://saveUrl")); } #ifdef Q_OS_UNIX diff --git a/tests/auto/widgets/graphicsview/graphicsview.pro b/tests/auto/widgets/graphicsview/graphicsview.pro index 9955e45b64..dce3c6dda9 100644 --- a/tests/auto/widgets/graphicsview/graphicsview.pro +++ b/tests/auto/widgets/graphicsview/graphicsview.pro @@ -26,7 +26,7 @@ SUBDIRS=\ qgraphicsscene \ qgraphicssceneindex \ -# These tests require the cleanlooks style -!contains(styles, cleanlooks):SUBDIRS -= \ +# These tests require the fusion style +!contains(styles, fusion):SUBDIRS -= \ qgraphicsproxywidget \ qgraphicswidget \ diff --git a/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/qgraphicsanchorlayout.pro b/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/qgraphicsanchorlayout.pro index 3eb18e61eb..8e8c0708a3 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/qgraphicsanchorlayout.pro +++ b/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/qgraphicsanchorlayout.pro @@ -3,4 +3,3 @@ TARGET = tst_qgraphicsanchorlayout QT += widgets widgets-private testlib QT += core-private gui-private SOURCES += tst_qgraphicsanchorlayout.cpp -CONFIG += parallel_test diff --git a/tests/auto/widgets/graphicsview/qgraphicseffectsource/qgraphicseffectsource.pro b/tests/auto/widgets/graphicsview/qgraphicseffectsource/qgraphicseffectsource.pro index 4fe3405d11..550d3debf7 100644 --- a/tests/auto/widgets/graphicsview/qgraphicseffectsource/qgraphicseffectsource.pro +++ b/tests/auto/widgets/graphicsview/qgraphicseffectsource/qgraphicseffectsource.pro @@ -5,4 +5,3 @@ QT += widgets widgets-private testlib QT += core-private gui-private SOURCES += tst_qgraphicseffectsource.cpp -CONFIG += parallel_test diff --git a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/qgraphicsgridlayout.pro b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/qgraphicsgridlayout.pro index 5796cbfd73..e49139a8ad 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/qgraphicsgridlayout.pro +++ b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/qgraphicsgridlayout.pro @@ -3,4 +3,3 @@ TARGET = tst_qgraphicsgridlayout QT += widgets testlib SOURCES += tst_qgraphicsgridlayout.cpp -CONFIG += parallel_test diff --git a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp index 8c8f27d635..1ffb5c3b5c 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp @@ -126,6 +126,7 @@ private slots: void spanningItem2x3_data(); void spanningItem2x3(); void spanningItem(); + void spanAcrossEmptyRow(); void heightForWidth(); void widthForHeight(); void heightForWidthWithSpanning(); @@ -3192,23 +3193,19 @@ void tst_QGraphicsGridLayout::heightForWidthWithSpanning() QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, -1)), QSizeF(1, 1)); QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(-1, -1)), QSizeF(200, 100)); - QEXPECT_FAIL("", "Due to an old bug this wrongly returns QWIDGETSIZE_MAX", Continue); QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(-1, -1)), QSizeF(30000, 30000)); QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(200, -1)), QSizeF(200, 100)); QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(200, -1)), QSizeF(200, 100)); - QEXPECT_FAIL("", "Due to an old bug this wrongly returns QWIDGETSIZE_MAX", Continue); QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(200, -1)), QSizeF(200, 100)); QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(2, -1)), QSizeF(2, 10000)); QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(2, -1)), QSizeF(2, 10000)); - QEXPECT_FAIL("", "Due to an old bug this wrongly returns QWIDGETSIZE_MAX", Continue); QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(2, -1)), QSizeF(2, 10000)); QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(200, -1)), QSizeF(200, 100)); QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(200, -1)), QSizeF(200, 100)); - QEXPECT_FAIL("", "Due to an old bug this wrongly returns QWIDGETSIZE_MAX", Continue); - QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(200, -1)), QSizeF(200, 10000)); + QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(200, -1)), QSizeF(200, 100)); } Q_DECLARE_METATYPE(QSizePolicy::Policy) @@ -3364,6 +3361,37 @@ void tst_QGraphicsGridLayout::spanningItem() QCOMPARE(layout->maximumSize(), QSizeF(160,80)); } +void tst_QGraphicsGridLayout::spanAcrossEmptyRow() +{ + QGraphicsWidget *form = new QGraphicsWidget(0, Qt::Window); + QGraphicsGridLayout *layout = new QGraphicsGridLayout(form); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + RectWidget *w1 = new RectWidget; + RectWidget *w2 = new RectWidget; + RectWidget *w3 = new RectWidget; + + QSizeF size(10, 10); + for (int i = 0; i < 3; ++i) { + w1->setSizeHint((Qt::SizeHint)i, size); + w2->setSizeHint((Qt::SizeHint)i, size); + w3->setSizeHint((Qt::SizeHint)i, size); + size+=size; //[(10,10), (20,20), (40,40)] + } + layout->addItem(w1, 0, 0, 1, 1); + layout->addItem(w2, 0, 1, 1, 2); + layout->addItem(w3, 0, 99, 1, 1); + + form->resize(60,20); + QCOMPARE(w1->geometry(), QRectF( 0, 0, 20, 20)); + QCOMPARE(w2->geometry(), QRectF(20, 0, 20, 20)); + QCOMPARE(w3->geometry(), QRectF(40, 0, 20, 20)); + + QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize), QSizeF(30, 10)); + QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize), QSizeF(60, 20)); + QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize), QSizeF(120, 40)); +} + void tst_QGraphicsGridLayout::stretchAndHeightForWidth() { QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window); diff --git a/tests/auto/widgets/graphicsview/qgraphicslinearlayout/qgraphicslinearlayout.pro b/tests/auto/widgets/graphicsview/qgraphicslinearlayout/qgraphicslinearlayout.pro index 50a886cece..2bf1a1d676 100644 --- a/tests/auto/widgets/graphicsview/qgraphicslinearlayout/qgraphicslinearlayout.pro +++ b/tests/auto/widgets/graphicsview/qgraphicslinearlayout/qgraphicslinearlayout.pro @@ -2,5 +2,3 @@ CONFIG += testcase TARGET = tst_qgraphicslinearlayout QT += widgets testlib SOURCES += tst_qgraphicslinearlayout.cpp -CONFIG += parallel_test - diff --git a/tests/auto/widgets/graphicsview/qgraphicssceneindex/qgraphicssceneindex.pro b/tests/auto/widgets/graphicsview/qgraphicssceneindex/qgraphicssceneindex.pro index 5fd3bdf8d6..3d0d73566e 100644 --- a/tests/auto/widgets/graphicsview/qgraphicssceneindex/qgraphicssceneindex.pro +++ b/tests/auto/widgets/graphicsview/qgraphicssceneindex/qgraphicssceneindex.pro @@ -4,5 +4,4 @@ requires(contains(QT_CONFIG,private_tests)) QT += widgets widgets-private testlib QT += core-private gui-private SOURCES += tst_qgraphicssceneindex.cpp -CONFIG += parallel_test DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/widgets/graphicsview/qgraphicswidget/qgraphicswidget.pro b/tests/auto/widgets/graphicsview/qgraphicswidget/qgraphicswidget.pro index 4e119cbcb3..481bc96d96 100644 --- a/tests/auto/widgets/graphicsview/qgraphicswidget/qgraphicswidget.pro +++ b/tests/auto/widgets/graphicsview/qgraphicswidget/qgraphicswidget.pro @@ -6,5 +6,4 @@ QT += core-private gui-private SOURCES += tst_qgraphicswidget.cpp -linux-*:system(". /etc/lsb-release && [ $DISTRIB_CODENAME = lucid ]"):DEFINES+=UBUNTU_LUCID # QTBUG-20778 DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp index 31439e203c..2dd2089f81 100644 --- a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp @@ -3194,9 +3194,6 @@ void tst_QGraphicsWidget::initialShow2() qApp->setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); -#ifdef UBUNTU_LUCID - QEXPECT_FAIL("", "QTBUG-20778", Abort); -#endif QTRY_COMPARE(widget->repaints, expectedRepaintCount); } diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp index 8e888f06ee..dfb780c8fa 100644 --- a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp +++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp @@ -106,6 +106,8 @@ private slots: void moveCursorStrikesBack_data(); void moveCursorStrikesBack(); + void moveCursorBiggerJump(); + void hideRows_data(); void hideRows(); @@ -1354,6 +1356,34 @@ void tst_QTableView::moveCursorStrikesBack() QCOMPARE(newColumn, expectedColumn); } +void tst_QTableView::moveCursorBiggerJump() +{ + QtTestTableModel model(50, 7); + QTableView view; + view.setModel(&model); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + int height = view.horizontalHeader()->height(); + for (int i=0;i<8;i++) + height += view.verticalHeader()->sectionSize(i); + view.resize(view.width(), height); + view.setCurrentIndex(model.index(0,0)); + + QTest::keyClick(&view, Qt::Key_PageDown); + QCOMPARE(view.indexAt(QPoint(0,0)), model.index(1,0)); + QTest::keyClick(&view, Qt::Key_PageDown); + QCOMPARE(view.indexAt(QPoint(0,0)), model.index(8,0)); + QTest::keyClick(&view, Qt::Key_PageDown); + QCOMPARE(view.indexAt(QPoint(0,0)), model.index(15,0)); + QTest::keyClick(&view, Qt::Key_PageUp); + QCOMPARE(view.indexAt(QPoint(0,0)), model.index(14,0)); + QTest::keyClick(&view, Qt::Key_PageUp); + QCOMPARE(view.indexAt(QPoint(0,0)), model.index(7,0)); + QTest::keyClick(&view, Qt::Key_PageUp); + QCOMPARE(view.indexAt(QPoint(0,0)), model.index(0,0)); +} + void tst_QTableView::hideRows_data() { QTest::addColumn<int>("rowCount"); @@ -3762,8 +3792,6 @@ void tst_QTableView::task259308_scrollVerticalHeaderSwappedSections() QTRY_COMPARE(tv.rowAt(0), tv.verticalHeader()->logicalIndex(0)); int newRow = tv.rowAt(tv.viewport()->height()); - if (newRow == tv.rowAt(tv.viewport()->height() - 1)) // Overlapping row - newRow++; QTest::keyClick(&tv, Qt::Key_PageDown); // Scroll down and check current QTRY_COMPARE(tv.currentIndex().row(), newRow); diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 9a7b7956d8..dcda9f7fd7 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -2017,6 +2017,8 @@ void tst_QTreeView::clicked() view.setModel(&model); view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QModelIndex firstIndex = model.index(0, 0, QModelIndex()); QVERIFY(firstIndex.isValid()); int itemHeight = view.visualRect(firstIndex).height(); diff --git a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp index 2b9b4fd761..ab2df2e250 100644 --- a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp +++ b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp @@ -84,6 +84,7 @@ private slots: void controlTypes(); void controlTypes2(); void adjustSizeShouldMakeSureLayoutIsActivated(); + void testRetainSizeWhenHidden(); }; tst_QLayout::tst_QLayout() @@ -350,5 +351,47 @@ void tst_QLayout::adjustSizeShouldMakeSureLayoutIsActivated() QCOMPARE(main.size(), QSize(200, 10)); } +void tst_QLayout::testRetainSizeWhenHidden() +{ + QWidget widget; + QBoxLayout layout(QBoxLayout::TopToBottom, &widget); + + QLabel *label1 = new QLabel("label1 text", &widget); + layout.addWidget(label1); + QLabel *label2 = new QLabel("label2 text", &widget); + layout.addWidget(label2); + + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + int normalHeight = widget.height(); + + // a. Verify that a removed visible will mean lesser size after adjust + label1->hide(); + widget.adjustSize(); + int heightWithoutLabel1 = widget.height(); + QVERIFY(heightWithoutLabel1 < normalHeight); + + // b restore with verify that the size is the same + label1->show(); + QCOMPARE(widget.sizeHint().height(), normalHeight); + + // c verify that a policy with retainSizeWhenHidden is respected + QSizePolicy sp_remove = label1->sizePolicy(); + QSizePolicy sp_retain = label1->sizePolicy(); + sp_retain.setRetainSizeWhenHidden(true); + + label1->setSizePolicy(sp_retain); + label1->hide(); + QCOMPARE(widget.sizeHint().height(), normalHeight); + + // d check that changing the policy to not wanting size will result in lesser size + label1->setSizePolicy(sp_remove); + QCOMPARE(widget.sizeHint().height(), heightWithoutLabel1); + + // e verify that changing back the hidden widget to want the hidden size will ensure that it gets more size + label1->setSizePolicy(sp_retain); + QCOMPARE(widget.sizeHint().height(), normalHeight); +} + QTEST_MAIN(tst_QLayout) #include "tst_qlayout.moc" diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 82d3fae0fa..4631154230 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -160,6 +160,7 @@ private slots: void maxVisibleItems(); void task_QTBUG_10491_currentIndexAndModelColumn(); void highlightedSignal(); + void itemData(); void task_QTBUG_31146_popupCompletion(); }; @@ -2756,6 +2757,151 @@ void tst_QComboBox::highlightedSignal() QCOMPARE(spy.size(), 1); } +void tst_QComboBox::itemData() +{ + QComboBox comboBox; + const int itemCount = 10; + + // ensure that the currentText(), the DisplayRole and the EditRole + // stay in sync when using QComboBox's default model + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("item text %1").arg(i); + comboBox.addItem(itemText); + } + + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("item text %1").arg(i); + QCOMPARE(comboBox.itemText(i), itemText); + QCOMPARE(comboBox.itemData(i, Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i, Qt::EditRole).toString(), itemText); + + comboBox.setCurrentIndex(i); + QCOMPARE(comboBox.currentIndex(), i); + QCOMPARE(comboBox.currentText(), itemText); + QCOMPARE(comboBox.currentData(Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.currentData(Qt::EditRole).toString(), itemText); + } + + for (int i = 0; i < itemCount; ++i) { + // now change by using setItemText + QString itemText = QString("setItemText %1").arg(i); + comboBox.setItemText(i, itemText); + } + + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("setItemText %1").arg(i); + QCOMPARE(comboBox.itemText(i), itemText); + QCOMPARE(comboBox.itemData(i, Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i, Qt::EditRole).toString(), itemText); + + comboBox.setCurrentIndex(i); + QCOMPARE(comboBox.currentIndex(), i); + QCOMPARE(comboBox.currentText(), itemText); + QCOMPARE(comboBox.currentData(Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.currentData(Qt::EditRole).toString(), itemText); + } + + for (int i = 0; i < itemCount; ++i) { + // now change by changing the DisplayRole's data + QString itemText = QString("setItemData(DisplayRole) %1").arg(i); + comboBox.setItemData(i, QVariant(itemText), Qt::DisplayRole); + } + + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("setItemData(DisplayRole) %1").arg(i); + QCOMPARE(comboBox.itemText(i), itemText); + QCOMPARE(comboBox.itemData(i, Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i, Qt::EditRole).toString(), itemText); + + comboBox.setCurrentIndex(i); + QCOMPARE(comboBox.currentIndex(), i); + QCOMPARE(comboBox.currentText(), itemText); + QCOMPARE(comboBox.currentData(Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.currentData(Qt::EditRole).toString(), itemText); + } + + for (int i = 0; i < itemCount; ++i) { + // now change by changing the EditRole's data + QString itemText = QString("setItemData(EditRole) %1").arg(i); + comboBox.setItemData(i, QVariant(itemText), Qt::EditRole); + } + + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("setItemData(EditRole) %1").arg(i); + QCOMPARE(comboBox.itemText(i), itemText); + QCOMPARE(comboBox.itemData(i, Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i, Qt::EditRole).toString(), itemText); + + comboBox.setCurrentIndex(i); + QCOMPARE(comboBox.currentIndex(), i); + QCOMPARE(comboBox.currentText(), itemText); + QCOMPARE(comboBox.currentData(Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.currentData(Qt::EditRole).toString(), itemText); + } + + comboBox.clear(); + + + // set additional user data in the addItem call + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("item text %1").arg(i); + QString itemDataText = QString("item data %1").arg(i); + comboBox.addItem(itemText, QVariant(itemDataText)); + } + + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("item text %1").arg(i); + QString itemDataText = QString("item data %1").arg(i); + QCOMPARE(comboBox.itemData(i, Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i, Qt::EditRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i).toString(), itemDataText); + + comboBox.setCurrentIndex(i); + QCOMPARE(comboBox.currentIndex(), i); + QCOMPARE(comboBox.currentData(Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.currentData(Qt::EditRole).toString(), itemText); + QCOMPARE(comboBox.currentData().toString(), itemDataText); + + } + + comboBox.clear(); + + + // additional roles, setItemData + // UserRole + 0 -> string + // UserRole + 1 -> double + // UserRole + 2 -> icon + QString qtlogoPath = QFINDTESTDATA("qtlogo.png"); + QIcon icon = QIcon(QPixmap(qtlogoPath)); + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("item text %1").arg(i); + QString itemDataText = QString("item data %1").arg(i); + double d = i; + comboBox.addItem(itemText); + comboBox.setItemData(i, QVariant(itemDataText), Qt::UserRole); + comboBox.setItemData(i, QVariant(d), Qt::UserRole + 1); + comboBox.setItemData(i, QVariant::fromValue(icon), Qt::UserRole + 2); + } + + for (int i = 0; i < itemCount; ++i) { + QString itemText = QString("item text %1").arg(i); + QString itemDataText = QString("item data %1").arg(i); + double d = i; + QCOMPARE(comboBox.itemData(i, Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i, Qt::EditRole).toString(), itemText); + QCOMPARE(comboBox.itemData(i, Qt::UserRole).toString(), itemDataText); + QCOMPARE(comboBox.itemData(i, Qt::UserRole + 1).toDouble(), d); + QCOMPARE(comboBox.itemData(i, Qt::UserRole + 2).value<QIcon>(), icon); + + comboBox.setCurrentIndex(i); + QCOMPARE(comboBox.currentData(Qt::DisplayRole).toString(), itemText); + QCOMPARE(comboBox.currentData(Qt::EditRole).toString(), itemText); + QCOMPARE(comboBox.currentData(Qt::UserRole).toString(), itemDataText); + QCOMPARE(comboBox.currentData(Qt::UserRole + 1).toDouble(), d); + QCOMPARE(comboBox.currentData(Qt::UserRole + 2).value<QIcon>(), icon); + } +} + void tst_QComboBox::task_QTBUG_31146_popupCompletion() { QComboBox comboBox; diff --git a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp index b0e454b643..db5b89f396 100644 --- a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp +++ b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp @@ -72,6 +72,8 @@ private slots: void testConstructor2_data(); void testConstructor3(); void testConstructor3_data(); + void testConstructor4(); + void testConstructor4_data(); void setOrientation_data(); void setOrientation(); void addButton1_data(); @@ -201,6 +203,41 @@ void tst_QDialogButtonBox::testConstructor3() QTEST(buttonBox.buttons().count(), "buttonCount"); } +void tst_QDialogButtonBox::testConstructor4_data() +{ + QTest::addColumn<QDialogButtonBox::StandardButtons>("buttons"); + QTest::addColumn<int>("buttonCount"); + + QTest::newRow("nothing") << (QDialogButtonBox::StandardButtons)0 << 0; + QTest::newRow("only 1") << QDialogButtonBox::StandardButtons(QDialogButtonBox::Ok) << 1; + QTest::newRow("only 1.. twice") + << (QDialogButtonBox::Ok | QDialogButtonBox::Ok) + << 1; + QTest::newRow("only 2") + << (QDialogButtonBox::Ok | QDialogButtonBox::Cancel) + << 2; + QTest::newRow("two different things") + << (QDialogButtonBox::Save | QDialogButtonBox::Close) + << 2; + QTest::newRow("three") + << (QDialogButtonBox::Ok + | QDialogButtonBox::Cancel + | QDialogButtonBox::Help) + << 3; + QTest::newRow("everything") + << (QDialogButtonBox::StandardButtons)UINT_MAX + << 18; +} + +void tst_QDialogButtonBox::testConstructor4() +{ + QFETCH(QDialogButtonBox::StandardButtons, buttons); + + QDialogButtonBox buttonBox(buttons); + QCOMPARE(buttonBox.orientation(), Qt::Horizontal); + QTEST(buttonBox.buttons().count(), "buttonCount"); +} + void tst_QDialogButtonBox::setOrientation_data() { QTest::addColumn<int>("orientation"); diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index d428e2705d..3000aad9ce 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -46,6 +46,9 @@ #include "qstringlist.h" #include "qstyle.h" #include "qvalidator.h" +#include "qwidgetaction.h" +#include "qimage.h" +#include "qicon.h" #include "qcompleter.h" #include "qstandarditemmodel.h" #include <qpa/qplatformtheme.h> @@ -61,8 +64,12 @@ #include <private/qlineedit_p.h> #include <private/qwidgetlinecontrol_p.h> #include <qmenu.h> +#include <qlabel.h> #include <qlayout.h> #include <qspinbox.h> +#include <qlistview.h> +#include <qstringlistmodel.h> +#include <qsortfilterproxymodel.h> #include <qdebug.h> #include "qcommonstyle.h" @@ -290,6 +297,9 @@ private slots: void undoRedoAndEchoModes_data(); void undoRedoAndEchoModes(); + void clearButton(); + void sideWidgets(); + protected slots: void editingFinished(); @@ -866,12 +876,18 @@ public: void tst_QLineEdit::hasAcceptableInputValidator() { + QSignalSpy spyChanged(testWidget, SIGNAL(textChanged(QString))); + QSignalSpy spyEdited(testWidget, SIGNAL(textEdited(QString))); + QFocusEvent lostFocus(QEvent::FocusOut); ValidatorWithFixup val; testWidget->setValidator(&val); testWidget->setText("foobar"); qApp->sendEvent(testWidget, &lostFocus); QVERIFY(testWidget->hasAcceptableInput()); + + QCOMPARE(spyChanged.count(), 2); + QCOMPARE(spyEdited.count(), 0); } @@ -4042,5 +4058,80 @@ void tst_QLineEdit::undoRedoAndEchoModes() QCOMPARE(testWidget->text(), expected.at(2)); } +void tst_QLineEdit::clearButton() +{ + // Construct a listview with a stringlist model and filter model. + QWidget testWidget; + QVBoxLayout *l = new QVBoxLayout(&testWidget); + QLineEdit *filterLineEdit = new QLineEdit(&testWidget); + l->addWidget(filterLineEdit); + QListView *listView = new QListView(&testWidget); + QStringListModel *model = new QStringListModel(QStringList() << QStringLiteral("aa") << QStringLiteral("ab") << QStringLiteral("cc"), listView); + QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(listView); + filterModel->setSourceModel(model); + connect(filterLineEdit, SIGNAL(textChanged(QString)), filterModel, SLOT(setFilterFixedString(QString))); + listView->setModel(filterModel); + l->addWidget(listView); + testWidget.move(300, 300); + testWidget.show(); + qApp->setActiveWindow(&testWidget); + QVERIFY(QTest::qWaitForWindowActive(&testWidget)); + // Flip the clear button on,off, trying to detect crashes. + filterLineEdit->setClearButtonEnabled(true); + QVERIFY(filterLineEdit->isClearButtonEnabled()); + filterLineEdit->setClearButtonEnabled(true); + QVERIFY(filterLineEdit->isClearButtonEnabled()); + filterLineEdit->setClearButtonEnabled(false); + QVERIFY(!filterLineEdit->isClearButtonEnabled()); + filterLineEdit->setClearButtonEnabled(false); + QVERIFY(!filterLineEdit->isClearButtonEnabled()); + filterLineEdit->setClearButtonEnabled(true); + QVERIFY(filterLineEdit->isClearButtonEnabled()); + // Emulate filtering + QToolButton *clearButton = filterLineEdit->findChild<QToolButton *>(); + QVERIFY(clearButton); + QCOMPARE(filterModel->rowCount(), 3); + QTest::keyClick(filterLineEdit, 'a'); + QTRY_COMPARE(filterModel->rowCount(), 2); // matches 'aa', 'ab' + QTest::keyClick(filterLineEdit, 'b'); + QTRY_COMPARE(filterModel->rowCount(), 1); // matches 'ab' + QTest::mouseClick(clearButton, Qt::LeftButton, 0, QRect(QPoint(0, 0), clearButton->size()).center()); + QTRY_COMPARE(filterModel->rowCount(), 3); +} + +void tst_QLineEdit::sideWidgets() +{ + QWidget testWidget; + QVBoxLayout *l = new QVBoxLayout(&testWidget); + QLineEdit *lineEdit = new QLineEdit(&testWidget); + l->addWidget(lineEdit); + l->addSpacerItem(new QSpacerItem(0, 50, QSizePolicy::Ignored, QSizePolicy::Fixed)); + QImage image(QSize(20, 20), QImage::Format_ARGB32); + image.fill(Qt::yellow); + QAction *iconAction = new QAction(QIcon(QPixmap::fromImage(image)), QString(), lineEdit); + QWidgetAction *label1Action = new QWidgetAction(lineEdit); + label1Action->setDefaultWidget(new QLabel(QStringLiteral("l1"))); + QWidgetAction *label2Action = new QWidgetAction(lineEdit); + label2Action->setDefaultWidget(new QLabel(QStringLiteral("l2"))); + QWidgetAction *label3Action = new QWidgetAction(lineEdit); + label3Action->setDefaultWidget(new QLabel(QStringLiteral("l3"))); + lineEdit->addAction(iconAction, QLineEdit::LeadingPosition); + lineEdit->addAction(label2Action, QLineEdit::LeadingPosition); + lineEdit->addAction(label1Action, QLineEdit::TrailingPosition); + lineEdit->addAction(label3Action, QLineEdit::TrailingPosition); + testWidget.move(300, 300); + testWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&testWidget)); + // Arbitrarily add/remove actions, trying to detect crashes. Add QTRY_VERIFY(false) to view the result. + delete label3Action; + lineEdit->removeAction(label2Action); + lineEdit->removeAction(iconAction); + lineEdit->removeAction(label1Action); + lineEdit->removeAction(iconAction); + lineEdit->removeAction(label1Action); + lineEdit->addAction(iconAction); + lineEdit->addAction(iconAction); +} + QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc" diff --git a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp index a64b34c56a..004fdda5ef 100644 --- a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp +++ b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp @@ -98,6 +98,9 @@ private slots: void setValue_data(); void setValue(); + void setDisplayIntegerBase_data(); + void setDisplayIntegerBase(); + void setPrefixSuffix_data(); void setPrefixSuffix(); @@ -274,6 +277,61 @@ void tst_QSpinBox::setValue() QCOMPARE(spin.value(), expected); } +void tst_QSpinBox::setDisplayIntegerBase_data() +{ + QTest::addColumn<int>("value"); + QTest::addColumn<int>("base"); + QTest::addColumn<QString>("string"); + + QTest::newRow("base 10") << 42 << 10 << "42"; + QTest::newRow("base 2") << 42 << 2 << "101010"; + QTest::newRow("base 8") << 42 << 8 << "52"; + QTest::newRow("base 16") << 42 << 16 << "2a"; + QTest::newRow("base 0") << 42 << 0 << "42"; + QTest::newRow("base -4") << 42 << -4 << "42"; + QTest::newRow("base 40") << 42 << 40 << "42"; + + QTest::newRow("negative base 10") << -42 << 10 << "-42"; + QTest::newRow("negative base 2") << -42 << 2 << "-101010"; + QTest::newRow("negative base 8") << -42 << 8 << "-52"; + QTest::newRow("negative base 16") << -42 << 16 << "-2a"; + QTest::newRow("negative base 0") << -42 << 0 << "-42"; + QTest::newRow("negative base -4") << -42 << -4 << "-42"; + QTest::newRow("negative base 40") << -42 << 40 << "-42"; + + QTest::newRow("0 base 10") << 0 << 10 << "0"; + QTest::newRow("0 base 2") << 0 << 2 << "0"; + QTest::newRow("0 base 8") << 0 << 8 << "0"; + QTest::newRow("0 base 16") << 0 << 16 << "0"; + QTest::newRow("0 base 0") << 0 << 0 << "0"; + QTest::newRow("0 base -4") << 0 << -4 << "0"; + QTest::newRow("0 base 40") << 0 << 40 << "0"; +} + +void tst_QSpinBox::setDisplayIntegerBase() +{ + QFETCH(int, value); + QFETCH(int, base); + QFETCH(QString, string); + + SpinBox spin; + spin.setRange(INT_MIN, INT_MAX); + + spin.setValue(value); + QCOMPARE(spin.lineEdit()->text(), QString::number(value)); + + spin.setDisplayIntegerBase(base); + QCOMPARE(spin.lineEdit()->text(), string); + + spin.setValue(0); + QCOMPARE(spin.value(), 0); + QCOMPARE(spin.lineEdit()->text(), QString::number(0, base)); + + spin.lineEdit()->clear(); + QTest::keyClicks(spin.lineEdit(), string); + QCOMPARE(spin.value(), value); +} + void tst_QSpinBox::setPrefixSuffix_data() { QTest::addColumn<QString>("prefix"); diff --git a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp index a188e3bfe1..0dac7d85e4 100644 --- a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp +++ b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp @@ -97,6 +97,8 @@ private slots: void changeTitleWhileDoubleClickingTab(); void taskQTBUG_10052_widgetLayoutWhenMoving(); + + void tabBarClicked(); }; // Testing get/set functions @@ -652,5 +654,45 @@ void tst_QTabBar::taskQTBUG_10052_widgetLayoutWhenMoving() QVERIFY(w2.moved); } +void tst_QTabBar::tabBarClicked() +{ + QTabBar tabBar; + tabBar.addTab("0"); + QSignalSpy clickSpy(&tabBar, SIGNAL(tabBarClicked(int))); + QSignalSpy doubleClickSpy(&tabBar, SIGNAL(tabBarDoubleClicked(int))); + + QCOMPARE(clickSpy.count(), 0); + QCOMPARE(doubleClickSpy.count(), 0); + + Qt::MouseButton button = Qt::LeftButton; + while (button <= Qt::MaxMouseButton) { + const QPoint tabPos = tabBar.tabRect(0).center(); + + QTest::mouseClick(&tabBar, button, 0, tabPos); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); + QCOMPARE(doubleClickSpy.count(), 0); + + QTest::mouseDClick(&tabBar, button, 0, tabPos); + QCOMPARE(clickSpy.count(), 0); + QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), 0); + + const QPoint barPos(tabBar.tabRect(0).right() + 5, tabBar.tabRect(0).center().y()); + + QTest::mouseClick(&tabBar, button, 0, barPos); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); + QCOMPARE(doubleClickSpy.count(), 0); + + QTest::mouseDClick(&tabBar, button, 0, barPos); + QCOMPARE(clickSpy.count(), 0); + QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), -1); + + button = Qt::MouseButton(button << 1); + } +} + QTEST_MAIN(tst_QTabBar) #include "tst_qtabbar.moc" diff --git a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp index 5dd9ee9b0f..fa518e6afd 100644 --- a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp +++ b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp @@ -42,6 +42,7 @@ #include <QtTest/QtTest> #include <qtabwidget.h> +#include <qtabbar.h> #include <qdebug.h> #include <qapplication.h> #include <qlabel.h> @@ -110,6 +111,7 @@ class tst_QTabWidget:public QObject { void minimumSizeHint(); void heightForWidth_data(); void heightForWidth(); + void tabBarClicked(); private: int addPage(); @@ -666,6 +668,46 @@ void tst_QTabWidget::heightForWidth() delete window; } +void tst_QTabWidget::tabBarClicked() +{ + QTabWidget tabWidget; + tabWidget.addTab(new QWidget(&tabWidget), "0"); + QSignalSpy clickSpy(&tabWidget, SIGNAL(tabBarClicked(int))); + QSignalSpy doubleClickSpy(&tabWidget, SIGNAL(tabBarDoubleClicked(int))); + + QCOMPARE(clickSpy.count(), 0); + QCOMPARE(doubleClickSpy.count(), 0); + + QTabBar &tabBar = *tabWidget.tabBar(); + Qt::MouseButton button = Qt::LeftButton; + while (button <= Qt::MaxMouseButton) { + const QPoint tabPos = tabBar.tabRect(0).center(); + + QTest::mouseClick(&tabBar, button, 0, tabPos); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); + QCOMPARE(doubleClickSpy.count(), 0); + + QTest::mouseDClick(&tabBar, button, 0, tabPos); + QCOMPARE(clickSpy.count(), 0); + QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), 0); + + const QPoint barPos(tabBar.tabRect(0).right() + 5, tabBar.tabRect(0).center().y()); + + QTest::mouseClick(&tabBar, button, 0, barPos); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); + QCOMPARE(doubleClickSpy.count(), 0); + + QTest::mouseDClick(&tabBar, button, 0, barPos); + QCOMPARE(clickSpy.count(), 0); + QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), -1); + + button = Qt::MouseButton(button << 1); + } +} QTEST_MAIN(tst_QTabWidget) #include "tst_qtabwidget.moc" diff --git a/tests/benchmarks/corelib/io/qfile/main.cpp b/tests/benchmarks/corelib/io/qfile/main.cpp index ef5fd36254..0beffebfb7 100644 --- a/tests/benchmarks/corelib/io/qfile/main.cpp +++ b/tests/benchmarks/corelib/io/qfile/main.cpp @@ -54,6 +54,10 @@ # include <windows.h> #endif +#if defined(Q_OS_QNX) && defined(open) +#undef open +#endif + #define BUFSIZE 1024*512 #define FACTOR 1024*512 #define TF_SIZE FACTOR*81 diff --git a/tests/benchmarks/corelib/tools/qset/main.cpp b/tests/benchmarks/corelib/tools/qset/main.cpp new file mode 100644 index 0000000000..744cc745d3 --- /dev/null +++ b/tests/benchmarks/corelib/tools/qset/main.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QSet> +#include <QTest> + +class tst_QSet : public QObject +{ + Q_OBJECT + +private slots: + void intersect_int_data(); + void intersect_int(); + void intersect_complexType_data(); + void intersect_complexType(); +}; + +void tst_QSet::intersect_int_data() +{ + QTest::addColumn<int>("lhsSize"); + QTest::addColumn<int>("rhsSize"); + QTest::addColumn<int>("intersectSize"); + + QTest::newRow("1000000.intersect(1000) = empty") << 1000000 << 1000 << 0; + QTest::newRow("1000.intersect(1000000) = empty") << 1000 << 1000000 << 0; + QTest::newRow("1000000.intersect(1000) = 500") << 1000000 << 1000 << 500; + QTest::newRow("1000.intersect(1000000) = 500") << 1000 << 1000000 << 500; + QTest::newRow("1000000.intersect(1000) = 1000") << 1000000 << 1000 << 1000; + QTest::newRow("1000.intersect(1000000) = 1000") << 1000 << 1000000 << 1000; +} + +void tst_QSet::intersect_int() +{ + QFETCH(int, lhsSize); + QFETCH(int, rhsSize); + QFETCH(int, intersectSize); + + // E.g. when lhsSize = 1000, rhsSize = 1000000 and intersectSize = 500: + // lhsSize = { 0, 1, ... 1000 } + // rhsSize = { 500, 501, ... 1000500 } + + QSet<int> lhs; + for (int i = 0; i < lhsSize; ++i) + lhs.insert(i); + + QSet<int> rhs; + const int start = lhsSize - intersectSize; + for (int i = start; i < start + rhsSize; ++i) + rhs.insert(i); + + QBENCHMARK { + lhs.intersect(rhs); + } + + QVERIFY(lhs.size() == intersectSize); +} + +struct ComplexType +{ + ComplexType(int a) : a(a) {} + int a; + int b; + int c; +}; + +inline uint qHash(const ComplexType &key, uint seed = 0) +{ + return uint(key.a) ^ seed; +} + +inline bool operator==(const ComplexType &lhs, const ComplexType &rhs) +{ + return lhs.a == rhs.a; +} + +void tst_QSet::intersect_complexType_data() +{ + intersect_int_data(); +} + +void tst_QSet::intersect_complexType() +{ + QFETCH(int, lhsSize); + QFETCH(int, rhsSize); + QFETCH(int, intersectSize); + + QSet<ComplexType> lhs; + for (int i = 0; i < lhsSize; ++i) + lhs.insert(ComplexType(i)); + + QSet<ComplexType> rhs; + const int start = lhsSize - intersectSize; + for (int i = start; i < start + rhsSize; ++i) + rhs.insert(ComplexType(i)); + + QBENCHMARK { + lhs.intersect(rhs); + } +} + +QTEST_MAIN(tst_QSet) + +#include "main.moc" diff --git a/tests/benchmarks/corelib/tools/qset/qset.pro b/tests/benchmarks/corelib/tools/qset/qset.pro new file mode 100644 index 0000000000..8fb8bcfa0b --- /dev/null +++ b/tests/benchmarks/corelib/tools/qset/qset.pro @@ -0,0 +1,4 @@ +TARGET = tst_qset +QT = core testlib +SOURCES += main.cpp +CONFIG += release diff --git a/tests/benchmarks/gui/itemviews/qtableview/tst_qtableview.cpp b/tests/benchmarks/gui/itemviews/qtableview/tst_qtableview.cpp index c32ff0d099..b590269b70 100644 --- a/tests/benchmarks/gui/itemviews/qtableview/tst_qtableview.cpp +++ b/tests/benchmarks/gui/itemviews/qtableview/tst_qtableview.cpp @@ -44,6 +44,8 @@ #include <QTableView> #include <QImage> #include <QPainter> +#include <QHeaderView> +#include <QStandardItemModel> class QtTestTableModel: public QAbstractTableModel { @@ -149,6 +151,7 @@ private slots: void columnInsertion(); void columnRemoval_data(); void columnRemoval(); + void sizeHintForColumnWhenHidden(); private: static inline void spanInit_helper(QTableView *); }; @@ -361,5 +364,23 @@ void tst_QTableView::columnRemoval() } } +void tst_QTableView::sizeHintForColumnWhenHidden() +{ + QTableView view; + QStandardItemModel model(12500, 6); + for (int r = 0; r < model.rowCount(); ++r) + for (int c = 0; c < model.columnCount(); ++c) { + QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(r).arg(c)); + model.setItem(r, c, item); + } + + view.horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + view.setModel(&model); + QBENCHMARK_ONCE { + view.horizontalHeader()->resizeSection(0, 10); // this force resizeSections - on a hidden view. + } + +} + QTEST_MAIN(tst_QTableView) #include "tst_qtableview.moc" diff --git a/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro b/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro index 7031b83210..92d20f50d0 100644 --- a/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro +++ b/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro @@ -2,7 +2,7 @@ TEMPLATE = app TARGET = tst_bench_qnetworkreply QT -= gui -QT += network testlib +QT += core-private network network-private testlib CONFIG += release diff --git a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp index 58cb65e1c7..55376d5a79 100644 --- a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -50,6 +50,9 @@ #include <QtNetwork/qtcpserver.h> #include "../../../../auto/network-settings.h" +#ifdef QT_BUILD_INTERNAL +#include <QtNetwork/private/qhostinfo_p.h> +#endif Q_DECLARE_METATYPE(QSharedPointer<char>) @@ -460,7 +463,9 @@ private slots: #ifndef QT_NO_SSL void echoPerformance_data(); void echoPerformance(); -#endif + void preConnectEncrypted(); +#endif // !QT_NO_SSL + void preConnectEncrypted_data(); void downloadPerformance(); void uploadPerformance(); @@ -472,9 +477,13 @@ private slots: void httpDownloadPerformanceDownloadBuffer(); void httpsRequestChain(); void httpsUpload(); + void preConnect_data(); + void preConnect(); private: void runHttpsUploadRequest(const QByteArray &data, const QNetworkRequest &request); + QPair<QNetworkReply *, qint64> runGetRequest(QNetworkAccessManager *manager, + const QNetworkRequest &request); }; void tst_qnetworkreply::initTestCase() @@ -495,6 +504,19 @@ void tst_qnetworkreply::httpLatency() } } +QPair<QNetworkReply *, qint64> tst_qnetworkreply::runGetRequest( + QNetworkAccessManager *manager, const QNetworkRequest &request) +{ + QElapsedTimer timer; + timer.start(); + QNetworkReply *reply = manager->get(request); + connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors())); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(20); + qint64 elapsed = timer.elapsed(); + return qMakePair(reply, elapsed); +} + #ifndef QT_NO_SSL void tst_qnetworkreply::echoPerformance_data() { @@ -527,7 +549,60 @@ void tst_qnetworkreply::echoPerformance() delete reply; } } + +void tst_qnetworkreply::preConnectEncrypted() +{ + QString hostName = QLatin1String("www.google.com"); + + QNetworkAccessManager manager; + QNetworkRequest request(QUrl("https://" + hostName)); + + // make sure we have a full request including + // DNS lookup, TCP and SSL handshakes +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); +#endif + + // first, benchmark a normal request + QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request); + QNetworkReply *normalReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(normalReply->error() == QNetworkReply::NoError); + qint64 normalElapsed = normalResult.second; + + // clear all caches again +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); #endif + manager.clearAccessCache(); + + // now try to make the connection beforehand + QFETCH(int, sleepTime); + manager.connectToHostEncrypted(hostName); + QTestEventLoop::instance().enterLoopMSecs(sleepTime); + + // now make another request and hopefully use the existing connection + QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request); + QNetworkReply *preConnectReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(preConnectReply->error() == QNetworkReply::NoError); + qint64 preConnectElapsed = preConnectResult.second; + qDebug() << request.url().toString() << "full request:" << normalElapsed + << "ms, pre-connect request:" << preConnectElapsed << "ms, difference:" + << (normalElapsed - preConnectElapsed) << "ms"; +} +#endif // !QT_NO_SSL + +void tst_qnetworkreply::preConnectEncrypted_data() +{ + QTest::addColumn<int>("sleepTime"); + QTest::newRow("2secs") << 2000; // to start a new request after preconnecting is done + QTest::newRow("100ms") << 100; // to start a new request while preconnecting is in-flight +} void tst_qnetworkreply::downloadPerformance() { @@ -850,6 +925,56 @@ void tst_qnetworkreply::httpsUpload() } } +void tst_qnetworkreply::preConnect_data() +{ + preConnectEncrypted_data(); +} + +void tst_qnetworkreply::preConnect() +{ + QString hostName = QLatin1String("www.google.com"); + + QNetworkAccessManager manager; + QNetworkRequest request(QUrl("http://" + hostName)); + + // make sure we have a full request including + // DNS lookup and TCP handshake +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); +#endif + + // first, benchmark a normal request + QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request); + QNetworkReply *normalReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(normalReply->error() == QNetworkReply::NoError); + qint64 normalElapsed = normalResult.second; + + // clear all caches again +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); +#endif + manager.clearAccessCache(); + + // now try to make the connection beforehand + QFETCH(int, sleepTime); + manager.connectToHost(hostName); + QTestEventLoop::instance().enterLoopMSecs(sleepTime); + + // now make another request and hopefully use the existing connection + QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request); + QNetworkReply *preConnectReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(preConnectReply->error() == QNetworkReply::NoError); + qint64 preConnectElapsed = preConnectResult.second; + qDebug() << request.url().toString() << "full request:" << normalElapsed + << "ms, pre-connect request:" << preConnectElapsed << "ms, difference:" + << (normalElapsed - preConnectElapsed) << "ms"; +} QTEST_MAIN(tst_qnetworkreply) diff --git a/tests/manual/corelib/tools/qhash/main.cpp b/tests/manual/corelib/tools/qhash/main.cpp new file mode 100644 index 0000000000..fd38350c88 --- /dev/null +++ b/tests/manual/corelib/tools/qhash/main.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +//#define QT_STRICT_ITERATORS +#include <QHash> + +void testEraseNoError() +{ + QHash<int, int> a; + + a.insert(100, 100); + a.insert(101, 200); + a.insert(5, 50); + a.insertMulti(5, 60); + a.insertMulti(5, 70); + a.insertMulti(5, 80); + + QHash<int, int>::iterator i = a.begin(); + while (i.key() != 5) + ++i; + ++i; + a.erase(i); + + qDebug() << "Erase - got no errors on iterator check"; +} + +void testErase() +{ + QHash<int, int> a, b; + a.insert(5, 50); + a.insert(6, 60); + a.insert(7, 70); + b = a; + a.erase(a.begin()); + b.erase(b.end() - 1); + qDebug() << "Erase - Executing line with error now."; + a.erase(b.begin()); +} + + +int main() +{ + testEraseNoError(); + testErase(); + return 0; +} diff --git a/tests/manual/corelib/tools/qhash/main.pro b/tests/manual/corelib/tools/qhash/main.pro new file mode 100644 index 0000000000..bba41b9c12 --- /dev/null +++ b/tests/manual/corelib/tools/qhash/main.pro @@ -0,0 +1 @@ +SOURCES = main.cpp diff --git a/tests/manual/corelib/tools/qlist/main.cpp b/tests/manual/corelib/tools/qlist/main.cpp new file mode 100644 index 0000000000..8c1ee2890c --- /dev/null +++ b/tests/manual/corelib/tools/qlist/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QDebug> +//#define QT_STRICT_ITERATORS +#include <QVector> +void testErase() +{ + QList<int> a, b; + a.append(5); + a.append(6); + a.append(7); + b = a; + a.erase(a.begin()); + qDebug() << "erase - Executing line with error now."; + // a.erase(a.end()); + a.erase(b.begin()); +} +void testInsert() +{ + QList<int> a, b; + a.insert(a.begin(), 1); + a.insert(a.begin(), 2); + a.insert(a.end(), 3); + b = a; + qDebug() << "insert - Executing line with error now."; + a.insert(b.begin(), 4); +} +int main() +{ + // testErase(); + testInsert(); + return 0; +}
\ No newline at end of file diff --git a/tests/manual/corelib/tools/qlist/main.pro b/tests/manual/corelib/tools/qlist/main.pro new file mode 100644 index 0000000000..bba41b9c12 --- /dev/null +++ b/tests/manual/corelib/tools/qlist/main.pro @@ -0,0 +1 @@ +SOURCES = main.cpp diff --git a/tests/auto/dbus/qdbusabstractinterface/pinger.cpp b/tests/manual/corelib/tools/qmap/main.cpp index be4fc30409..0d88e3f170 100644 --- a/tests/auto/dbus/qdbusabstractinterface/pinger.cpp +++ b/tests/manual/corelib/tools/qmap/main.cpp @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtDBus module of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,29 +39,73 @@ ** ****************************************************************************/ -/* - * This file was generated by qdbusxml2cpp version 0.7 - * Command line was: qdbusxml2cpp -i interface.h -p pinger org.qtproject.QtDBus.Pinger.xml - * - * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). - * - * This is an auto-generated file. - * This file may have been hand-edited. Look for HAND-EDIT comments - * before re-generating it. - */ +//#define Q_NO_DEBUGMAP_PARENT_TEST +// Comment in line above to skip the parent test. +#include <QtCore/QMap> +#include <QDebug> -#include "pinger.h" +void noBugErase() +{ + QMap<int, int> a, b; + a[10] = 11; + a[11] = 12; + b = a; + b.erase(b.begin()); +} -/* - * Implementation of interface class ComTrolltechQtDBusPingerInterface - */ +void noBugInsertWithHints() +{ + QMap<int, int> a; + QMap<int, int> b; + for (int u = 100; u < 10000; u += 20) + a.insert(u, u); + b = a; + QMap<int, int>::const_iterator b_ite(b.begin()); // b.begin() ensures correct detach() + ++b_ite; + b.insert(b_ite, 501, 501); + b.insert(b_ite, 115, 115); + QMap<int, int> c; + c = b; + c.setSharable(false); +} -ComTrolltechQtDBusPingerInterface::ComTrolltechQtDBusPingerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) - : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +void testInsertWithHintCorruption() { + qDebug() << "Starting testInsertWithHintCorruption"; + + QMap<int, int> a; + QMap<int, int> b; + for (int u = 100; u < 10000; u += 20) + a.insert(u, u); + b = a; + QMap<int, int>::const_iterator b_ite = b.constBegin(); + ++b_ite; + b.insert(b_ite, 501, 501); + b.insert(b_ite, 115, 115); // insert with wrong hint. + QMap<int, int> c; + c = b; + c.setSharable(false); + qDebug() << "End of testInsertWithHintCorruption - failed silently"; } -ComTrolltechQtDBusPingerInterface::~ComTrolltechQtDBusPingerInterface() +void testEraseCorruption() { + qDebug() << "Starting testEraseCorruption"; + + QMap<int, int> a, b; + a[10] = 11; + a[11] = 12; + b = a; + b.erase(a.begin()); + qDebug() << "End of testEraseCorruption - failed silently"; } +int main() +{ + noBugErase(); + noBugInsertWithHints(); + + // testEraseCorruption(); + testInsertWithHintCorruption(); + return 0; +} diff --git a/tests/manual/corelib/tools/qmap/qmaptest.pro b/tests/manual/corelib/tools/qmap/qmaptest.pro new file mode 100644 index 0000000000..fbe7013144 --- /dev/null +++ b/tests/manual/corelib/tools/qmap/qmaptest.pro @@ -0,0 +1,2 @@ +TEMPLATE = app +SOURCES = main.cpp diff --git a/tests/manual/corelib/tools/qset/main.cpp b/tests/manual/corelib/tools/qset/main.cpp new file mode 100644 index 0000000000..34a6c58c63 --- /dev/null +++ b/tests/manual/corelib/tools/qset/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +//#define QT_STRICT_ITERATORS +#include <QSet> + +void testErase() +{ + QSet<int> a, b; + a.insert(5); + a.insert(6); + a.insert(7); + b = a; + a.erase(a.begin()); + b.erase(b.end() - 1); + qDebug() << "erase - no errors until now"; + a.erase(b.begin()); +} + +int main() +{ + testErase(); + return 0; +} diff --git a/tests/manual/corelib/tools/qset/main.pro b/tests/manual/corelib/tools/qset/main.pro new file mode 100644 index 0000000000..bba41b9c12 --- /dev/null +++ b/tests/manual/corelib/tools/qset/main.pro @@ -0,0 +1 @@ +SOURCES = main.cpp diff --git a/tests/manual/corelib/tools/qvarlengtharray/main.cpp b/tests/manual/corelib/tools/qvarlengtharray/main.cpp new file mode 100644 index 0000000000..759f4b3905 --- /dev/null +++ b/tests/manual/corelib/tools/qvarlengtharray/main.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +//#define QT_STRICT_ITERATORS +#include <QVarLengthArray> + +void testErase() +{ + QVarLengthArray<int> a, b; + a.append(5); + a.append(6); + a.append(7); + b = a; + a.erase(a.begin()); + a.erase(a.end() - 1); + qDebug() << "erase - no errors until now"; + // a.erase(a.end()); + a.erase(b.begin()); +} + +void testInsert() +{ + QVarLengthArray<int> a, b; + a.insert(a.begin(), 1); + a.insert(a.begin(), 2); + a.insert(a.end(), 3); + b = a; + qDebug() << "insert - no errors until now"; + a.insert(b.begin(), 1, 4); +} + +int main() +{ + // testErase(); + testInsert(); + return 0; +} diff --git a/tests/manual/corelib/tools/qvarlengtharray/main.pro b/tests/manual/corelib/tools/qvarlengtharray/main.pro new file mode 100644 index 0000000000..4ce070ab75 --- /dev/null +++ b/tests/manual/corelib/tools/qvarlengtharray/main.pro @@ -0,0 +1 @@ +SOURCES=main.cpp diff --git a/tests/manual/corelib/tools/qvector/main.cpp b/tests/manual/corelib/tools/qvector/main.cpp new file mode 100644 index 0000000000..2dce4a9264 --- /dev/null +++ b/tests/manual/corelib/tools/qvector/main.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +//#define QT_STRICT_ITERATORS +#include <QVector> + +void testErase() +{ + QVector<int> a, b; + a.append(5); + a.append(6); + a.append(7); + b = a; + a.erase(a.begin()); + a.erase(a.end() - 1); + qDebug() << "erase - no errors until now"; + // a.erase(a.end()); + a.erase(b.begin()); +} + +void testInsert() +{ + QVector<int> a, b; + a.insert(a.begin(), 1, 1); + a.insert(a.begin(), 1, 2); + a.insert(a.begin(), 1, 3); + b = a; + qDebug() << "insert - no errors until now"; + a.insert(b.begin(), 1, 4); +} + +int main() +{ + testErase(); + // testInsert(); + return 0; +} diff --git a/tests/manual/corelib/tools/qvector/main.pro b/tests/manual/corelib/tools/qvector/main.pro new file mode 100644 index 0000000000..bba41b9c12 --- /dev/null +++ b/tests/manual/corelib/tools/qvector/main.pro @@ -0,0 +1 @@ +SOURCES = main.cpp diff --git a/tests/manual/dialogs/colordialogpanel.h b/tests/manual/dialogs/colordialogpanel.h index 05ca336a23..7f2898cea0 100644 --- a/tests/manual/dialogs/colordialogpanel.h +++ b/tests/manual/dialogs/colordialogpanel.h @@ -45,9 +45,11 @@ #include <QPointer> #include <QColorDialog> +QT_BEGIN_NAMESPACE class QComboBox; class QCheckBox; class QPushButton; +QT_END_NAMESPACE class ColorDialogPanel : public QWidget { diff --git a/tests/manual/dialogs/dialogs.pro b/tests/manual/dialogs/dialogs.pro index 4ed200ab7f..d19c3026d0 100644 --- a/tests/manual/dialogs/dialogs.pro +++ b/tests/manual/dialogs/dialogs.pro @@ -5,6 +5,6 @@ TARGET = dialogs TEMPLATE = app SOURCES += main.cpp filedialogpanel.cpp colordialogpanel.cpp fontdialogpanel.cpp \ - wizardpanel.cpp + wizardpanel.cpp messageboxpanel.cpp HEADERS += filedialogpanel.h colordialogpanel.h fontdialogpanel.h \ - wizardpanel.h + wizardpanel.h messageboxpanel.h diff --git a/tests/manual/dialogs/filedialogpanel.cpp b/tests/manual/dialogs/filedialogpanel.cpp index a342122570..000d755cef 100644 --- a/tests/manual/dialogs/filedialogpanel.cpp +++ b/tests/manual/dialogs/filedialogpanel.cpp @@ -154,9 +154,11 @@ FileDialogPanel::FileDialogPanel(QWidget *parent) , m_nameFilterDetailsVisible(new QCheckBox(tr("Name filter details visible"))) , m_resolveSymLinks(new QCheckBox(tr("Resolve symlinks"))) , m_native(new QCheckBox(tr("Use native dialog"))) + , m_customDirIcons(new QCheckBox(tr("Don't use custom directory icons"))) , m_acceptMode(createCombo(this, acceptModeComboData, sizeof(acceptModeComboData)/sizeof(ComboData))) , m_fileMode(createCombo(this, fileModeComboData, sizeof(fileModeComboData)/sizeof(ComboData))) , m_viewMode(createCombo(this, viewModeComboData, sizeof(viewModeComboData)/sizeof(ComboData))) + , m_allowedSchemes(new QLineEdit(this)) , m_defaultSuffix(new QLineEdit(this)) , m_directory(new QLineEdit(this)) , m_selectedFileName(new QLineEdit(this)) @@ -171,11 +173,13 @@ FileDialogPanel::FileDialogPanel(QWidget *parent) optionsLayout->addRow(tr("AcceptMode:"), m_acceptMode); optionsLayout->addRow(tr("FileMode:"), m_fileMode); optionsLayout->addRow(tr("ViewMode:"), m_viewMode); + optionsLayout->addRow(tr("Allowed Schemes:"), m_allowedSchemes); optionsLayout->addRow(m_native); optionsLayout->addRow(m_confirmOverWrite); optionsLayout->addRow(m_nameFilterDetailsVisible); optionsLayout->addRow(m_resolveSymLinks); optionsLayout->addRow(m_readOnly); + optionsLayout->addRow(m_customDirIcons); // Files QGroupBox *filesGroupBox = new QGroupBox(tr("Files / Filters")); @@ -216,9 +220,13 @@ FileDialogPanel::FileDialogPanel(QWidget *parent) row = 0; column++; addButton(tr("getOpenFileName"), buttonLayout, row, column, this, SLOT(getOpenFileName())); + addButton(tr("getOpenFileUrl"), buttonLayout, row, column, this, SLOT(getOpenFileUrl())); addButton(tr("getOpenFileNames"), buttonLayout, row, column, this, SLOT(getOpenFileNames())); + addButton(tr("getOpenFileUrls"), buttonLayout, row, column, this, SLOT(getOpenFileUrls())); addButton(tr("getSaveFileName"), buttonLayout, row, column, this, SLOT(getSaveFileName())); + addButton(tr("getSaveFileUrl"), buttonLayout, row, column, this, SLOT(getSaveFileUrl())); addButton(tr("getExistingDirectory"), buttonLayout, row, column, this, SLOT(getExistingDirectory())); + addButton(tr("getExistingDirectoryUrl"), buttonLayout, row, column, this, SLOT(getExistingDirectoryUrl())); addButton(tr("Restore defaults"), buttonLayout, row, column, this, SLOT(restoreDefaults())); // Main layout @@ -316,9 +324,16 @@ QFileDialog::Options FileDialogPanel::options() const result |= QFileDialog::DontConfirmOverwrite; if (!m_native->isChecked()) result |= QFileDialog::DontUseNativeDialog; + if (!m_customDirIcons->isChecked()) + result |= QFileDialog::DontUseCustomDirectoryIcons; return result; } +QStringList FileDialogPanel::allowedSchemes() const +{ + return m_allowedSchemes->text().simplified().split(' ', QString::SkipEmptyParts); +} + void FileDialogPanel::getOpenFileNames() { QString selectedFilter = m_selectedNameFilter->text().trimmed(); @@ -334,6 +349,22 @@ void FileDialogPanel::getOpenFileNames() } } +void FileDialogPanel::getOpenFileUrls() +{ + QString selectedFilter = m_selectedNameFilter->text().trimmed(); + const QList<QUrl> files = + QFileDialog::getOpenFileUrls(this, tr("getOpenFileNames Qt %1").arg(QLatin1String(QT_VERSION_STR)), + QUrl(m_directory->text()), filterString(), &selectedFilter, options(), + allowedSchemes()); + if (!files.isEmpty()) { + QString result; + QDebug(&result).nospace() + << "Files: " << QUrl::toStringList(files) + << "\nName filter: " << selectedFilter; + QMessageBox::information(this, tr("getOpenFileNames"), result, QMessageBox::Ok); + } +} + void FileDialogPanel::getOpenFileName() { QString selectedFilter = m_selectedNameFilter->text().trimmed(); @@ -349,6 +380,22 @@ void FileDialogPanel::getOpenFileName() } } +void FileDialogPanel::getOpenFileUrl() +{ + QString selectedFilter = m_selectedNameFilter->text().trimmed(); + const QUrl file = + QFileDialog::getOpenFileUrl(this, tr("getOpenFileUrl Qt %1").arg(QLatin1String(QT_VERSION_STR)), + QUrl(m_directory->text()), filterString(), &selectedFilter, options(), + allowedSchemes()); + if (file.isValid()) { + QString result; + QDebug(&result).nospace() + << "File: " << file.toString() + << "\nName filter: " << selectedFilter; + QMessageBox::information(this, tr("getOpenFileName"), result, QMessageBox::Ok); + } +} + void FileDialogPanel::getSaveFileName() { QString selectedFilter = m_selectedNameFilter->text().trimmed(); @@ -364,6 +411,22 @@ void FileDialogPanel::getSaveFileName() } } +void FileDialogPanel::getSaveFileUrl() +{ + QString selectedFilter = m_selectedNameFilter->text().trimmed(); + const QUrl file = + QFileDialog::getSaveFileUrl(this, tr("getSaveFileName Qt %1").arg(QLatin1String(QT_VERSION_STR)), + QUrl(m_directory->text()), filterString(), &selectedFilter, options(), + allowedSchemes()); + if (file.isValid()) { + QString result; + QDebug(&result).nospace() + << "File: " << file.toString() + << "\nName filter: " << selectedFilter; + QMessageBox::information(this, tr("getSaveFileNames"), result, QMessageBox::Ok); + } +} + void FileDialogPanel::getExistingDirectory() { const QString dir = @@ -373,17 +436,29 @@ void FileDialogPanel::getExistingDirectory() QMessageBox::information(this, tr("getExistingDirectory"), QLatin1String("Directory: ") + dir, QMessageBox::Ok); } +void FileDialogPanel::getExistingDirectoryUrl() +{ + const QUrl dir = + QFileDialog::getExistingDirectoryUrl(this, tr("getExistingDirectory Qt %1").arg(QLatin1String(QT_VERSION_STR)), + QUrl(m_directory->text()), options() | QFileDialog::ShowDirsOnly, + allowedSchemes()); + if (!dir.isEmpty()) + QMessageBox::information(this, tr("getExistingDirectory"), QLatin1String("Directory: ") + dir.toString(), QMessageBox::Ok); +} + void FileDialogPanel::restoreDefaults() { QFileDialog d; setComboBoxValue(m_acceptMode, d.acceptMode()); setComboBoxValue(m_fileMode, d.fileMode()); setComboBoxValue(m_viewMode, d.viewMode()); + m_allowedSchemes->setText(QString()); m_confirmOverWrite->setChecked(d.confirmOverwrite()); m_nameFilterDetailsVisible->setChecked(d.isNameFilterDetailsVisible()); m_resolveSymLinks->setChecked(d.resolveSymlinks()); m_readOnly->setChecked(d.isReadOnly()); m_native->setChecked(true); + m_customDirIcons->setChecked(d.testOption(QFileDialog::DontUseCustomDirectoryIcons)); m_directory->setText(QDir::homePath()); m_defaultSuffix->setText(QLatin1String("txt")); m_nameFilters->setPlainText(QLatin1String("Any files (*)\nImage files (*.png *.xpm *.jpg)\nText files (*.txt)")); diff --git a/tests/manual/dialogs/filedialogpanel.h b/tests/manual/dialogs/filedialogpanel.h index 2977de4164..2e1d5d4de9 100644 --- a/tests/manual/dialogs/filedialogpanel.h +++ b/tests/manual/dialogs/filedialogpanel.h @@ -46,11 +46,13 @@ #include <QFileDialog> #include <QPointer> +QT_BEGIN_NAMESPACE class QPushButton; class QCheckBox; class QComboBox; class QLineEdit; class QPlainTextEdit; +QT_END_NAMESPACE class LabelLineEdit; class FileDialogPanel : public QWidget @@ -66,9 +68,13 @@ public slots: void deleteNonModalDialog(); void deleteModalDialog(); void getOpenFileNames(); + void getOpenFileUrls(); void getOpenFileName(); + void getOpenFileUrl(); void getSaveFileName(); + void getSaveFileUrl(); void getExistingDirectory(); + void getExistingDirectoryUrl(); void accepted(); void showAcceptedResult(); void restoreDefaults(); @@ -80,6 +86,7 @@ private slots: private: QString filterString() const; QFileDialog::Options options() const; + QStringList allowedSchemes() const; void applySettings(QFileDialog *d) const; QCheckBox *m_readOnly; @@ -87,9 +94,11 @@ private: QCheckBox *m_nameFilterDetailsVisible; QCheckBox *m_resolveSymLinks; QCheckBox *m_native; + QCheckBox *m_customDirIcons; QComboBox *m_acceptMode; QComboBox *m_fileMode; QComboBox *m_viewMode; + QLineEdit *m_allowedSchemes; QLineEdit *m_defaultSuffix; QLineEdit *m_directory; QLineEdit *m_selectedFileName; diff --git a/tests/manual/dialogs/fontdialogpanel.cpp b/tests/manual/dialogs/fontdialogpanel.cpp index 02f05f9580..c72bf77351 100644 --- a/tests/manual/dialogs/fontdialogpanel.cpp +++ b/tests/manual/dialogs/fontdialogpanel.cpp @@ -67,12 +67,20 @@ FontDialogPanel::FontDialogPanel(QWidget *parent) , m_fontSizeBox(new QDoubleSpinBox) , m_noButtons(new QCheckBox(tr("Don't display OK/Cancel buttons"))) , m_dontUseNativeDialog(new QCheckBox(tr("Don't use native dialog"))) + , m_scalableFilter(new QCheckBox(tr("Filter scalable fonts"))) + , m_nonScalableFilter(new QCheckBox(tr("Filter non scalable fonts"))) + , m_monospacedFilter(new QCheckBox(tr("Filter monospaced fonts"))) + , m_proportionalFilter(new QCheckBox(tr("Filter proportional fonts"))) { // Options QGroupBox *optionsGroupBox = new QGroupBox(tr("Options"), this); QVBoxLayout *optionsLayout = new QVBoxLayout(optionsGroupBox); optionsLayout->addWidget(m_noButtons); optionsLayout->addWidget(m_dontUseNativeDialog); + optionsLayout->addWidget(m_scalableFilter); + optionsLayout->addWidget(m_nonScalableFilter); + optionsLayout->addWidget(m_monospacedFilter); + optionsLayout->addWidget(m_proportionalFilter); // Font QGroupBox *fontGroupBox = new QGroupBox(tr("Font"), this); @@ -201,6 +209,10 @@ void FontDialogPanel::applySettings(QFontDialog *d) const { d->setOption(QFontDialog::NoButtons, m_noButtons->isChecked()); d->setOption(QFontDialog::DontUseNativeDialog, m_dontUseNativeDialog->isChecked()); + d->setOption(QFontDialog::ScalableFonts, m_scalableFilter->isChecked()); + d->setOption(QFontDialog::NonScalableFonts, m_nonScalableFilter->isChecked()); + d->setOption(QFontDialog::MonospacedFonts, m_monospacedFilter->isChecked()); + d->setOption(QFontDialog::ProportionalFonts, m_proportionalFilter->isChecked()); QFont font = m_fontFamilyBox->currentFont(); font.setPointSizeF(m_fontSizeBox->value()); diff --git a/tests/manual/dialogs/fontdialogpanel.h b/tests/manual/dialogs/fontdialogpanel.h index f3bbbb3939..4592c2ec6e 100644 --- a/tests/manual/dialogs/fontdialogpanel.h +++ b/tests/manual/dialogs/fontdialogpanel.h @@ -45,10 +45,12 @@ #include <QPointer> #include <QFontDialog> +QT_BEGIN_NAMESPACE class QCheckBox; class QPushButton; class QFontComboBox; class QDoubleSpinBox; +QT_END_NAMESPACE class FontDialogPanel : public QWidget { @@ -77,6 +79,10 @@ private: QDoubleSpinBox *m_fontSizeBox; QCheckBox *m_noButtons; QCheckBox *m_dontUseNativeDialog; + QCheckBox *m_scalableFilter; + QCheckBox *m_nonScalableFilter; + QCheckBox *m_monospacedFilter; + QCheckBox *m_proportionalFilter; QPushButton *m_deleteNonModalDialogButton; QPushButton *m_deleteModalDialogButton; QString m_result; diff --git a/tests/manual/dialogs/main.cpp b/tests/manual/dialogs/main.cpp index 4ad2842e44..c5f14cabef 100644 --- a/tests/manual/dialogs/main.cpp +++ b/tests/manual/dialogs/main.cpp @@ -43,6 +43,7 @@ #include "colordialogpanel.h" #include "fontdialogpanel.h" #include "wizardpanel.h" +#include "messageboxpanel.h" #include <QMainWindow> #include <QApplication> @@ -73,6 +74,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) tabWidget->addTab(new ColorDialogPanel, tr("QColorDialog")); tabWidget->addTab(new FontDialogPanel, tr("QFontDialog")); tabWidget->addTab(new WizardPanel, tr("QWizard")); + tabWidget->addTab(new MessageBoxPanel, tr("QMessageBox")); setCentralWidget(tabWidget); } diff --git a/tests/manual/dialogs/messageboxpanel.cpp b/tests/manual/dialogs/messageboxpanel.cpp new file mode 100644 index 0000000000..6fc84e11fd --- /dev/null +++ b/tests/manual/dialogs/messageboxpanel.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "messageboxpanel.h" + +#include <QGroupBox> +#include <QPushButton> +#include <QVBoxLayout> +#include <QHBoxLayout> +#include <QMessageBox> +#include <QPushButton> +#include <QDebug> +#include <QComboBox> +#include <QLineEdit> +#include <QLabel> +#include <QCheckBox> + +MessageBoxPanel::MessageBoxPanel(QWidget *parent) : QWidget(parent) +,m_iconComboBox(new QComboBox) +,m_textInMsgBox(new QLineEdit) +,m_informativeText(new QLineEdit) +,m_detailedtext(new QLineEdit) +,m_buttonsMask(new QLineEdit) +,m_btnExec(new QPushButton) +,m_btnShowApply(new QPushButton) +,m_resultLabel(new QLabel) +,m_chkReallocMsgBox(new QCheckBox(QString::fromLatin1("Reallocate Message Box"))) +,m_msgbox(new QMessageBox) +{ + // --- Options --- + QGroupBox *optionsGroupBox = new QGroupBox(tr("Options"), this); + QVBoxLayout *optionsLayout = new QVBoxLayout(optionsGroupBox); + + // text + optionsLayout->addWidget(new QLabel(QString::fromLatin1("Message box text"))); + m_textInMsgBox->setText(QString::fromLatin1("This is a simple test with a text that is not long")); + optionsLayout->addWidget(m_textInMsgBox); + + // informative text + optionsLayout->addWidget(new QLabel(QString::fromLatin1("Informative Text"))); + optionsLayout->addWidget(m_informativeText); + + // detailed text + optionsLayout->addWidget(new QLabel(QString::fromLatin1("detailed Text"))); + optionsLayout->addWidget(m_detailedtext); + + // icon + QStringList items; + items << "NoIcon" << "Information" << "Warning" << "Critical" << "Question"; + m_iconComboBox->addItems(items); + optionsLayout->addWidget(new QLabel(QString::fromLatin1("Message box icon"))); + optionsLayout->addWidget(m_iconComboBox); + + // buttons mask + optionsLayout->addWidget(new QLabel(QString::fromLatin1("Message box button mask (in hex)"))); + m_validator = new QRegExpValidator(QRegExp("0[xX]?[0-9a-fA-F]+"), this); + m_buttonsMask->setMaxLength(10); + m_buttonsMask->setValidator(m_validator); + m_buttonsMask->setText(QString::fromLatin1("0x00300400")); + optionsLayout->addWidget(m_buttonsMask); + + // reallocate + optionsLayout->addWidget(m_chkReallocMsgBox); + optionsLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding)); + + // Exec/Show + QGroupBox *execGroupBox = new QGroupBox(tr("Exec")); + QVBoxLayout *execLayout = new QVBoxLayout(execGroupBox); + m_btnExec->setText(QString::fromLatin1("Exec message box")); + connect(m_btnExec, SIGNAL(clicked()), this, SLOT(doExec())); + execLayout->addWidget(m_btnExec); + + m_btnShowApply->setText(QString::fromLatin1("Show / apply")); + connect(m_btnShowApply, SIGNAL(clicked()), this, SLOT(doShowApply())); + execLayout->addWidget(m_btnShowApply); + + // result label + execLayout->addWidget(m_resultLabel); + + execLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding)); + execGroupBox->setLayout(execLayout); + + // Main layout + QHBoxLayout *mainLayout = new QHBoxLayout(); + mainLayout->addWidget(optionsGroupBox); + mainLayout->addWidget(execGroupBox); + + setLayout(mainLayout); +} + +void MessageBoxPanel::setupMessageBox(QMessageBox &box) +{ + m_resultLabel->setText(QString()); + box.setText(m_textInMsgBox->text()); + box.setInformativeText(m_informativeText->text()); + box.setDetailedText(m_detailedtext->text()); + + QString btnHexText = m_buttonsMask->text(); + btnHexText = btnHexText.replace(QString::fromLatin1("0x"), QString(), Qt::CaseInsensitive); + bool ok; + QMessageBox::StandardButtons btns = (QMessageBox::StandardButtons) btnHexText.toUInt(&ok, 16); + box.setStandardButtons((QMessageBox::StandardButtons) btns); + if (box.standardButtons() == (QMessageBox::StandardButtons) 0) + box.setStandardButtons(QMessageBox::Ok); // just to have something. + + box.setIcon((QMessageBox::Icon) m_iconComboBox->currentIndex()); +} + +MessageBoxPanel::~MessageBoxPanel() +{ + if (m_msgbox) + m_msgbox->deleteLater(); +} + +void MessageBoxPanel::doExec() +{ + if (!m_msgbox || m_chkReallocMsgBox->isChecked()) { + if (m_msgbox) + m_msgbox->deleteLater(); + m_msgbox = new QMessageBox; + } + setupMessageBox(*m_msgbox); + m_msgbox->setWindowModality(Qt::NonModal); + + int res = m_msgbox->exec(); + QString sres; + sres.setNum(res, 16); + m_resultLabel->setText(QString::fromLatin1("Return value (hex): %1").arg(sres)); +} + +void MessageBoxPanel::doShowApply() +{ + if (!m_msgbox || m_chkReallocMsgBox->isChecked()) { + if (m_msgbox) + m_msgbox->deleteLater(); + m_msgbox = new QMessageBox; + } + setupMessageBox(*m_msgbox); + if (!m_msgbox->isVisible()) { + m_msgbox->setWindowModality(Qt::NonModal); + m_msgbox->show(); + } +} diff --git a/tests/manual/dialogs/messageboxpanel.h b/tests/manual/dialogs/messageboxpanel.h new file mode 100644 index 0000000000..9f7e35210c --- /dev/null +++ b/tests/manual/dialogs/messageboxpanel.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MESSAGEBOXPANEL_H +#define MESSAGEBOXPANEL_H + +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QComboBox; +class QCheckBox; +class QPushButton; +class QLineEdit; +class QValidator; +class QLabel; +class QMessageBox; +class QCheckBox; +QT_END_NAMESPACE + +class MessageBoxPanel : public QWidget +{ + Q_OBJECT +public: + explicit MessageBoxPanel(QWidget *parent = 0); + ~MessageBoxPanel(); + +public slots: + void doExec(); + void doShowApply(); + +private: + QComboBox *m_iconComboBox; + QLineEdit *m_textInMsgBox; + QLineEdit *m_informativeText; + QLineEdit *m_detailedtext; + QLineEdit *m_buttonsMask; + QPushButton *m_btnExec; + QPushButton *m_btnShowApply; + QValidator *m_validator; + QLabel *m_resultLabel; + QCheckBox *m_chkReallocMsgBox; + QMessageBox *m_msgbox; + void setupMessageBox(QMessageBox &box); +}; + +#endif diff --git a/tests/manual/dialogs/wizardpanel.h b/tests/manual/dialogs/wizardpanel.h index 6a2268e94c..10e0c5071e 100644 --- a/tests/manual/dialogs/wizardpanel.h +++ b/tests/manual/dialogs/wizardpanel.h @@ -46,7 +46,9 @@ class WizardStyleControl; class WizardOptionsControl; +QT_BEGIN_NAMESPACE class QWizard; +QT_END_NAMESPACE class WizardPanel : public QWidget { diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 2fa05f65e0..c04f22b53b 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -20,6 +20,7 @@ qlayout \ qlocale \ qnetworkaccessmanager/qget \ qnetworkconfigurationmanager \ +qnetworkconfiguration \ qnetworkreply \ qpainfo \ qscreen \ diff --git a/tests/manual/qdesktopservices/tst_qdesktopservices.cpp b/tests/manual/qdesktopservices/tst_qdesktopservices.cpp index 534816a01b..9c39002fba 100644 --- a/tests/manual/qdesktopservices/tst_qdesktopservices.cpp +++ b/tests/manual/qdesktopservices/tst_qdesktopservices.cpp @@ -104,6 +104,11 @@ void tst_QDesktopServices::openUrl_data() << QUrl("http://google.com/search?q=/profile/5") << "This should search \"/profile/5\" on Google."; + // see QTBUG-31945 + QTest::newRow("two-fragments") + << QUrl("http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006926-CH3-SW81") + << "This should open \"Implementing a Container View Controller\" in the UIViewController docs"; + QTest::newRow("mail") << QUrl("mailto:development@qt-project.org") << "This should open an email composer with the destination set to development@qt-project.org"; @@ -118,7 +123,7 @@ void tst_QDesktopServices::openUrl() QFETCH(QUrl, data); QFETCH(QString, message); qWarning("\n\nOpening \"%s\": %s", qPrintable(data.toString()), qPrintable(message)); - QDesktopServices::openUrl(data); + QVERIFY(QDesktopServices::openUrl(data)); } QTEST_MAIN(tst_QDesktopServices) diff --git a/tests/manual/qnetworkconfiguration/main.cpp b/tests/manual/qnetworkconfiguration/main.cpp new file mode 100644 index 0000000000..c611cfc9e2 --- /dev/null +++ b/tests/manual/qnetworkconfiguration/main.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research in Motion. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include <qtest.h> +#include <QtTest/QtTest> +#include <QtNetwork/qnetworkconfiguration.h> +#include <QtNetwork/qnetworkconfigmanager.h> + +class tst_qnetworkconfiguration : public QObject +{ + Q_OBJECT + +private slots: + void bearerType(); + void bearerTypeFamily(); +}; + +void tst_qnetworkconfiguration::bearerType() +{ + QNetworkConfigurationManager m; + QList<QNetworkConfiguration> allConfs = m.allConfigurations(); + QElapsedTimer timer; + for (int a = 0; a < allConfs.count(); a++) { + timer.start(); + QNetworkConfiguration::BearerType type = allConfs.at(a).bearerType(); + qint64 elapsed = timer.elapsed(); + QString typeString; + switch (type) { + case QNetworkConfiguration::BearerUnknown: + typeString = QLatin1String("Unknown"); + break; + case QNetworkConfiguration::BearerEthernet: + typeString = QLatin1String("Ethernet"); + break; + case QNetworkConfiguration::BearerWLAN: + typeString = QLatin1String("WLAN"); + break; + case QNetworkConfiguration::Bearer2G: + typeString = QLatin1String("2G"); + break; + case QNetworkConfiguration::BearerCDMA2000: + typeString = QLatin1String("CDMA2000"); + break; + case QNetworkConfiguration::BearerWCDMA: + typeString = QLatin1String("WCDMA"); + break; + case QNetworkConfiguration::BearerHSPA: + typeString = QLatin1String("HSPA"); + break; + case QNetworkConfiguration::BearerBluetooth: + typeString = QLatin1String("Bluetooth"); + break; + case QNetworkConfiguration::BearerWiMAX: + typeString = QLatin1String("WiMAX"); + break; + case QNetworkConfiguration::BearerEVDO: + typeString = QLatin1String("EVDO"); + break; + case QNetworkConfiguration::BearerLTE: + typeString = QLatin1String("LTE"); + break; + default: + typeString = "unknown bearer (?)"; + } + + const char *isDefault = (allConfs.at(a) == m.defaultConfiguration()) + ? "*DEFAULT*" : ""; + qDebug() << isDefault << "identifier:" << allConfs.at(a).identifier() + << "bearer type name:" << allConfs.at(a).bearerTypeName() + << "bearer type:" << type << "(" << typeString << ")" + << "elapsed:" << elapsed; + QCOMPARE(allConfs.at(a).bearerTypeName(), typeString); + } +} + +void tst_qnetworkconfiguration::bearerTypeFamily() +{ + QNetworkConfigurationManager m; + foreach (const QNetworkConfiguration &config, + m.allConfigurations(QNetworkConfiguration::Active)) { + QString family; + switch (config.bearerTypeFamily()) { + case QNetworkConfiguration::Bearer3G: + family = QLatin1String("Bearer3G"); + break; + case QNetworkConfiguration::Bearer4G: + family = QLatin1String("Bearer4G"); + break; + default: + family = config.bearerTypeName(); + } + qDebug() << config.name() << "has bearer type" + << config.bearerTypeName() << "of bearer type family" + << family; + } +} + +QTEST_MAIN(tst_qnetworkconfiguration) + +#include "main.moc" diff --git a/tests/manual/qnetworkconfiguration/qnetworkconfiguration.pro b/tests/manual/qnetworkconfiguration/qnetworkconfiguration.pro new file mode 100644 index 0000000000..25ef41b92a --- /dev/null +++ b/tests/manual/qnetworkconfiguration/qnetworkconfiguration.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = tst_qnetworkconfiguration + +QT -= gui +QT += network testlib + +SOURCES += main.cpp diff --git a/tests/manual/qpainfo/main.cpp b/tests/manual/qpainfo/main.cpp index 6b712304a0..0f5119bab3 100644 --- a/tests/manual/qpainfo/main.cpp +++ b/tests/manual/qpainfo/main.cpp @@ -49,6 +49,7 @@ #include <QStringList> #include <QVariant> #include <QFont> +#include <QFontDatabase> #include <QSysInfo> #include <QLibraryInfo> #include <QStandardPaths> @@ -85,6 +86,12 @@ std::ostream &operator<<(std::ostream &str, const QStringList &l) return str; } +std::ostream &operator<<(std::ostream &str, const QFont &f) +{ + std::cout << '"' << f.family().toStdString() << "\" " << f.pointSize(); + return str; +} + static QStringList toNativeSeparators(QStringList in) { for (int i = 0; i < in.size(); ++i) @@ -184,7 +191,12 @@ int main(int argc, char **argv) << " from " << platformTheme->themeHint(QPlatformTheme::IconThemeSearchPaths).toStringList() << '\n'; } if (const QFont *systemFont = platformTheme->font()) - std::cout << " System font: \"" << systemFont->family().toStdString() << "\" " << systemFont->pointSize() << '\n'; + std::cout << " System font: " << *systemFont<< '\n'; + std::cout << " General font : " << QFontDatabase::systemFont(QFontDatabase::GeneralFont) << '\n' + << " Fixed font : " << QFontDatabase::systemFont(QFontDatabase::FixedFont) << '\n' + << " Title font : " << QFontDatabase::systemFont(QFontDatabase::TitleFont) << '\n' + << " Smallest font: " << QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont) << "\n\n"; + if (platformTheme->usePlatformNativeDialog(QPlatformTheme::FileDialog)) std::cout << " Native file dialog\n"; if (platformTheme->usePlatformNativeDialog(QPlatformTheme::ColorDialog)) diff --git a/tests/manual/qtabletevent/regular_widgets/main.cpp b/tests/manual/qtabletevent/regular_widgets/main.cpp index 1e2f5c00da..ce77cf8cff 100644 --- a/tests/manual/qtabletevent/regular_widgets/main.cpp +++ b/tests/manual/qtabletevent/regular_widgets/main.cpp @@ -43,12 +43,38 @@ #include <QDebug> #include <QMouseEvent> #include <QTabletEvent> -#include <QWidget> +#include <QMainWindow> +#include <QMenuBar> +#include <QMenu> +#include <QAction> +#include <QVector> +#include <QPainter> +#include <QCursor> + +enum TabletPointType { + TabletButtonPress, + TabletButtonRelease, + TabletMove, + TabletDraw +}; + +struct TabletPoint +{ + TabletPoint(const QPoint &p = QPoint(), TabletPointType t = TabletMove) : pos(p), type(t) {} + + QPoint pos; + TabletPointType type; +}; class EventReportWidget : public QWidget { + Q_OBJECT public: EventReportWidget(); + +public slots: + void clearPoints() { m_points.clear(); update(); } + protected: void mouseDoubleClickEvent(QMouseEvent *event) { outputMouseEvent(event); } void mouseMoveEvent(QMouseEvent *event) { outputMouseEvent(event); } @@ -57,11 +83,14 @@ protected: void tabletEvent(QTabletEvent *); + void paintEvent(QPaintEvent *); + private: void outputMouseEvent(QMouseEvent *event); bool m_lastIsMouseMove; bool m_lastIsTabletMove; + QVector<TabletPoint> m_points; }; EventReportWidget::EventReportWidget() @@ -69,6 +98,34 @@ EventReportWidget::EventReportWidget() , m_lastIsTabletMove(false) { } +void EventReportWidget::paintEvent(QPaintEvent *) +{ + QPainter p(this); + const QRect geom = QRect(QPoint(0, 0), size()); + p.fillRect(geom, Qt::white); + p.drawRect(QRect(geom.topLeft(), geom.bottomRight() - QPoint(1,1))); + foreach (const TabletPoint &t, m_points) { + if (geom.contains(t.pos)) { + QPainterPath pp; + pp.addEllipse(t.pos, 5, 5); + switch (t.type) { + case TabletButtonPress: + p.fillPath(pp, Qt::black); + break; + case TabletButtonRelease: + p.fillPath(pp, Qt::red); + break; + case TabletMove: + p.drawPath(pp); + break; + case TabletDraw: + p.fillPath(pp, Qt::blue); + break; + } + } + } +} + void EventReportWidget::tabletEvent(QTabletEvent *event) { QWidget::tabletEvent(event); @@ -89,14 +146,20 @@ void EventReportWidget::tabletEvent(QTabletEvent *event) m_lastIsTabletMove = true; type = QString::fromLatin1("TabletMove"); + m_points.push_back(TabletPoint(event->pos(), event->pressure() ? TabletDraw : TabletMove)); + update(); break; case QEvent::TabletPress: m_lastIsTabletMove = false; type = QString::fromLatin1("TabletPress"); + m_points.push_back(TabletPoint(event->pos(), TabletButtonPress)); + update(); break; case QEvent::TabletRelease: m_lastIsTabletMove = false; type = QString::fromLatin1("TabletRelease"); + m_points.push_back(TabletPoint(event->pos(), TabletButtonRelease)); + update(); break; default: Q_ASSERT(false); @@ -105,7 +168,8 @@ void EventReportWidget::tabletEvent(QTabletEvent *event) qDebug() << "Tablet event, type = " << type << " position = " << event->pos() - << " global position = " << event->globalPos(); + << " global position = " << event->globalPos() + << " cursor at " << QCursor::pos(); } void EventReportWidget::outputMouseEvent(QMouseEvent *event) @@ -144,7 +208,18 @@ void EventReportWidget::outputMouseEvent(QMouseEvent *event) int main(int argc, char *argv[]) { QApplication app(argc, argv); - EventReportWidget widget; - widget.show(); + QMainWindow mainWindow; + mainWindow.setWindowTitle(QString::fromLatin1("Tablet Test %1").arg(QT_VERSION_STR)); + EventReportWidget *widget = new EventReportWidget; + widget->setMinimumSize(640, 480); + QMenu *fileMenu = mainWindow.menuBar()->addMenu("File"); + QObject::connect(fileMenu->addAction("Clear"), SIGNAL(triggered()), widget, SLOT(clearPoints())); + QAction *quitAction = fileMenu->addAction("Quit"); + QObject::connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); + mainWindow.setCentralWidget(widget); + mainWindow.show(); return app.exec(); } + +#include "main.moc" diff --git a/tests/manual/widgets/itemviews/autoResizePrecision/tablehorz/testtable1.cpp b/tests/manual/widgets/itemviews/autoResizePrecision/tablehorz/testtable1.cpp new file mode 100644 index 0000000000..463366433c --- /dev/null +++ b/tests/manual/widgets/itemviews/autoResizePrecision/tablehorz/testtable1.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtWidgets/QtWidgets> + +const int rowCount = 2000; + +class TableDialog : public QDialog +{ + Q_OBJECT +public: + TableDialog() : model(rowCount, 3) { create(); } + void create() + { + resize(1000, 233); + gridLayout = new QGridLayout(this); + tableView = new QTableView(this); + + gridLayout->addWidget(tableView, 0, 0, 2, 1); + spinPrecision = new QSpinBox(this); + gridLayout->addWidget(spinPrecision, 0, 1, 1, 1); + verticalSpacer = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(verticalSpacer, 1, 1, 1, 1); + + QString ii = QString::fromLatin1("ii"); + QStringList is; + spinPrecision->setMinimum(-1); + spinPrecision->setMaximum(rowCount + 2); + for (int u = 0; u < rowCount; ++u) { + if (u % 25 == 0) + ii += QString::fromLatin1("i"); + else + ii[ii.length() - 1] = QChar::fromLatin1('a' + (u % 25)); + ii[ii.length() - 2] = QChar::fromLatin1('i'); + is.append(ii); + } + + for (int u = 0; u < rowCount; ++u) { + QString col1; + col1 = QString::fromLatin1("Row: %1").arg(u); + model.setData(model.index(u, 0), col1); + model.setData(model.index(u, 1), is[u]); + model.setData(model.index(u, 2), is[rowCount - u -1]); + } + tableView->setModel(&model); + + tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + spinPrecision->setValue(tableView->horizontalHeader()->resizeContentsPrecision()); + connect(spinPrecision, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int))); + } // setupUi +protected slots: + void slotValueChanged(int newval); +protected: + QGridLayout *gridLayout; + QTableView *tableView; + QSpinBox *spinPrecision; + QSpacerItem *verticalSpacer; + QStandardItemModel model; +}; + +void TableDialog::slotValueChanged(int newval) +{ + tableView->horizontalHeader()->setResizeContentsPrecision(newval, true); +} + + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + TableDialog d1; + d1.show(); + app.exec(); +} + +#include "testtable1.moc" diff --git a/tests/manual/widgets/itemviews/autoResizePrecision/tablehorz/testtable1.pro b/tests/manual/widgets/itemviews/autoResizePrecision/tablehorz/testtable1.pro new file mode 100644 index 0000000000..e07f40bc2f --- /dev/null +++ b/tests/manual/widgets/itemviews/autoResizePrecision/tablehorz/testtable1.pro @@ -0,0 +1,2 @@ +SOURCES = testtable1.cpp +QT += widgets diff --git a/tests/manual/widgets/itemviews/autoResizePrecision/tablevert/testtable2.cpp b/tests/manual/widgets/itemviews/autoResizePrecision/tablevert/testtable2.cpp new file mode 100644 index 0000000000..027801d528 --- /dev/null +++ b/tests/manual/widgets/itemviews/autoResizePrecision/tablevert/testtable2.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtWidgets/QtWidgets> + +const int columnCount = 1500; + +class TableDialog : public QDialog +{ + Q_OBJECT +public: + TableDialog() : model(2, columnCount) { create(); } + void create() + { + resize(1200, 400); + gridLayout = new QGridLayout(this); + tableView = new QTableView(this); + + gridLayout->addWidget(tableView, 0, 0, 2, 1); + spinPrecision = new QSpinBox(this); + gridLayout->addWidget(spinPrecision, 0, 1, 1, 1); + verticalSpacer = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(verticalSpacer, 1, 1, 1, 1); + + QString ii = QString::fromLatin1("ii"); + QStringList is; + spinPrecision->setMinimum(-1); + spinPrecision->setMaximum(columnCount + 2); + + QFont f = QApplication::font(); + for (int u = 0; u < columnCount; ++u) { + int size = 10 + (u % 63); + f.setPixelSize(size); + QString col; + if (u % 50 < 25) + col = QChar::fromLatin1('a' + (u % 25)); + else + col = QChar::fromLatin1('A' + (u % 25)); + + int v = columnCount - u - 1; + model.setData(model.index(0, u), col); + model.setData(model.index(1, v), col); + + model.setData(model.index(0, u), f, Qt::FontRole); + model.setData(model.index(1, v), f, Qt::FontRole); + } + tableView->setModel(&model); + + for (int u = 0; u < columnCount; ++ u) + tableView->horizontalHeader()->resizeSection(u, 60); + + // Make last index in first row a bit special + f.setPixelSize(96); + model.setData(model.index(0, columnCount - 1), f, Qt::FontRole); + model.setData(model.index(0, columnCount - 1), QString::fromLatin1("qI")); + tableView->horizontalHeader()->resizeSection(columnCount - 1, 140); + + tableView->verticalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + tableView->verticalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + spinPrecision->setValue(tableView->verticalHeader()->resizeContentsPrecision()); + connect(spinPrecision, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int))); + } // setupUi +protected slots: + void slotValueChanged(int newval); +protected: + QGridLayout *gridLayout; + QTableView *tableView; + QSpinBox *spinPrecision; + QSpacerItem *verticalSpacer; + QStandardItemModel model; +}; + +void TableDialog::slotValueChanged(int newval) +{ + tableView->verticalHeader()->setResizeContentsPrecision(newval, true); +} + + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + TableDialog d1; + d1.show(); + app.exec(); +} + +#include "testtable2.moc" diff --git a/tests/manual/widgets/itemviews/autoResizePrecision/tablevert/testtable2.pro b/tests/manual/widgets/itemviews/autoResizePrecision/tablevert/testtable2.pro new file mode 100644 index 0000000000..b887fcb14b --- /dev/null +++ b/tests/manual/widgets/itemviews/autoResizePrecision/tablevert/testtable2.pro @@ -0,0 +1,2 @@ +SOURCES = testtable2.cpp +QT += widgets diff --git a/tests/manual/widgets/itemviews/autoResizePrecision/treeview/testtree.cpp b/tests/manual/widgets/itemviews/autoResizePrecision/treeview/testtree.cpp new file mode 100644 index 0000000000..c48d933fcd --- /dev/null +++ b/tests/manual/widgets/itemviews/autoResizePrecision/treeview/testtree.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtWidgets/QtWidgets> + +class TreeDialog : public QDialog +{ + Q_OBJECT +public: + TreeDialog() { create(); } +protected: + void create() + { + resize(1000, 233); + gridLayout = new QGridLayout(this); + treeWidget = new QTreeWidget(this); + + gridLayout->addWidget(treeWidget, 0, 0, 2, 1); + spinPrecision = new QSpinBox(this); + gridLayout->addWidget(spinPrecision, 0, 1, 1, 1); + verticalSpacer = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(verticalSpacer, 1, 1, 1, 1); + + QStringList itemInfo("Col1"); + itemInfo.append("Col2"); + itemInfo.append("Col3"); + itemInfo.append("Dummy"); + // Developer no. could also have been social security number og some other id. + treeWidget->setHeaderLabels(itemInfo); + + QStringList sl1("This is Root Item"); + sl1.append("i"); + QTreeWidgetItem *rootitem = new QTreeWidgetItem(treeWidget, sl1); + + QStringList sl2("This is Child1 Item"); + sl2.append("WW"); + QTreeWidgetItem *child1 = new QTreeWidgetItem(rootitem, sl2); + + QString ii = QString::fromLatin1("ii"); + QStringList is; + const int rowCount = 3000; + spinPrecision->setMinimum(-1); + spinPrecision->setMaximum(rowCount + 5); + for (int u = 0; u < rowCount; ++u) { + if (u % 25 == 0) + ii += QString::fromLatin1("i"); + else + ii[ii.length() - 1] = QChar::fromLatin1('a' + (u % 25)); + ii[ii.length() - 2] = QChar::fromLatin1('i'); + is.append(ii); + } + + for (int u = 0; u < rowCount - 2; ++u) { // -2 since we have rootitem and child1 + QString col1; + col1 = QString::fromLatin1("This is child item %1").arg(u + 2); + + QStringList sl(col1); + sl.append(is[u]); + sl.append(is[rowCount - u - 1]); + + if (u > 500) + new QTreeWidgetItem(rootitem, sl); + else + new QTreeWidgetItem(child1, sl); + } + treeWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + treeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + treeWidget->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + spinPrecision->setValue(treeWidget->header()->resizeContentsPrecision()); + connect(spinPrecision, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int))); + } // setupUi +protected slots: + void slotValueChanged(int newval); +protected: + QGridLayout *gridLayout; + QTreeWidget *treeWidget; + QSpinBox *spinPrecision; + QSpacerItem *verticalSpacer; +}; + +void TreeDialog::slotValueChanged(int newval) +{ + treeWidget->header()->setResizeContentsPrecision(newval, true); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + TreeDialog d1; + d1.show(); + app.exec(); +} + +#include "testtree.moc" diff --git a/tests/manual/widgets/itemviews/autoResizePrecision/treeview/testtree.pro b/tests/manual/widgets/itemviews/autoResizePrecision/treeview/testtree.pro new file mode 100644 index 0000000000..c062586eac --- /dev/null +++ b/tests/manual/widgets/itemviews/autoResizePrecision/treeview/testtree.pro @@ -0,0 +1,2 @@ +SOURCES = testtree.cpp +QT += widgets diff --git a/tests/manual/widgets/itemviews/itemviews.pro b/tests/manual/widgets/itemviews/itemviews.pro index 58b02bfc0d..6b91531a87 100644 --- a/tests/manual/widgets/itemviews/itemviews.pro +++ b/tests/manual/widgets/itemviews/itemviews.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = delegate qheaderview qtreeview +SUBDIRS = delegate qheaderview qtreeview qtreewidget diff --git a/tests/manual/widgets/itemviews/qtreeview/main.cpp b/tests/manual/widgets/itemviews/qtreeview/main.cpp index 296ba6bcbf..22b4e07f75 100644 --- a/tests/manual/widgets/itemviews/qtreeview/main.cpp +++ b/tests/manual/widgets/itemviews/qtreeview/main.cpp @@ -39,17 +39,34 @@ ** ****************************************************************************/ - -#include <QtWidgets/QFileSystemModel> -#include <QtWidgets/QtWidgets> +#include <QtWidgets> int main(int argc, char *argv[]) { QApplication app(argc, argv); - QFileSystemModel *model = new QFileSystemModel; - model->setRootPath(QDir::currentPath()); - QTreeView *tree = new QTreeView(); - tree->setModel(model); - tree->show(); - app.exec(); + QFileSystemModel model; + QWidget window; + QTreeView *tree = new QTreeView(&window); + tree->setMaximumSize(1000, 600); + + QHBoxLayout *layout = new QHBoxLayout; + layout->setSizeConstraint(QLayout::SetFixedSize); + layout->addWidget(tree); + + window.setLayout(layout); + model.setRootPath(""); + tree->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + tree->setModel(&model); + + tree->setAnimated(false); + tree->setIndentation(20); + tree->setSortingEnabled(true); + tree->header()->setStretchLastSection(false); + + window.setWindowTitle(QObject::tr("Dir View")); + tree->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + + window.show(); + + return app.exec(); } diff --git a/tests/manual/widgets/itemviews/qtreewidget/main.cpp b/tests/manual/widgets/itemviews/qtreewidget/main.cpp new file mode 100644 index 0000000000..9428113250 --- /dev/null +++ b/tests/manual/widgets/itemviews/qtreewidget/main.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QVBoxLayout> +#include <QTreeWidget> +#include <QGroupBox> +#include <QRadioButton> +#include <QDialog> +#include <QApplication> +#include <QHeaderView> + +class ExampleDlg : public QDialog +{ + Q_OBJECT +public: + QVBoxLayout *groupLayout; + QVBoxLayout *dialogLayout; + QTreeWidget *treeWidget; + QGroupBox *groupBox; + QRadioButton *radioFirstName; + QRadioButton *radioLastName; + QRadioButton *radioDeveloperNo; + QRadioButton *radioTitle; + + ExampleDlg() : QDialog(0) + { + dialogLayout = new QVBoxLayout(this); + treeWidget = new QTreeWidget(this); + dialogLayout->addWidget(treeWidget); + + groupBox = new QGroupBox(this); + groupLayout = new QVBoxLayout(groupBox); + radioFirstName = new QRadioButton("First Name", groupBox); + groupLayout->addWidget(radioFirstName); + radioLastName = new QRadioButton("Last Name", groupBox); + groupLayout->addWidget(radioLastName); + radioDeveloperNo = new QRadioButton("Developer No.", groupBox); + groupLayout->addWidget(radioDeveloperNo); + radioTitle = new QRadioButton("Title", groupBox); + groupLayout->addWidget(radioTitle); + dialogLayout->addWidget(groupBox); + + QStringList item1sl("Barry"); + item1sl.append("Butter"); + item1sl.append("12199"); + item1sl.append("Key Maintainer"); + QTreeWidgetItem *item1 = new QTreeWidgetItem(treeWidget, item1sl); + + QStringList item2sl("Cordon"); + item2sl.append("Rampsey"); + item2sl.append("59299"); + item2sl.append("Maintainer"); + QTreeWidgetItem *item2 = new QTreeWidgetItem(item1, item2sl); + + QStringList item3sl("Samuel le"); + item3sl.append("Smackson"); + item3sl.append("708"); + item3sl.append("Contributer"); + /* QTreeWidgetItem *item3 = */ new QTreeWidgetItem(item2, item3sl); + + QStringList item4sl("Georg"); + item4sl.append("Ambush"); + item4sl.append("86999"); + item4sl.append("Area Maintainer"); + QTreeWidgetItem *item4 = new QTreeWidgetItem(item1, item4sl); + + QStringList item5sl("Arne"); + item5sl.append("Strassenleger"); + item5sl.append("338999"); + item5sl.append("Approver"); + /* QTreeWidgetItem *item4 =*/ new QTreeWidgetItem(item4, item5sl); + + treeWidget->setColumnCount(item2sl.size()); + QStringList itemInfo("First Name"); + itemInfo.append("Last Name"); + itemInfo.append("Developer No."); + // Developer no. could also have been social security number og some other id. + itemInfo.append("Title"); + treeWidget->setHeaderLabels(itemInfo); + radioFirstName->setChecked(true); + + connect(radioFirstName, SIGNAL(toggled(bool)), this, SLOT(fixDataInTree(bool))); + connect(radioLastName, SIGNAL(toggled(bool)), this, SLOT(fixDataInTree(bool))); + connect(radioDeveloperNo, SIGNAL(toggled(bool)), this, SLOT(fixDataInTree(bool))); + connect(radioTitle, SIGNAL(toggled(bool)), this, SLOT(fixDataInTree(bool))); + treeWidget->setTreePosition(-1); + } + + protected slots: + void fixDataInTree(bool checked) + { + if (!checked) + return; + int colInTree = 0; // first Name + if (radioLastName->isChecked()) + colInTree = 1; + if (radioDeveloperNo->isChecked()) + colInTree = 2; + if (radioTitle->isChecked()) + colInTree = 3; + treeWidget->header()->swapSections(0, treeWidget->header()->visualIndex(colInTree)); + } +}; + + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + ExampleDlg d; + d.show(); + app.exec(); +} + +#include "main.moc" diff --git a/tests/manual/widgets/itemviews/qtreewidget/qtreewidgettest.pro b/tests/manual/widgets/itemviews/qtreewidget/qtreewidgettest.pro new file mode 100644 index 0000000000..4b1da9be38 --- /dev/null +++ b/tests/manual/widgets/itemviews/qtreewidget/qtreewidgettest.pro @@ -0,0 +1,4 @@ +TEMPLATE = app +SOURCES = main.cpp +QT += widgets core-private +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/manual/widgets/kernel/kernel.pro b/tests/manual/widgets/kernel/kernel.pro new file mode 100644 index 0000000000..968d71724f --- /dev/null +++ b/tests/manual/widgets/kernel/kernel.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = qtooltip sizeonhide diff --git a/tests/manual/widgets/kernel/qtooltip/main.cpp b/tests/manual/widgets/kernel/qtooltip/main.cpp new file mode 100644 index 0000000000..a7a2b9915c --- /dev/null +++ b/tests/manual/widgets/kernel/qtooltip/main.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QTest> +#include <QDialog> +#include <QToolTip> +#include <QLabel> +#include <QPushButton> +#include <QVBoxLayout> +#include <QProxyStyle> +#include <QSpinBox> + +class QToolTipTest : public QProxyStyle +{ + Q_OBJECT +public: + QToolTipTest() : QProxyStyle() + { + wakeTime = QApplication::style()->styleHint(SH_ToolTip_WakeUpDelay); + sleepTime = QApplication::style()->styleHint(SH_ToolTip_FallAsleepDelay); + } + + int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, + QStyleHintReturn *returnData = 0) const + { + switch (hint) { + case SH_ToolTip_WakeUpDelay: + return wakeTime; + case SH_ToolTip_FallAsleepDelay: + return sleepTime; + default: + return QProxyStyle::styleHint(hint, option, widget, returnData); + } + } + +public slots: + void setWakeTime(int wake) { wakeTime = wake; } + void setSleepTime(int sleep) { sleepTime = sleep; } +protected: + int wakeTime; + int sleepTime; +}; + +class TestDialog : public QDialog +{ + Q_OBJECT +public: + TestDialog(QToolTipTest *s); + QToolTipTest *style; +protected slots: + void showSomeToolTips(); +}; + +void TestDialog::showSomeToolTips() +{ + QPoint p(100 + 20, 100 + 20); + + for (int u = 1; u < 20; u += 5) { + QString s = tr("Seconds: ") + QString::number(u); + QToolTip::showText(p, s, 0, QRect(), 1000 * u); + QTest::qWait((u + 1) * 1000); + } + + QToolTip::showText(p, tr("Seconds: 2"), 0, QRect(), 2000); + QTest::qWait(3000); + + QToolTip::showText(p, tr("Standard label"), 0, QRect()); + QTest::qWait(12000); +} + +TestDialog::TestDialog(QToolTipTest *s) : style(s) +{ + // Notice that these tool tips will disappear if another tool tip is shown. + QLabel *label1 = new QLabel(tr("Tooltip - Only two seconds display")); + label1->setToolTip(tr("2 seconds display")); + label1->setToolTipDuration(2000); + Q_ASSERT(label1->toolTipDuration() == 2000); + + QLabel *label2 = new QLabel(tr("Tooltip - 30 seconds display time")); + label2->setToolTip(tr("30 seconds display")); + label2->setToolTipDuration(30000); + + QPushButton *pb = new QPushButton(tr("&Test")); + pb->setToolTip(tr("Show some tool tips.")); + Q_ASSERT(pb->toolTipDuration() == -1); + connect(pb, SIGNAL(clicked()), this, SLOT(showSomeToolTips())); + + QLabel *wakeLabel = new QLabel(tr("Wake Delay:")); + QSpinBox *wakeSpinBox = new QSpinBox(); + wakeSpinBox->setRange(0, 100000); + wakeSpinBox->setValue(style->styleHint(QStyle::SH_ToolTip_WakeUpDelay)); + connect(wakeSpinBox, SIGNAL(valueChanged(int)), style, SLOT(setWakeTime(int))); + + QLabel *sleepLabel = new QLabel(tr("Sleep Delay:")); + QSpinBox *sleepSpinBox = new QSpinBox(); + sleepSpinBox->setRange(0, 100000); + sleepSpinBox->setValue(style->styleHint(QStyle::SH_ToolTip_FallAsleepDelay)); + connect(sleepSpinBox, SIGNAL(valueChanged(int)), style, SLOT(setSleepTime(int))); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(label1); + layout->addWidget(label2); + layout->addWidget(pb); + layout->addWidget(wakeLabel); + layout->addWidget(wakeSpinBox); + layout->addWidget(wakeLabel); + layout->addWidget(sleepLabel); + layout->addWidget(sleepSpinBox); + + setLayout(layout); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QToolTipTest *style = new QToolTipTest(); + QApplication::setStyle(style); + TestDialog dlg(style); + dlg.show(); + return app.exec(); +} + +#include "main.moc" diff --git a/tests/manual/widgets/kernel/qtooltip/main.pro b/tests/manual/widgets/kernel/qtooltip/main.pro new file mode 100644 index 0000000000..dac880a10e --- /dev/null +++ b/tests/manual/widgets/kernel/qtooltip/main.pro @@ -0,0 +1,2 @@ +SOURCES = main.cpp +QT += widgets testlib diff --git a/tests/manual/widgets/kernel/sizeonhide/main.cpp b/tests/manual/widgets/kernel/sizeonhide/main.cpp new file mode 100644 index 0000000000..e8b95dfe28 --- /dev/null +++ b/tests/manual/widgets/kernel/sizeonhide/main.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Thorbjørn Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtWidgets> + +class KeepSizeExampleDlg : public QDialog +{ + Q_OBJECT +public: + QGridLayout *gridLayout; + QHBoxLayout *horizontalLayout; + QVBoxLayout *verticalLayout; + QCheckBox *checkBox; + QCheckBox *checkBox2; + QCheckBox *checkBox3; + QCheckBox *checkBox4; + QGroupBox *groupBox; + QVBoxLayout *verticalLayout2; + QRadioButton *radioButton; + QRadioButton *radioButton2; + QRadioButton *radioButton3; + QTableView *tableView; + QPushButton *pushButton; + QSpacerItem *horizontalSpacer; + + KeepSizeExampleDlg() + { + QWidget *form = this; + form->resize(408, 295); + gridLayout = new QGridLayout(form); + horizontalLayout = new QHBoxLayout(); + verticalLayout = new QVBoxLayout(); + checkBox = new QCheckBox(form); + verticalLayout->addWidget(checkBox); + checkBox2 = new QCheckBox(form); + verticalLayout->addWidget(checkBox2); + checkBox3 = new QCheckBox(form); + verticalLayout->addWidget(checkBox3); + checkBox4 = new QCheckBox(form); + verticalLayout->addWidget(checkBox4); + horizontalLayout->addLayout(verticalLayout); + groupBox = new QGroupBox(form); + verticalLayout2 = new QVBoxLayout(groupBox); + radioButton = new QRadioButton(groupBox); + verticalLayout2->addWidget(radioButton); + radioButton2 = new QRadioButton(groupBox); + verticalLayout2->addWidget(radioButton2); + radioButton3 = new QRadioButton(groupBox); + verticalLayout2->addWidget(radioButton3); + horizontalLayout->addWidget(groupBox); + gridLayout->addLayout(horizontalLayout, 0, 0, 1, 2); + tableView = new QTableView(form); + gridLayout->addWidget(tableView, 1, 0, 1, 2); + pushButton = new QPushButton(form); + gridLayout->addWidget(pushButton, 2, 0, 1, 1); + horizontalSpacer = new QSpacerItem(340, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + gridLayout->addItem(horizontalSpacer, 2, 1, 1, 1); + checkBox->setText(QString::fromUtf8("CheckBox1")); + checkBox2->setText(QString::fromUtf8("CheckBox2")); + checkBox3->setText(QString::fromUtf8("CheckBox - for client A only")); + checkBox4->setText(QString::fromUtf8("CheckBox - also for client A")); + groupBox->setTitle(QString::fromUtf8("Mode")); + radioButton->setText(QString::fromUtf8("Mode 1")); + radioButton2->setText(QString::fromUtf8("Mode 2")); + radioButton3->setText(QString::fromUtf8("Mode 3")); + pushButton->setText(QString::fromUtf8("&Hide/Show")); + + QObject::connect(pushButton, SIGNAL(clicked()), this, SLOT(showOrHide())); + } + + protected slots: + void showOrHide() + { + if (checkBox3->isVisible()) { + checkBox3->hide(); + checkBox4->hide(); + } else { + checkBox3->show(); + checkBox4->show(); + } + } +}; + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + KeepSizeExampleDlg d; + QSizePolicy policyKeepSpace = d.checkBox3->sizePolicy(); + policyKeepSpace.setRetainSizeWhenHidden(true); + d.checkBox3->setSizePolicy(policyKeepSpace); + d.checkBox4->setSizePolicy(policyKeepSpace); + d.show(); + app.exec(); +} + +#include "main.moc" diff --git a/tests/manual/widgets/kernel/sizeonhide/sizeonhide.pro b/tests/manual/widgets/kernel/sizeonhide/sizeonhide.pro new file mode 100644 index 0000000000..1969392ab3 --- /dev/null +++ b/tests/manual/widgets/kernel/sizeonhide/sizeonhide.pro @@ -0,0 +1,3 @@ +TEMPLATE = app +SOURCES = main.cpp +QT += widgets core-private diff --git a/tests/manual/widgets/qgraphicsview/rubberband/rubberbandtest.cpp b/tests/manual/widgets/qgraphicsview/rubberband/rubberbandtest.cpp index aec2479239..bb05570f18 100644 --- a/tests/manual/widgets/qgraphicsview/rubberband/rubberbandtest.cpp +++ b/tests/manual/widgets/qgraphicsview/rubberband/rubberbandtest.cpp @@ -49,7 +49,7 @@ public: setFlags(QGraphicsItem::ItemIsSelectable); } - void paint(QPainter *painter, const QStyleOptionGraphicsItem * /* option*/, QWidget * /*widget*/) + void paint(QPainter *painter, const QStyleOptionGraphicsItem * /* option*/, QWidget * /*widget*/) Q_DECL_OVERRIDE { if (isSelected()) painter->fillRect(rect(), QColor(255, 0, 0)); @@ -68,7 +68,7 @@ public: connect(this, SIGNAL(rubberBandChanged(QRect, QPointF, QPointF)), this, SLOT(updateRubberbandInfo(QRect, QPointF, QPointF))); } protected: - void mouseMoveEvent(QMouseEvent *event) + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE { QGraphicsView::mouseMoveEvent(event); diff --git a/tests/manual/widgets/widgets.pro b/tests/manual/widgets/widgets.pro index 4e2e4c7cee..e9dcdf39e7 100644 --- a/tests/manual/widgets/widgets.pro +++ b/tests/manual/widgets/widgets.pro @@ -1,2 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = itemviews qgraphicsview +SUBDIRS = itemviews qgraphicsview kernel + diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index c7477abe99..430dae5e87 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -135,23 +135,9 @@ Configure::Configure(int& argc, char** argv) const QString installPath = buildPath; #endif if (sourceDir != buildDir) { //shadow builds! - cout << "Preparing build tree..." << endl; QDir(buildPath).mkpath("bin"); - //copy the mkspecs buildDir.mkpath("mkspecs"); - if (!Environment::cpdir(sourcePath + "/mkspecs", buildPath + "/mkspecs")){ - cout << "Couldn't copy mkspecs!" << sourcePath << " " << buildPath << endl; - dictionary["DONE"] = "error"; - return; - } - - buildDir.mkpath("doc"); - if (!Environment::cpdir(sourcePath + "/doc/global", buildPath + "/doc/global")) { - cout << "Couldn't copy global documentation!" << sourcePath << " " << buildPath << endl; - dictionary["DONE"] = "error"; - return; - } } defaultBuildParts << QStringLiteral("libs") << QStringLiteral("tools") << QStringLiteral("examples"); @@ -2819,6 +2805,14 @@ void Configure::generateCachefile() moduleStream << "QT_SKIP_MODULES += " << skipModules.join(' ') << endl; moduleStream << endl; + moduleStream << "host_build {" << endl; + moduleStream << " QT_CPU_FEATURES." << dictionary["QT_HOST_ARCH"] << + " = " << dictionary["QT_HOST_CPU_FEATURES"] << endl; + moduleStream << "} else {" << endl; + moduleStream << " QT_CPU_FEATURES." << dictionary["QT_ARCH"] << + " = " << dictionary["QT_CPU_FEATURES"] << endl; + moduleStream << "}" << endl; + if (dictionary["QT_EDITION"] != "QT_EDITION_OPENSOURCE") moduleStream << "DEFINES *= QT_EDITION=QT_EDITION_DESKTOP" << endl; @@ -3099,15 +3093,17 @@ void Configure::generateQConfigPri() configStream << " qpa"; configStream << endl; - configStream << "QT_ARCH = " << dictionary["QT_ARCH"] << endl; - configStream << "QT_HOST_ARCH = " << dictionary["QT_HOST_ARCH"] << endl; - configStream << "QT_CPU_FEATURES = " << dictionary["QT_CPU_FEATURES"] << endl; - configStream << "QT_HOST_CPU_FEATURES = " << dictionary["QT_HOST_CPU_FEATURES"] << endl; + configStream << "host_build {" << endl; + configStream << " QT_ARCH = " << dictionary["QT_HOST_ARCH"] << endl; + configStream << " QT_TARGET_ARCH = " << dictionary["QT_ARCH"] << endl; + configStream << "} else {" << endl; + configStream << " QT_ARCH = " << dictionary["QT_ARCH"] << endl; if (dictionary.contains("XQMAKESPEC") && !dictionary["XQMAKESPEC"].startsWith("wince")) { // FIXME: add detection - configStream << "QMAKE_DEFAULT_LIBDIRS = /lib /usr/lib" << endl; - configStream << "QMAKE_DEFAULT_INCDIRS = /usr/include /usr/local/include" << endl; + configStream << " QMAKE_DEFAULT_LIBDIRS = /lib /usr/lib" << endl; + configStream << " QMAKE_DEFAULT_INCDIRS = /usr/include /usr/local/include" << endl; } + configStream << "}" << endl; if (dictionary["QT_EDITION"].contains("OPENSOURCE")) configStream << "QT_EDITION = " << QLatin1String("OpenSource") << endl; else @@ -3867,6 +3863,9 @@ void Configure::buildQmake() QTextStream confStream(&confFile); confStream << "[EffectivePaths]" << endl << "Prefix=.." << endl; + if (sourcePath != buildPath) + confStream << "[EffectiveSourcePaths]" << endl + << "Prefix=" << sourcePath << endl; confStream.flush(); confFile.close(); diff --git a/util/local_database/enumdata.py b/util/local_database/enumdata.py index b5935ca45f..256866e177 100644 --- a/util/local_database/enumdata.py +++ b/util/local_database/enumdata.py @@ -616,7 +616,8 @@ country_list = { 253 : [ "TristanDaCunha", "TA" ], 254 : [ "SouthSudan", "SS" ], 255 : [ "Bonaire", "BQ" ], - 256 : [ "SintMaarten", "SX" ] + 256 : [ "SintMaarten", "SX" ], + 257 : [ "Kosovo", "XK" ] } script_list = { diff --git a/util/unicode/main.cpp b/util/unicode/main.cpp index 5affaeb59f..a4d3e0f377 100644 --- a/util/unicode/main.cpp +++ b/util/unicode/main.cpp @@ -689,8 +689,9 @@ static const char *property_string = " ushort titleCaseSpecial : 1;\n" " ushort caseFoldSpecial : 1;\n" " ushort unicodeVersion : 4;\n" - " ushort graphemeBreakClass : 8; /* 4 used */\n" - " ushort wordBreakClass : 8; /* 4 used */\n" + " ushort nfQuickCheck : 8;\n" // could be narrowed + " ushort graphemeBreakClass : 4; /* 4 used */\n" + " ushort wordBreakClass : 4; /* 4 used */\n" " ushort sentenceBreakClass : 8; /* 4 used */\n" " ushort lineBreakClass : 8; /* 6 used */\n" " ushort script : 8; /* 7 used */\n" @@ -741,6 +742,7 @@ struct PropertyFlags { && sentenceBreakClass == o.sentenceBreakClass && lineBreakClass == o.lineBreakClass && script == o.script + && nfQuickCheck == o.nfQuickCheck ); } // from UnicodeData.txt @@ -768,6 +770,8 @@ struct PropertyFlags { SentenceBreakClass sentenceBreakClass; LineBreakClass lineBreakClass; int script; + // from DerivedNormalizationProps.txt + uchar nfQuickCheck; }; @@ -873,6 +877,7 @@ struct UnicodeData { p.wordBreakClass = WordBreak_Other; p.sentenceBreakClass = SentenceBreak_Other; p.script = QChar::Script_Unknown; + p.nfQuickCheck = 0; propertyIndex = -1; excludedComposition = false; } @@ -1270,9 +1275,12 @@ static void readDerivedNormalizationProps() Q_ASSERT(l.size() >= 2); QByteArray propName = l[1].trimmed(); - if (propName != "Full_Composition_Exclusion") + if (propName != "Full_Composition_Exclusion" && + propName != "NFD_QC" && propName != "NFC_QC" && + propName != "NFKD_QC" && propName != "NFKC_QC") { // ### continue; + } QByteArray codes = l[0].trimmed(); codes.replace("..", "."); @@ -1289,7 +1297,35 @@ static void readDerivedNormalizationProps() for (int codepoint = from; codepoint <= to; ++codepoint) { UnicodeData &d = UnicodeData::valueRef(codepoint); - d.excludedComposition = true; + if (propName == "Full_Composition_Exclusion") { + d.excludedComposition = true; + } else { + Q_STATIC_ASSERT(QString::NormalizationForm_D == 0); + Q_STATIC_ASSERT(QString::NormalizationForm_C == 1); + Q_STATIC_ASSERT(QString::NormalizationForm_KD == 2); + Q_STATIC_ASSERT(QString::NormalizationForm_KC == 3); + + QString::NormalizationForm form; + if (propName == "NFD_QC") + form = QString::NormalizationForm_D; + else if (propName == "NFC_QC") + form = QString::NormalizationForm_C; + else if (propName == "NFKD_QC") + form = QString::NormalizationForm_KD; + else// if (propName == "NFKC_QC") + form = QString::NormalizationForm_KC; + + Q_ASSERT(l.size() == 3); + l[2] = l[2].trimmed(); + + enum { NFQC_YES = 0, NFQC_NO = 1, NFQC_MAYBE = 3 }; + uchar ynm = (l[2] == "N" ? NFQC_NO : l[2] == "M" ? NFQC_MAYBE : NFQC_YES); + if (ynm == NFQC_MAYBE) { + // if this changes, we need to revise the normalizationQuickCheckHelper() implementation + Q_ASSERT(form == QString::NormalizationForm_C || form == QString::NormalizationForm_KC); + } + d.p.nfQuickCheck |= (ynm << (form << 1)); // 2 bits per NF + } } } @@ -2246,8 +2282,11 @@ static QByteArray createPropertyInfo() // " ushort unicodeVersion : 4;\n" out += QByteArray::number( p.age ); out += ", "; -// " ushort graphemeBreakClass : 8; /* 4 used */\n" -// " ushort wordBreakClass : 8; /* 4 used */\n" +// " ushort nfQuickCheck : 8;\n" + out += QByteArray::number( p.nfQuickCheck ); + out += ", "; +// " ushort graphemeBreakClass : 4; /* 4 used */\n" +// " ushort wordBreakClass : 4; /* 4 used */\n" // " ushort sentenceBreakClass : 8; /* 4 used */\n" // " ushort lineBreakClass : 8; /* 6 used */\n" out += QByteArray::number( p.graphemeBreakClass ); |