summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2015-08-26 20:06:57 +0200
committerLiang Qi <liang.qi@theqtcompany.com>2015-08-26 20:06:57 +0200
commitafab1546a7665bac2a8d7a6452e6aea46bfd2127 (patch)
treed616a7559c54a40e35a12b464f606774c9b0475b
parent06b457c693f207e392d3021d77a0ab18cd78da92 (diff)
parent53ecaade10319ecc1d8115521ae6d8eba1ee55c1 (diff)
Merge remote-tracking branch 'origin/5.5' into 5.6
Conflicts: qmake/doc/snippets/code/doc_src_qmake-manual.pro qmake/doc/src/qmake-manual.qdoc src/corelib/io/qstorageinfo_unix.cpp src/corelib/tools/qbytearray.cpp src/widgets/kernel/qwidgetwindow.cpp tests/auto/corelib/io/qprocess/tst_qprocess.cpp tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp tests/auto/network/access/qnetworkreply/BLACKLIST Change-Id: I9efcd7e1cce1c394eed425c43aa6fce7d2edf31c
-rw-r--r--LICENSE.GPLv32
-rw-r--r--LICENSE.LGPLv34
-rw-r--r--mkspecs/common/msvc-desktop.conf2
-rw-r--r--mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in5
-rw-r--r--mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in4
-rw-r--r--mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in4
-rw-r--r--mkspecs/features/winrt/default_pre.prf12
-rw-r--r--mkspecs/features/winrt/package_manifest.prf17
-rw-r--r--mkspecs/winrt-arm-msvc2015/qmake.conf14
-rw-r--r--mkspecs/winrt-x64-msvc2015/qmake.conf14
-rw-r--r--mkspecs/winrt-x86-msvc2015/qmake.conf14
-rw-r--r--qmake/doc/snippets/code/doc_src_qmake-manual.pro6
-rw-r--r--qmake/doc/src/qmake-manual.qdoc19
-rw-r--r--qmake/generators/mac/pbuilder_pbx.cpp6
-rw-r--r--qmake/generators/unix/unixmake2.cpp4
-rw-r--r--qmake/generators/win32/msbuild_objectmodel.cpp7
-rw-r--r--qmake/generators/win32/msvc_nmake.cpp25
-rw-r--r--qmake/generators/win32/msvc_vcproj.cpp3
-rw-r--r--src/3rdparty/pcre/patches/0001-Re-fix-X86-Wince-builds.patch35
-rw-r--r--src/3rdparty/pcre/pcre.h6
-rw-r--r--src/3rdparty/pcre/pcre_compile.c271
-rw-r--r--src/3rdparty/pcre/pcre_exec.c3
-rw-r--r--src/3rdparty/pcre/pcre_internal.h17
-rw-r--r--src/3rdparty/pcre/pcre_jit_compile.c58
-rw-r--r--src/3rdparty/pcre/pcre_study.c19
-rw-r--r--src/3rdparty/pcre/sljit/sljitConfig.h9
-rw-r--r--src/3rdparty/pcre/sljit/sljitConfigInternal.h13
-rw-r--r--src/3rdparty/pcre/sljit/sljitLir.c10
-rw-r--r--src/3rdparty/pcre/sljit/sljitLir.h40
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativeARM_32.c27
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativeARM_64.c48
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c58
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c15
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativePPC_common.c23
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c19
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c311
-rw-r--r--src/3rdparty/pcre/sljit/sljitNativeX86_common.c59
-rw-r--r--src/angle/src/compiler/preprocessor/preprocessor.pro6
-rw-r--r--src/angle/src/compiler/translator.pro6
-rw-r--r--src/corelib/global/qnamespace.qdoc1
-rw-r--r--src/corelib/io/qfileinfo.cpp16
-rw-r--r--src/corelib/io/qprocess.cpp23
-rw-r--r--src/corelib/io/qprocess_win.cpp6
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp6
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp2
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp16
-rw-r--r--src/corelib/mimetypes/qmimeprovider_p.h3
-rw-r--r--src/corelib/thread/qmutex.cpp23
-rw-r--r--src/corelib/thread/thread.pri24
-rw-r--r--src/corelib/tools/qchar.cpp10
-rw-r--r--src/corelib/tools/qdatetime.cpp1
-rw-r--r--src/corelib/tools/qelapsedtimer_mac.cpp5
-rw-r--r--src/corelib/tools/qregexp.cpp4
-rw-r--r--src/corelib/tools/qregularexpression.cpp45
-rw-r--r--src/gui/image/qbmphandler.cpp6
-rw-r--r--src/gui/image/qimage.cpp7
-rw-r--r--src/gui/kernel/qguiapplication.cpp3
-rw-r--r--src/gui/kernel/qshortcutmap.cpp12
-rw-r--r--src/gui/kernel/qshortcutmap_p.h4
-rw-r--r--src/gui/opengl/qopenglshaderprogram.cpp17
-rw-r--r--src/gui/painting/qimagescale.cpp5
-rw-r--r--src/gui/painting/qrasterizer.cpp28
-rw-r--r--src/gui/text/qfontengine.cpp212
-rw-r--r--src/gui/text/qfontengine_p.h2
-rw-r--r--src/gui/text/qfontengine_qpf2.cpp10
-rw-r--r--src/gui/text/qtextlayout.cpp81
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp1
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp112
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h1
-rw-r--r--src/network/access/qhttpnetworkreply.cpp2
-rw-r--r--src/network/access/qhttpprotocolhandler.cpp8
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.cpp12
-rw-r--r--src/network/socket/qabstractsocket.cpp7
-rw-r--r--src/network/ssl/qsslsocket.cpp8
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp7
-rw-r--r--src/platformsupport/eglconvenience/qeglplatformcontext.cpp3
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h4
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm31
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm52
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm3
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp16
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h1
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp19
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.h1
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp19
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp6
-rw-r--r--src/printsupport/dialogs/qprintdialog_unix.cpp2
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp3
-rw-r--r--src/widgets/graphicsview/qgraphicsitem.cpp11
-rw-r--r--src/widgets/itemviews/qtreeview.cpp3
-rw-r--r--src/widgets/kernel/qapplication.cpp3
-rw-r--r--src/widgets/kernel/qlayoutitem.cpp2
-rw-r--r--src/widgets/kernel/qwidget.cpp11
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp4
-rw-r--r--src/widgets/styles/qmacstyle_mac.mm3
-rw-r--r--src/widgets/styles/qstyle.cpp19
-rw-r--r--src/widgets/widgets/qcombobox.cpp2
-rw-r--r--src/widgets/widgets/qlineedit_p.cpp27
-rw-r--r--src/widgets/widgets/qlineedit_p.h16
-rw-r--r--src/widgets/widgets/qmenubar.cpp2
-rw-r--r--tests/auto/corelib/io/qprocess/qprocess.pri1
-rw-r--r--tests/auto/corelib/io/qprocess/testProcessHang/main.cpp62
-rw-r--r--tests/auto/corelib/io/qprocess/testProcessHang/testProcessHang.pro4
-rw-r--r--tests/auto/corelib/io/qprocess/tst_qprocess.cpp165
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/qmimedatabase-cache.pro2
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/tst_qmimedatabase-cache.cpp2
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/qmimedatabase-xml.pro2
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/tst_qmimedatabase-xml.cpp2
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc1
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/text-x-objcsrc.xml7
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp87
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h8
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/yast2-metapackage-handler-mimetypes.xml2
-rw-r--r--tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp386
-rw-r--r--tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h1
-rw-r--r--tests/auto/corelib/tools/qtime/tst_qtime.cpp2
-rw-r--r--tests/auto/network/access/qnetworkreply/BLACKLIST8
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp9
-rw-r--r--tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp34
-rw-r--r--tests/auto/other/qaccessibility/tst_qaccessibility.cpp2
-rw-r--r--tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp44
-rw-r--r--tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp11
126 files changed, 2191 insertions, 874 deletions
diff --git a/LICENSE.GPLv3 b/LICENSE.GPLv3
index afa69d94b9..4e49b122ae 100644
--- a/LICENSE.GPLv3
+++ b/LICENSE.GPLv3
@@ -6,7 +6,7 @@
You may use, distribute and copy the Qt GUI Toolkit under the terms of
GNU Lesser General Public License version 3. That license references
the General Public License version 3, that is displayed below. Other
- portions of the Qt Toolkit may be licensed directly other this license.
+ portions of the Qt Toolkit may be licensed directly under this license.
-------------------------------------------------------------------------
diff --git a/LICENSE.LGPLv3 b/LICENSE.LGPLv3
index 2a0988d97b..4d67bac0b4 100644
--- a/LICENSE.LGPLv3
+++ b/LICENSE.LGPLv3
@@ -4,8 +4,8 @@
Contact: http://www.qt.io/licensing/
You may use, distribute and copy the Qt GUI Toolkit under the terms of
- GNU Lesser General Public License version 3, which is displayed
- below. This license makes reference to the version 3 of the GNU General
+ GNU Lesser General Public License version 3, which is displayed below.
+ This license makes reference to the version 3 of the GNU General
Public License, which you can find in the LICENSE.GPLv3 file.
-------------------------------------------------------------------------
diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf
index 72e0b98c9c..849048dad0 100644
--- a/mkspecs/common/msvc-desktop.conf
+++ b/mkspecs/common/msvc-desktop.conf
@@ -140,7 +140,7 @@ greaterThan(MSC_VER, 1899) {
QMAKE_CFLAGS += -Zc:strictStrings
QMAKE_CFLAGS_WARN_ON += -w44456 -w44457 -w44458
QMAKE_CFLAGS_AVX2 = -arch:AVX2
- QMAKE_CXXFLAGS += -Zc:strictStrings
+ QMAKE_CXXFLAGS += -Zc:strictStrings -Zc:throwingNew
QMAKE_CXXFLAGS_WARN_ON += -w44456 -w44457 -w44458 -wd4577
}
diff --git a/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in
index c6419660c1..9e188084ad 100644
--- a/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in
+++ b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in
@@ -9,7 +9,8 @@
<Identity
Name=\"$${WINRT_MANIFEST.identity}\"
Publisher=\"$${WINRT_MANIFEST.publisherid}\"
- Version=\"$${WINRT_MANIFEST.version}\" />
+ Version=\"$${WINRT_MANIFEST.version}\"
+ ProcessorArchitecture=\"$${WINRT_MANIFEST.architecture}\" />
<mp:PhoneIdentity PhoneProductId=\"$${WINRT_MANIFEST.identity}\" PhonePublisherId=\"$${WINRT_MANIFEST.phone_publisher_id}\"/>
@@ -20,7 +21,7 @@
</Properties>
<Dependencies>
- <TargetDeviceFamily Name=\"Windows.Universal\" MinVersion=\"10.0.10069.0\" MaxVersionTested=\"10.0.10069.0\" />
+ <TargetDeviceFamily Name=\"Windows.Universal\" MinVersion=\"10.0.10069.0\" MaxVersionTested=\"10.0.10069.0\" />$${WINRT_MANIFEST.dependencies}
</Dependencies>
<Resources>
diff --git a/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in
index 038184ee4d..91353c608b 100644
--- a/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in
+++ b/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in
@@ -41,6 +41,8 @@
<m2:SplashScreen Image=\"$${WINRT_MANIFEST.logo_620x300}\" />$${WINRT_MANIFEST.rotation_preference}
</m2:VisualElements>
</Application>
- </Applications>$${WINRT_MANIFEST.capabilities}$${WINRT_MANIFEST.dependencies}
+ </Applications>$${WINRT_MANIFEST.capabilities}
+ <Dependencies>$${WINRT_MANIFEST.dependencies}
+ </Dependencies>
</Package>
<!-- Generated by qmake using the $$[QMAKE_XSPEC] mkspec. -->
diff --git a/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in
index 67830bd4ad..19deb94675 100644
--- a/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in
+++ b/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in
@@ -42,6 +42,8 @@
<m3:SplashScreen Image=\"$${WINRT_MANIFEST.logo_480x800}\" />$${WINRT_MANIFEST.rotation_preference}
</m3:VisualElements>
</Application>
- </Applications>$${WINRT_MANIFEST.capabilities}$${WINRT_MANIFEST.dependencies}
+ </Applications>$${WINRT_MANIFEST.capabilities}
+ <Dependencies>$${WINRT_MANIFEST.dependencies}
+ </Dependencies>
</Package>
<!-- Generated by qmake using the $$[QMAKE_XSPEC] mkspec. -->
diff --git a/mkspecs/features/winrt/default_pre.prf b/mkspecs/features/winrt/default_pre.prf
new file mode 100644
index 0000000000..44e3c94b8a
--- /dev/null
+++ b/mkspecs/features/winrt/default_pre.prf
@@ -0,0 +1,12 @@
+*msvc2015 {
+ # Note that the order is important, ucrt(d) has to be first
+ # Otherwise the linker might use malloc from a different library
+ # but free_dbg() from the runtime, causing assert when deleting
+ # items from different heaps
+ CONFIG(debug, debug|release): \
+ QMAKE_LIBS = ucrtd.lib $$QMAKE_LIBS
+ else: \
+ QMAKE_LIBS = ucrt.lib $$QMAKE_LIBS
+}
+
+load(default_pre)
diff --git a/mkspecs/features/winrt/package_manifest.prf b/mkspecs/features/winrt/package_manifest.prf
index 7e5effa438..0f6f185170 100644
--- a/mkspecs/features/winrt/package_manifest.prf
+++ b/mkspecs/features/winrt/package_manifest.prf
@@ -58,9 +58,11 @@
VCLIBS = Microsoft.VCLibs.$$replace(MSVC_VER, \\., ).00
winphone: VCLIBS = $${VCLIBS}.Phone
CONFIG(debug, debug|release): \
- WINRT_MANIFEST.dependencies += $${VCLIBS}.Debug
+ VCLIBS = $${VCLIBS}.Debug
else: \
- WINRT_MANIFEST.dependencies += $$VCLIBS
+ VCLIBS = $${VCLIBS}
+ contains(MSVC_VER, "14.0"): VCLIBS = "$${VCLIBS}\" MinVersion=\"14.0.0.0\" Publisher=\"CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
+ WINRT_MANIFEST.dependencies += $$VCLIBS
}
# Provide default values for required variables
@@ -122,12 +124,11 @@
}
# Dependencies are given as a string list. The CRT dependency is added automatically above.
+ # For MSVC2015 the dependencies are added in conjunction with TargetDeviceFamily
WINRT_MANIFEST.dependencies = $$unique(WINRT_MANIFEST.dependencies)
!isEmpty(WINRT_MANIFEST.dependencies) {
- MANIFEST_DEPENDENCIES += "<Dependencies>"
for(DEPENDENCY, WINRT_MANIFEST.dependencies): \
MANIFEST_DEPENDENCIES += " <PackageDependency Name=\"$$DEPENDENCY\" />"
- MANIFEST_DEPENDENCIES += "</Dependencies>"
WINRT_MANIFEST.dependencies = $$join(MANIFEST_DEPENDENCIES, $$INDENT, $$INDENT)
}
@@ -159,5 +160,13 @@
WINRT_MANIFEST.$${ICON_NAME} = assets/$$basename(ICON_FILE)
}
+ !contains(TEMPLATE, "vc.*") {
+ winrt_manifest_install.files = $$manifest_file.output
+ winrt_manifest_install.path = $$target.path
+ winrt_assets_install.files = $$BUILD_DIR/assets/*
+ winrt_assets_install.path = $$target.path/assets
+ INSTALLS += winrt_manifest_install winrt_assets_install
+ }
+
QMAKE_SUBSTITUTES += manifest_file
}
diff --git a/mkspecs/winrt-arm-msvc2015/qmake.conf b/mkspecs/winrt-arm-msvc2015/qmake.conf
index fcb6d99aa9..44c91a5e80 100644
--- a/mkspecs/winrt-arm-msvc2015/qmake.conf
+++ b/mkspecs/winrt-arm-msvc2015/qmake.conf
@@ -10,19 +10,9 @@ DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_APP ARM __ARM__ __arm__
QMAKE_CFLAGS += -FS
QMAKE_CXXFLAGS += -FS
-QMAKE_LFLAGS += /MACHINE:ARM /NODEFAULTLIB:kernel32.lib
+QMAKE_LFLAGS += /MACHINE:ARM
-QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib
-
-# Note that the order is important, ucrt(d) has to be first
-# Otherwise the linker might use malloc from a different library
-# but free_dbg() from the runtime, causing assert when deleting
-# items from different heaps
-CONFIG(debug, debug|release) {
- QMAKE_LIBS = ucrtd.lib $$QMAKE_LIBS
-} else {
- QMAKE_LIBS = ucrt.lib $$QMAKE_LIBS
-}
+QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib kernel32.lib
VCPROJ_ARCH = ARM
MSVC_VER = 14.0
diff --git a/mkspecs/winrt-x64-msvc2015/qmake.conf b/mkspecs/winrt-x64-msvc2015/qmake.conf
index e8062f5364..a6c5db6f0f 100644
--- a/mkspecs/winrt-x64-msvc2015/qmake.conf
+++ b/mkspecs/winrt-x64-msvc2015/qmake.conf
@@ -10,19 +10,9 @@ DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_APP X64 __X64__ __x64__
QMAKE_CFLAGS += -FS
QMAKE_CXXFLAGS += -FS
-QMAKE_LFLAGS += /MACHINE:X64 /NODEFAULTLIB:kernel32.lib
+QMAKE_LFLAGS += /MACHINE:X64
-QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib
-
-# Note that the order is important, ucrt(d) has to be first
-# Otherwise the linker might use malloc from a different library
-# but free_dbg() from the runtime, causing assert when deleting
-# items from different heaps
-CONFIG(debug, debug|release) {
- QMAKE_LIBS = ucrtd.lib $$QMAKE_LIBS
-} else {
- QMAKE_LIBS = ucrt.lib $$QMAKE_LIBS
-}
+QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib kernel32.lib
VCPROJ_ARCH = x64
MSVC_VER = 14.0
diff --git a/mkspecs/winrt-x86-msvc2015/qmake.conf b/mkspecs/winrt-x86-msvc2015/qmake.conf
index 5b44a97e8d..dfeaf63e2c 100644
--- a/mkspecs/winrt-x86-msvc2015/qmake.conf
+++ b/mkspecs/winrt-x86-msvc2015/qmake.conf
@@ -10,19 +10,9 @@ DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_APP X86 __X86__ __x86__
QMAKE_CFLAGS += -FS
QMAKE_CXXFLAGS += -FS
-QMAKE_LFLAGS += /SAFESEH /MACHINE:X86 /NODEFAULTLIB:kernel32.lib
+QMAKE_LFLAGS += /SAFESEH /MACHINE:X86
-QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib
-
-# Note that the order is important, ucrt(d) has to be first
-# Otherwise the linker might use malloc from a different library
-# but free_dbg() from the runtime, causing assert when deleting
-# items from different heaps
-CONFIG(debug, debug|release) {
- QMAKE_LIBS = ucrtd.lib $$QMAKE_LIBS
-} else {
- QMAKE_LIBS = ucrt.lib $$QMAKE_LIBS
-}
+QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib kernel32.lib
VCPROJ_ARCH = Win32
MSVC_VER = 14.0
diff --git a/qmake/doc/snippets/code/doc_src_qmake-manual.pro b/qmake/doc/snippets/code/doc_src_qmake-manual.pro
index 7609a98111..6fa3ca085d 100644
--- a/qmake/doc/snippets/code/doc_src_qmake-manual.pro
+++ b/qmake/doc/snippets/code/doc_src_qmake-manual.pro
@@ -977,3 +977,9 @@ VERSION_PE_HEADER = 1.2
RC_DEFINES += USE_MY_STUFF
#! [186]
+#! [187]
+win32-g++:contains(QMAKE_HOST.arch, x86_64):{
+ message("Host is 64bit")
+ ...
+}
+#! [187]
diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc
index 14697425c0..d54dc9569a 100644
--- a/qmake/doc/src/qmake-manual.qdoc
+++ b/qmake/doc/src/qmake-manual.qdoc
@@ -1714,6 +1714,25 @@
See \l{Creating Frameworks} for more information about creating frameworks.
+ \target QMAKE_HOST
+ \section1 QMAKE_HOST
+
+ Provides information about the host machine running qmake.
+ For example, you can retrieve the host machine architecture from
+ \c{QMAKE_HOST.arch}.
+
+ \table
+ \header \li Keys \li Values
+ \row \li .arch \li Host architecture
+ \row \li .os \li Host OS
+ \row \li .cpu_count \li Number of available cpus
+ \row \li .name \li Host computer name
+ \row \li .version \li Host OS version number
+ \row \li .version_string \li Host OS version string
+ \endtable
+
+ \snippet code/doc_src_qmake-manual.pro 187
+
\target QMAKE_INCDIR
\section1 QMAKE_INCDIR
diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp
index 81bb0683ac..7ff1d97b16 100644
--- a/qmake/generators/mac/pbuilder_pbx.cpp
+++ b/qmake/generators/mac/pbuilder_pbx.cpp
@@ -1478,7 +1478,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
else
warn_msg(WarnLogic, "Could not resolve Info.plist: '%s'. Check if QMAKE_INFO_PLIST points to a valid file.", plist.toLatin1().constData());
} else {
- plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
+ plist = fileFixify(specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE"), FileFixifyBackwards);
QFile plist_in_file(plist);
if (plist_in_file.open(QIODevice::ReadOnly)) {
QTextStream plist_in(&plist_in_file);
@@ -1505,7 +1505,11 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QTextStream plist_out(&plist_out_file);
plist_out << plist_in_text;
t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";\n";
+ } else {
+ warn_msg(WarnLogic, "Could not write Info.plist: '%s'.", plist_out_file.fileName().toLatin1().constData());
}
+ } else {
+ warn_msg(WarnLogic, "Could not open Info.plist: '%s'.", plist.toLatin1().constData());
}
}
}
diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp
index 6fb2e7d0a1..05a090b23a 100644
--- a/qmake/generators/unix/unixmake2.cpp
+++ b/qmake/generators/unix/unixmake2.cpp
@@ -817,7 +817,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
t << escapeDependencyPath(info_plist_out) << ": \n\t";
info_plist_out = escapeFilePath(info_plist_out);
if (!destdir.isEmpty())
- t << mkdir_p_asstring(destdir, false) << "\n\t";
+ t << mkdir_p_asstring(destdir) << "\n\t";
ProStringList commonSedArgs;
if (!project->values("VERSION").isEmpty()) {
commonSedArgs << "-e \"s,@SHORT_VERSION@," << project->first("VER_MAJ") << "."
@@ -839,6 +839,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
bundleIdentifier.chop(4);
if (bundleIdentifier.endsWith(".framework"))
bundleIdentifier.chop(10);
+ // replace invalid bundle id characters
+ bundleIdentifier.replace('_', '-');
commonSedArgs << "-e \"s,@BUNDLEIDENTIFIER@," << bundleIdentifier << ",g\" ";
if (!isFramework) {
diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp
index cbf7cf26dc..aad6e6e878 100644
--- a/qmake/generators/win32/msbuild_objectmodel.cpp
+++ b/qmake/generators/win32/msbuild_objectmodel.cpp
@@ -643,7 +643,12 @@ void VCXProjectWriter::write(XmlOutput &xml, VCProject &tool)
<< tagValue("DefaultLanguage", "en")
<< tagValue("AppContainerApplication", "true")
<< tagValue("ApplicationType", isWinPhone ? "Windows Phone" : "Windows Store")
- << tagValue("ApplicationTypeRevision", tool.SdkVersion == "10.0" ? "8.2" : tool.SdkVersion);
+ << tagValue("ApplicationTypeRevision", tool.SdkVersion);
+ if (tool.SdkVersion == "10.0") {
+ const QString ucrtVersion = qgetenv("UCRTVERSION");
+ xml << tagValue("WindowsTargetPlatformVersion", ucrtVersion)
+ << tagValue("WindowsTargetPlatformMinVersion", ucrtVersion);
+ }
}
xml << closetag();
diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp
index aff8d9fcad..7646198da1 100644
--- a/qmake/generators/win32/msvc_nmake.cpp
+++ b/qmake/generators/win32/msvc_nmake.cpp
@@ -190,19 +190,24 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t)
incDirs << vcInstallDir + QStringLiteral("include");
incDirs << vcInstallDir + QStringLiteral("atlmfc/include");
- // ### Investigate why VS uses 10056 first
- incDirs << kitDir + QStringLiteral("Include/10.0.10056.0/ucrt");
- incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/ucrt");
- incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/um");
- incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/shared");
- incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/winrt");
+
+ const QString crtVersion = qgetenv("UCRTVersion");
+ if (crtVersion.isEmpty()) {
+ fprintf(stderr, "Failed to access CRT version.\n");
+ return false;
+ }
+ const QString crtInclude = kitDir + QStringLiteral("Include/") + crtVersion;
+ const QString crtLib = kitDir + QStringLiteral("Lib/") + crtVersion;
+ incDirs << crtInclude + QStringLiteral("/ucrt");
+ incDirs << crtInclude + QStringLiteral("/um");
+ incDirs << crtInclude + QStringLiteral("/shared");
+ incDirs << crtInclude + QStringLiteral("/winrt");
libDirs << vcInstallDir + QStringLiteral("lib/store/") + compilerArch;
libDirs << vcInstallDir + QStringLiteral("atlmfc/lib") + compilerArch;
- // ### Investigate why VS uses 10056 first
- libDirs << kitDir + QStringLiteral("lib/10.0.10056.0/ucrt/") + arch;
- libDirs << kitDir + QStringLiteral("lib/10.0.10069.0/ucrt/") + arch;
- libDirs << kitDir + QStringLiteral("lib/10.0.10069.0/um/") + arch;
+
+ libDirs << crtLib + QStringLiteral("/ucrt/") + arch;
+ libDirs << crtLib + QStringLiteral("/um/") + arch;
} else if (isPhone) {
QString sdkDir = vcInstallDir;
if (!QDir(sdkDir).exists()) {
diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp
index b8f9c8135d..ae4fcfd482 100644
--- a/qmake/generators/win32/msvc_vcproj.cpp
+++ b/qmake/generators/win32/msvc_vcproj.cpp
@@ -1307,7 +1307,8 @@ void VcprojGenerator::initDeploymentTool()
}
ProStringList dllPaths = project->values("QMAKE_DLL_PATHS");
// Only deploy Qt libs for shared build
- if (!dllPaths.isEmpty()) {
+ if (!dllPaths.isEmpty() &&
+ !(conf.WinRT && project->first("MSVC_VER").toQString() == "14.0")) {
// FIXME: This code should actually resolve the libraries from all Qt modules.
ProStringList arg = project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE");
for (ProStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) {
diff --git a/src/3rdparty/pcre/patches/0001-Re-fix-X86-Wince-builds.patch b/src/3rdparty/pcre/patches/0001-Re-fix-X86-Wince-builds.patch
deleted file mode 100644
index 8cb3c8c608..0000000000
--- a/src/3rdparty/pcre/patches/0001-Re-fix-X86-Wince-builds.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 121e4d1ad09bdbfeb8a871d4f2c3ffe1acb8e2d6 Mon Sep 17 00:00:00 2001
-From: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-Date: Tue, 30 Jun 2015 09:41:39 +0200
-Subject: [PATCH] Re-fix X86 Wince builds.
-
-eebb8de21ce4845866f15e444a4c78fc2cbb7f3f fixed the PCRE
-build, but was accidentally overwritten by a subsequent
-import of the PCRE tarball.
-
-Now put the same patch also into patches/ so that we don't
-forget it needs to be manually applied.
-
-Change-Id: I93c2ee9c2e2dd1c48d391ce7e16d33208fb2cbbb
----
- src/3rdparty/pcre/sljit/sljitNativeX86_common.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c b/src/3rdparty/pcre/sljit/sljitNativeX86_common.c
-index 22a163f..21b276f 100644
---- a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c
-+++ b/src/3rdparty/pcre/sljit/sljitNativeX86_common.c
-@@ -273,7 +273,9 @@ static sljit_si cpu_has_sse2 = -1;
- #endif
- static sljit_si cpu_has_cmov = -1;
-
--#if defined(_MSC_VER) && _MSC_VER >= 1400
-+#ifdef _WIN32_WCE
-+#include <cmnintrin.h>
-+#elif defined(_MSC_VER) && _MSC_VER >= 1400
- #include <intrin.h>
- #endif
-
---
-1.9.1
-
diff --git a/src/3rdparty/pcre/pcre.h b/src/3rdparty/pcre/pcre.h
index 58ed46a2a3..c2557cf4b1 100644
--- a/src/3rdparty/pcre/pcre.h
+++ b/src/3rdparty/pcre/pcre.h
@@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
/* The current PCRE version information. */
#define PCRE_MAJOR 8
-#define PCRE_MINOR 37
-#define PCRE_PRERELEASE
-#define PCRE_DATE 2015-04-28
+#define PCRE_MINOR 38
+#define PCRE_PRERELEASE -RC1
+#define PCRE_DATE 2015-05-03
/* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE, the appropriate
diff --git a/src/3rdparty/pcre/pcre_compile.c b/src/3rdparty/pcre/pcre_compile.c
index 0efad2645d..866aa8c693 100644
--- a/src/3rdparty/pcre/pcre_compile.c
+++ b/src/3rdparty/pcre/pcre_compile.c
@@ -174,7 +174,7 @@ static const short int escapes[] = {
-ESC_Z, CHAR_LEFT_SQUARE_BRACKET,
CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET,
CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE,
- CHAR_GRAVE_ACCENT, 7,
+ CHAR_GRAVE_ACCENT, ESC_a,
-ESC_b, 0,
-ESC_d, ESC_e,
ESC_f, 0,
@@ -202,9 +202,9 @@ static const short int escapes[] = {
/* 68 */ 0, 0, '|', ',', '%', '_', '>', '?',
/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"',
-/* 80 */ 0, 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0,
+/* 80 */ 0, ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0,
/* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0,
-/* 90 */ 0, 0, -ESC_k, 'l', 0, ESC_n, 0, -ESC_p,
+/* 90 */ 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p,
/* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0,
/* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0,
/* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0,
@@ -219,6 +219,12 @@ static const short int escapes[] = {
/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* F8 */ 0, 0, 0, 0, 0, 0, 0, 0
};
+
+/* We also need a table of characters that may follow \c in an EBCDIC
+environment for characters 0-31. */
+
+static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
+
#endif
@@ -458,7 +464,7 @@ static const char error_texts[] =
"range out of order in character class\0"
"nothing to repeat\0"
/* 10 */
- "operand of unlimited repeat could match the empty string\0" /** DEAD **/
+ "internal error: invalid forward reference offset\0"
"internal error: unexpected repeat\0"
"unrecognized character after (? or (?-\0"
"POSIX named classes are supported only within a class\0"
@@ -527,7 +533,11 @@ static const char error_texts[] =
"different names for subpatterns of the same number are not allowed\0"
"(*MARK) must have an argument\0"
"this version of PCRE is not compiled with Unicode property support\0"
+#ifndef EBCDIC
"\\c must be followed by an ASCII character\0"
+#else
+ "\\c must be followed by a letter or one of [\\]^_?\0"
+#endif
"\\k is not followed by a braced, angle-bracketed, or quoted name\0"
/* 70 */
"internal error: unknown opcode in find_fixedlength()\0"
@@ -1425,7 +1435,16 @@ else
c ^= 0x40;
#else /* EBCDIC coding */
if (c >= CHAR_a && c <= CHAR_z) c += 64;
- c ^= 0xC0;
+ if (c == CHAR_QUESTION_MARK)
+ c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff;
+ else
+ {
+ for (i = 0; i < 32; i++)
+ {
+ if (c == ebcdic_escape_c[i]) break;
+ }
+ if (i < 32) c = i; else *errorcodeptr = ERR68;
+ }
#endif
break;
@@ -1799,7 +1818,7 @@ for (;;)
case OP_ASSERTBACK:
case OP_ASSERTBACK_NOT:
do cc += GET(cc, 1); while (*cc == OP_ALT);
- cc += PRIV(OP_lengths)[*cc];
+ cc += 1 + LINK_SIZE;
break;
/* Skip over things that don't match chars */
@@ -2487,7 +2506,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (c == OP_BRA || c == OP_BRAPOS ||
c == OP_CBRA || c == OP_CBRAPOS ||
c == OP_ONCE || c == OP_ONCE_NC ||
- c == OP_COND)
+ c == OP_COND || c == OP_SCOND)
{
BOOL empty_branch;
if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */
@@ -3886,11 +3905,11 @@ didn't consider this to be a POSIX class. Likewise for [:1234:].
The problem in trying to be exactly like Perl is in the handling of escapes. We
have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX
class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code
-below handles the special case of \], but does not try to do any other escape
-processing. This makes it different from Perl for cases such as [:l\ower:]
-where Perl recognizes it as the POSIX class "lower" but PCRE does not recognize
-"l\ower". This is a lesser evil than not diagnosing bad classes when Perl does,
-I think.
+below handles the special cases \\ and \], but does not try to do any other
+escape processing. This makes it different from Perl for cases such as
+[:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does
+not recognize "l\ower". This is a lesser evil than not diagnosing bad classes
+when Perl does, I think.
A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not.
It seems that the appearance of a nested POSIX class supersedes an apparent
@@ -3917,21 +3936,16 @@ pcre_uchar terminator; /* Don't combine these lines; the Solaris cc */
terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */
for (++ptr; *ptr != CHAR_NULL; ptr++)
{
- if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
+ if (*ptr == CHAR_BACKSLASH &&
+ (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET ||
+ ptr[1] == CHAR_BACKSLASH))
ptr++;
- else if (*ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE;
- else
+ else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) ||
+ *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE;
+ else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
{
- if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
- {
- *endptr = ptr;
- return TRUE;
- }
- if (*ptr == CHAR_LEFT_SQUARE_BRACKET &&
- (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT ||
- ptr[1] == CHAR_EQUALS_SIGN) &&
- check_posix_syntax(ptr, endptr))
- return FALSE;
+ *endptr = ptr;
+ return TRUE;
}
}
return FALSE;
@@ -3985,11 +3999,12 @@ have their offsets adjusted. That one of the jobs of this function. Before it
is called, the partially compiled regex must be temporarily terminated with
OP_END.
-This function has been extended with the possibility of forward references for
-recursions and subroutine calls. It must also check the list of such references
-for the group we are dealing with. If it finds that one of the recursions in
-the current group is on this list, it adjusts the offset in the list, not the
-value in the reference (which is a group number).
+This function has been extended to cope with forward references for recursions
+and subroutine calls. It must check the list of such references for the
+group we are dealing with. If it finds that one of the recursions in the
+current group is on this list, it does not adjust the value in the reference
+(which is a group number). After the group has been scanned, all the offsets in
+the forward reference list for the group are adjusted.
Arguments:
group points to the start of the group
@@ -4005,29 +4020,21 @@ static void
adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd,
size_t save_hwm_offset)
{
+int offset;
+pcre_uchar *hc;
pcre_uchar *ptr = group;
while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL)
{
- int offset;
- pcre_uchar *hc;
-
- /* See if this recursion is on the forward reference list. If so, adjust the
- reference. */
-
for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
hc += LINK_SIZE)
{
offset = (int)GET(hc, 0);
- if (cd->start_code + offset == ptr + 1)
- {
- PUT(hc, 0, offset + adjust);
- break;
- }
+ if (cd->start_code + offset == ptr + 1) break;
}
- /* Otherwise, adjust the recursion offset if it's after the start of this
- group. */
+ /* If we have not found this recursion on the forward reference list, adjust
+ the recursion's offset if it's after the start of this group. */
if (hc >= cd->hwm)
{
@@ -4037,6 +4044,15 @@ while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL)
ptr += 1 + LINK_SIZE;
}
+
+/* Now adjust all forward reference offsets for the group. */
+
+for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
+ hc += LINK_SIZE)
+ {
+ offset = (int)GET(hc, 0);
+ PUT(hc, 0, offset + adjust);
+ }
}
@@ -4465,7 +4481,7 @@ const pcre_uchar *tempptr;
const pcre_uchar *nestptr = NULL;
pcre_uchar *previous = NULL;
pcre_uchar *previous_callout = NULL;
-size_t save_hwm_offset = 0;
+size_t item_hwm_offset = 0;
pcre_uint8 classbits[32];
/* We can fish out the UTF-8 setting once and for all into a BOOL, but we
@@ -4767,6 +4783,7 @@ for (;; ptr++)
zeroreqchar = reqchar;
zeroreqcharflags = reqcharflags;
previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY;
break;
@@ -4818,6 +4835,7 @@ for (;; ptr++)
/* Handle a real character class. */
previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
/* PCRE supports POSIX class stuff inside a class. Perl gives an error if
they are encountered at the top level, so we'll do that too. */
@@ -5195,9 +5213,9 @@ for (;; ptr++)
cd, PRIV(vspace_list));
continue;
-#ifdef SUPPORT_UCP
case ESC_p:
case ESC_P:
+#ifdef SUPPORT_UCP
{
BOOL negated;
unsigned int ptype = 0, pdata = 0;
@@ -5211,6 +5229,9 @@ for (;; ptr++)
class_has_8bitchar--; /* Undo! */
continue;
}
+#else
+ *errorcodeptr = ERR45;
+ goto FAILED;
#endif
/* Unrecognized escapes are faulted if PCRE is running in its
strict mode. By default, for compatibility with Perl, they are
@@ -5930,7 +5951,7 @@ for (;; ptr++)
{
register int i;
int len = (int)(code - previous);
- size_t base_hwm_offset = save_hwm_offset;
+ size_t base_hwm_offset = item_hwm_offset;
pcre_uchar *bralink = NULL;
pcre_uchar *brazeroptr = NULL;
@@ -5985,7 +6006,7 @@ for (;; ptr++)
if (repeat_max <= 1) /* Covers 0, 1, and unlimited */
{
*code = OP_END;
- adjust_recurse(previous, 1, utf, cd, save_hwm_offset);
+ adjust_recurse(previous, 1, utf, cd, item_hwm_offset);
memmove(previous + 1, previous, IN_UCHARS(len));
code++;
if (repeat_max == 0)
@@ -6009,7 +6030,7 @@ for (;; ptr++)
{
int offset;
*code = OP_END;
- adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm_offset);
+ adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, item_hwm_offset);
memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
code += 2 + LINK_SIZE;
*previous++ = OP_BRAZERO + repeat_type;
@@ -6254,6 +6275,12 @@ for (;; ptr++)
while (*scode == OP_ALT);
}
+ /* A conditional group with only one branch has an implicit empty
+ alternative branch. */
+
+ if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT)
+ *bracode = OP_SCOND;
+
/* Handle possessive quantifiers. */
if (possessive_quantifier)
@@ -6267,11 +6294,11 @@ for (;; ptr++)
{
int nlen = (int)(code - bracode);
*code = OP_END;
- adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+ adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen));
code += 1 + LINK_SIZE;
nlen += 1 + LINK_SIZE;
- *bracode = OP_BRAPOS;
+ *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS;
*code++ = OP_KETRPOS;
PUTINC(code, 0, nlen);
PUT(bracode, 1, nlen);
@@ -6401,7 +6428,7 @@ for (;; ptr++)
else
{
*code = OP_END;
- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
code += 1 + LINK_SIZE;
len += 1 + LINK_SIZE;
@@ -6450,7 +6477,7 @@ for (;; ptr++)
default:
*code = OP_END;
- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
code += 1 + LINK_SIZE;
len += 1 + LINK_SIZE;
@@ -6623,7 +6650,7 @@ for (;; ptr++)
newoptions = options;
skipbytes = 0;
bravalue = OP_CBRA;
- save_hwm_offset = cd->hwm - cd->start_workspace;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
reset_bracount = FALSE;
/* Deal with the extended parentheses; all are introduced by '?', and the
@@ -6641,6 +6668,7 @@ for (;; ptr++)
/* ------------------------------------------------------------ */
case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */
reset_bracount = TRUE;
+ cd->dupgroups = TRUE; /* Record (?| encountered */
/* Fall through */
/* ------------------------------------------------------------ */
@@ -6741,6 +6769,12 @@ for (;; ptr++)
{
while (IS_DIGIT(*ptr))
{
+ if (recno > INT_MAX / 10 - 1) /* Integer overflow */
+ {
+ while (IS_DIGIT(*ptr)) ptr++;
+ *errorcodeptr = ERR61;
+ goto FAILED;
+ }
recno = recno * 10 + (int)(*ptr - CHAR_0);
ptr++;
}
@@ -6769,7 +6803,7 @@ for (;; ptr++)
ptr++;
}
namelen = (int)(ptr - name);
- if (lengthptr != NULL) *lengthptr += IMM2_SIZE;
+ if (lengthptr != NULL) skipbytes += IMM2_SIZE;
}
/* Check the terminator */
@@ -6875,6 +6909,11 @@ for (;; ptr++)
*errorcodeptr = ERR15;
goto FAILED;
}
+ if (recno > INT_MAX / 10 - 1) /* Integer overflow */
+ {
+ *errorcodeptr = ERR61;
+ goto FAILED;
+ }
recno = recno * 10 + name[i] - CHAR_0;
}
if (recno == 0) recno = RREF_ANY;
@@ -7151,7 +7190,8 @@ for (;; ptr++)
if (lengthptr != NULL)
{
named_group *ng;
-
+ recno = 0;
+
if (namelen == 0)
{
*errorcodeptr = ERR62;
@@ -7168,20 +7208,6 @@ for (;; ptr++)
goto FAILED;
}
- /* The name table does not exist in the first pass; instead we must
- scan the list of names encountered so far in order to get the
- number. If the name is not found, set the value to 0 for a forward
- reference. */
-
- ng = cd->named_groups;
- for (i = 0; i < cd->names_found; i++, ng++)
- {
- if (namelen == ng->length &&
- STRNCMP_UC_UC(name, ng->name, namelen) == 0)
- break;
- }
- recno = (i < cd->names_found)? ng->number : 0;
-
/* Count named back references. */
if (!is_recurse) cd->namedrefcount++;
@@ -7191,6 +7217,56 @@ for (;; ptr++)
16-bit data item. */
*lengthptr += IMM2_SIZE;
+
+ /* If this is a forward reference and we are within a (?|...) group,
+ the reference may end up as the number of a group which we are
+ currently inside, that is, it could be a recursive reference. In the
+ real compile this will be picked up and the reference wrapped with
+ OP_ONCE to make it atomic, so we must space in case this occurs. */
+
+ /* In fact, this can happen for a non-forward reference because
+ another group with the same number might be created later. This
+ issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance
+ only mode, we finesse the bug by allowing more memory always. */
+
+ *lengthptr += 2 + 2*LINK_SIZE;
+
+ /* It is even worse than that. The current reference may be to an
+ existing named group with a different number (so apparently not
+ recursive) but which later on is also attached to a group with the
+ current number. This can only happen if $(| has been previous
+ encountered. In that case, we allow yet more memory, just in case.
+ (Again, this is fixed "properly" in PCRE2. */
+
+ if (cd->dupgroups) *lengthptr += 4 + 4*LINK_SIZE;
+
+ /* Otherwise, check for recursion here. The name table does not exist
+ in the first pass; instead we must scan the list of names encountered
+ so far in order to get the number. If the name is not found, leave
+ the value of recno as 0 for a forward reference. */
+
+ else
+ {
+ ng = cd->named_groups;
+ for (i = 0; i < cd->names_found; i++, ng++)
+ {
+ if (namelen == ng->length &&
+ STRNCMP_UC_UC(name, ng->name, namelen) == 0)
+ {
+ open_capitem *oc;
+ recno = ng->number;
+ if (is_recurse) break;
+ for (oc = cd->open_caps; oc != NULL; oc = oc->next)
+ {
+ if (oc->number == recno)
+ {
+ oc->flag = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
}
/* In the real compile, search the name table. We check the name
@@ -7237,8 +7313,6 @@ for (;; ptr++)
for (i++; i < cd->names_found; i++)
{
if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break;
-
-
count++;
cslot += cd->name_entry_size;
}
@@ -7247,6 +7321,7 @@ for (;; ptr++)
{
if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
PUT2INC(code, 0, index);
PUT2INC(code, 0, count);
@@ -7284,9 +7359,14 @@ for (;; ptr++)
/* ------------------------------------------------------------ */
- case CHAR_R: /* Recursion */
- ptr++; /* Same as (?0) */
- /* Fall through */
+ case CHAR_R: /* Recursion, same as (?0) */
+ recno = 0;
+ if (*(++ptr) != CHAR_RIGHT_PARENTHESIS)
+ {
+ *errorcodeptr = ERR29;
+ goto FAILED;
+ }
+ goto HANDLE_RECURSION;
/* ------------------------------------------------------------ */
@@ -7323,7 +7403,15 @@ for (;; ptr++)
recno = 0;
while(IS_DIGIT(*ptr))
+ {
+ if (recno > INT_MAX / 10 - 1) /* Integer overflow */
+ {
+ while (IS_DIGIT(*ptr)) ptr++;
+ *errorcodeptr = ERR61;
+ goto FAILED;
+ }
recno = recno * 10 + *ptr++ - CHAR_0;
+ }
if (*ptr != (pcre_uchar)terminator)
{
@@ -7360,6 +7448,7 @@ for (;; ptr++)
HANDLE_RECURSION:
previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
called = cd->start_code;
/* When we are actually compiling, find the bracket that is being
@@ -7561,7 +7650,11 @@ for (;; ptr++)
previous = NULL;
cd->iscondassert = FALSE;
}
- else previous = code;
+ else
+ {
+ previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
+ }
*code = bravalue;
tempcode = code;
@@ -7809,7 +7902,7 @@ for (;; ptr++)
const pcre_uchar *p;
pcre_uint32 cf;
- save_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */
+ item_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */
terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
@@ -7838,7 +7931,7 @@ for (;; ptr++)
if (*p != (pcre_uchar)terminator)
{
*errorcodeptr = ERR57;
- break;
+ goto FAILED;
}
ptr++;
goto HANDLE_NUMERICAL_RECURSION;
@@ -7853,7 +7946,7 @@ for (;; ptr++)
ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET))
{
*errorcodeptr = ERR69;
- break;
+ goto FAILED;
}
is_recurse = FALSE;
terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
@@ -7877,6 +7970,7 @@ for (;; ptr++)
HANDLE_REFERENCE:
if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;
PUT2INC(code, 0, recno);
cd->backref_map |= (recno < 32)? (1 << recno) : 1;
@@ -7906,6 +8000,7 @@ for (;; ptr++)
if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
goto FAILED;
previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
*code++ = ptype;
*code++ = pdata;
@@ -7946,6 +8041,7 @@ for (;; ptr++)
{
previous = (escape > ESC_b && escape < ESC_Z)? code : NULL;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape;
}
}
@@ -7989,6 +8085,7 @@ for (;; ptr++)
ONE_CHAR:
previous = code;
+ item_hwm_offset = cd->hwm - cd->start_workspace;
/* For caseless UTF-8 mode when UCP support is available, check whether
this character has more than one other case. If so, generate a special
@@ -9164,6 +9261,7 @@ cd->names_found = 0;
cd->name_entry_size = 0;
cd->name_table = NULL;
cd->dupnames = FALSE;
+cd->dupgroups = FALSE;
cd->namedrefcount = 0;
cd->start_code = cworkspace;
cd->hwm = cworkspace;
@@ -9198,7 +9296,7 @@ if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;
DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,
(int)(cd->hwm - cworkspace)));
-
+
if (length > MAX_PATTERN_SIZE)
{
errorcode = ERR20;
@@ -9336,6 +9434,16 @@ if (cd->hwm > cd->start_workspace)
int offset, recno;
cd->hwm -= LINK_SIZE;
offset = GET(cd->hwm, 0);
+
+ /* Check that the hwm handling hasn't gone wrong. This whole area is
+ rewritten in PCRE2 because there are some obscure cases. */
+
+ if (offset == 0 || codestart[offset-1] != OP_RECURSE)
+ {
+ errorcode = ERR10;
+ break;
+ }
+
recno = GET(codestart, offset);
if (recno != prev_recno)
{
@@ -9366,7 +9474,7 @@ used in this code because at least one compiler gives a warning about loss of
"const" attribute if the cast (pcre_uchar *)codestart is used directly in the
function call. */
-if ((options & PCRE_NO_AUTO_POSSESS) == 0)
+if (errorcode == 0 && (options & PCRE_NO_AUTO_POSSESS) == 0)
{
pcre_uchar *temp = (pcre_uchar *)codestart;
auto_possessify(temp, utf, cd);
@@ -9380,7 +9488,7 @@ OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The
exceptional ones forgo this. We scan the pattern to check that they are fixed
length, and set their lengths. */
-if (cd->check_lookbehind)
+if (errorcode == 0 && cd->check_lookbehind)
{
pcre_uchar *cc = (pcre_uchar *)codestart;
@@ -9593,4 +9701,3 @@ return (pcre32 *)re;
}
/* End of pcre_compile.c */
-
diff --git a/src/3rdparty/pcre/pcre_exec.c b/src/3rdparty/pcre/pcre_exec.c
index c021fe1a4c..24b23ca286 100644
--- a/src/3rdparty/pcre/pcre_exec.c
+++ b/src/3rdparty/pcre/pcre_exec.c
@@ -6685,7 +6685,8 @@ if (md->offset_vector != NULL)
register int *iend = iptr - re->top_bracket;
if (iend < md->offset_vector + 2) iend = md->offset_vector + 2;
while (--iptr >= iend) *iptr = -1;
- md->offset_vector[0] = md->offset_vector[1] = -1;
+ if (offsetcount > 0) md->offset_vector[0] = -1;
+ if (offsetcount > 1) md->offset_vector[1] = -1;
}
/* Set up the first character to match, if available. The first_char value is
diff --git a/src/3rdparty/pcre/pcre_internal.h b/src/3rdparty/pcre/pcre_internal.h
index dd0ac7fc91..544d9c0709 100644
--- a/src/3rdparty/pcre/pcre_internal.h
+++ b/src/3rdparty/pcre/pcre_internal.h
@@ -984,7 +984,7 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */
#ifndef EBCDIC
#define HSPACE_LIST \
- CHAR_HT, CHAR_SPACE, 0xa0, \
+ CHAR_HT, CHAR_SPACE, CHAR_NBSP, \
0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \
0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \
NOTACHAR
@@ -1010,7 +1010,7 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */
#define HSPACE_BYTE_CASES \
case CHAR_HT: \
case CHAR_SPACE: \
- case 0xa0 /* NBSP */
+ case CHAR_NBSP
#define HSPACE_CASES \
HSPACE_BYTE_CASES: \
@@ -1037,11 +1037,12 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */
/* ------ EBCDIC environments ------ */
#else
-#define HSPACE_LIST CHAR_HT, CHAR_SPACE
+#define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR
#define HSPACE_BYTE_CASES \
case CHAR_HT: \
- case CHAR_SPACE
+ case CHAR_SPACE: \
+ case CHAR_NBSP
#define HSPACE_CASES HSPACE_BYTE_CASES
@@ -1215,6 +1216,7 @@ same code point. */
#define CHAR_ESC '\047'
#define CHAR_DEL '\007'
+#define CHAR_NBSP '\x41'
#define STR_ESC "\047"
#define STR_DEL "\007"
@@ -1229,6 +1231,7 @@ a positive value. */
#define CHAR_NEL ((unsigned char)'\x85')
#define CHAR_ESC '\033'
#define CHAR_DEL '\177'
+#define CHAR_NBSP ((unsigned char)'\xa0')
#define STR_LF "\n"
#define STR_NL STR_LF
@@ -1606,6 +1609,7 @@ only. */
#define CHAR_VERTICAL_LINE '\174'
#define CHAR_RIGHT_CURLY_BRACKET '\175'
#define CHAR_TILDE '\176'
+#define CHAR_NBSP ((unsigned char)'\xa0')
#define STR_HT "\011"
#define STR_VT "\013"
@@ -1762,6 +1766,10 @@ only. */
/* Escape items that are just an encoding of a particular data value. */
+#ifndef ESC_a
+#define ESC_a CHAR_BEL
+#endif
+
#ifndef ESC_e
#define ESC_e CHAR_ESC
#endif
@@ -2446,6 +2454,7 @@ typedef struct compile_data {
BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
BOOL check_lookbehind; /* Lookbehinds need later checking */
BOOL dupnames; /* Duplicate names exist */
+ BOOL dupgroups; /* Duplicate groups exist: (?| found */
BOOL iscondassert; /* Next assert is a condition */
int nltype; /* Newline type */
int nllen; /* Newline string length */
diff --git a/src/3rdparty/pcre/pcre_jit_compile.c b/src/3rdparty/pcre/pcre_jit_compile.c
index debdf6ef45..868d1d91bf 100644
--- a/src/3rdparty/pcre/pcre_jit_compile.c
+++ b/src/3rdparty/pcre/pcre_jit_compile.c
@@ -1064,6 +1064,7 @@ pcre_uchar *alternative;
pcre_uchar *end = NULL;
int private_data_ptr = *private_data_start;
int space, size, bracketlen;
+BOOL repeat_check = TRUE;
while (cc < ccend)
{
@@ -1071,9 +1072,10 @@ while (cc < ccend)
size = 0;
bracketlen = 0;
if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE)
- return;
+ break;
- if (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)
+ if (repeat_check && (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND))
+ {
if (detect_repeat(common, cc))
{
/* These brackets are converted to repeats, so no global
@@ -1081,6 +1083,8 @@ while (cc < ccend)
if (cc >= end)
end = bracketend(cc);
}
+ }
+ repeat_check = TRUE;
switch(*cc)
{
@@ -1136,6 +1140,13 @@ while (cc < ccend)
bracketlen = 1 + LINK_SIZE + IMM2_SIZE;
break;
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ case OP_BRAPOSZERO:
+ repeat_check = FALSE;
+ size = 1;
+ break;
+
CASE_ITERATOR_PRIVATE_DATA_1
space = 1;
size = -2;
@@ -1162,12 +1173,17 @@ while (cc < ccend)
size = 1;
break;
- CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+ case OP_TYPEUPTO:
if (cc[1 + IMM2_SIZE] != OP_ANYNL && cc[1 + IMM2_SIZE] != OP_EXTUNI)
space = 2;
size = 1 + IMM2_SIZE;
break;
+ case OP_TYPEMINUPTO:
+ space = 2;
+ size = 1 + IMM2_SIZE;
+ break;
+
case OP_CLASS:
case OP_NCLASS:
size += 1 + 32 / sizeof(pcre_uchar);
@@ -1316,6 +1332,13 @@ while (cc < ccend)
cc += 1 + LINK_SIZE + IMM2_SIZE;
break;
+ case OP_THEN:
+ stack_restore = TRUE;
+ if (common->control_head_ptr != 0)
+ *needs_control_head = TRUE;
+ cc ++;
+ break;
+
default:
stack_restore = TRUE;
/* Fall through. */
@@ -2220,6 +2243,7 @@ while (current != NULL)
SLJIT_ASSERT_STOP();
break;
}
+ SLJIT_ASSERT(current > (sljit_sw*)current[-1]);
current = (sljit_sw*)current[-1];
}
return -1;
@@ -3209,7 +3233,7 @@ bytes[len] = byte;
bytes[0] = len;
}
-static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uint32 *chars, pcre_uint8 *bytes, int max_chars)
+static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uint32 *chars, pcre_uint8 *bytes, int max_chars, pcre_uint32 *rec_count)
{
/* Recursive function, which scans prefix literals. */
BOOL last, any, caseless;
@@ -3227,9 +3251,14 @@ pcre_uchar othercase[1];
repeat = 1;
while (TRUE)
{
+ if (*rec_count == 0)
+ return 0;
+ (*rec_count)--;
+
last = TRUE;
any = FALSE;
caseless = FALSE;
+
switch (*cc)
{
case OP_CHARI:
@@ -3291,7 +3320,7 @@ while (TRUE)
#ifdef SUPPORT_UTF
if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
#endif
- max_chars = scan_prefix(common, cc + len, chars, bytes, max_chars);
+ max_chars = scan_prefix(common, cc + len, chars, bytes, max_chars, rec_count);
if (max_chars == 0)
return consumed;
last = FALSE;
@@ -3314,7 +3343,7 @@ while (TRUE)
alternative = cc + GET(cc, 1);
while (*alternative == OP_ALT)
{
- max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, bytes, max_chars);
+ max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, bytes, max_chars, rec_count);
if (max_chars == 0)
return consumed;
alternative += GET(alternative, 1);
@@ -3556,6 +3585,7 @@ int i, max, from;
int range_right = -1, range_len = 3 - 1;
sljit_ub *update_table = NULL;
BOOL in_range;
+pcre_uint32 rec_count;
for (i = 0; i < MAX_N_CHARS; i++)
{
@@ -3564,7 +3594,8 @@ for (i = 0; i < MAX_N_CHARS; i++)
bytes[i * MAX_N_BYTES] = 0;
}
-max = scan_prefix(common, common->start, chars, bytes, MAX_N_CHARS);
+rec_count = 10000;
+max = scan_prefix(common, common->start, chars, bytes, MAX_N_CHARS, &rec_count);
if (max <= 1)
return FALSE;
@@ -7665,6 +7696,10 @@ while (*cc != OP_KETRPOS)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
}
+ /* Even if the match is empty, we need to reset the control head. */
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack));
+
if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0));
@@ -7692,6 +7727,10 @@ while (*cc != OP_KETRPOS)
OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw), STR_PTR, 0);
}
+ /* Even if the match is empty, we need to reset the control head. */
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack));
+
if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0));
@@ -7704,9 +7743,6 @@ while (*cc != OP_KETRPOS)
}
}
- if (needs_control_head)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack));
-
JUMPTO(SLJIT_JUMP, loop);
flush_stubs(common);
@@ -9648,6 +9684,7 @@ set_jumps(common->currententry->calls, common->currententry->entry);
sljit_emit_fast_enter(compiler, TMP2, 0);
allocate_stack(common, private_data_size + framesize + alternativesize);
+count_match(common);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(private_data_size + framesize + alternativesize - 1), TMP2, 0);
copy_private_data(common, ccbegin, ccend, TRUE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head);
if (needs_control_head)
@@ -9992,6 +10029,7 @@ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
OP1(SLJIT_MOV_UI, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match));
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, base));
OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit));
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0);
if (mode == JIT_PARTIAL_SOFT_COMPILE)
diff --git a/src/3rdparty/pcre/pcre_study.c b/src/3rdparty/pcre/pcre_study.c
index 998fe2325e..932e9a7c4c 100644
--- a/src/3rdparty/pcre/pcre_study.c
+++ b/src/3rdparty/pcre/pcre_study.c
@@ -71,6 +71,7 @@ Arguments:
startcode pointer to start of the whole pattern's code
options the compiling options
recurses chain of recurse_check to catch mutual recursion
+ countptr pointer to call count (to catch over complexity)
Returns: the minimum length
-1 if \C in UTF-8 mode or (*ACCEPT) was encountered
@@ -80,7 +81,8 @@ Returns: the minimum length
static int
find_minlength(const REAL_PCRE *re, const pcre_uchar *code,
- const pcre_uchar *startcode, int options, recurse_check *recurses)
+ const pcre_uchar *startcode, int options, recurse_check *recurses,
+ int *countptr)
{
int length = -1;
/* PCRE_UTF16 has the same value as PCRE_UTF8. */
@@ -90,6 +92,8 @@ recurse_check this_recurse;
register int branchlength = 0;
register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE;
+if ((*countptr)++ > 1000) return -1; /* too complex */
+
if (*code == OP_CBRA || *code == OP_SCBRA ||
*code == OP_CBRAPOS || *code == OP_SCBRAPOS) cc += IMM2_SIZE;
@@ -131,7 +135,7 @@ for (;;)
case OP_SBRAPOS:
case OP_ONCE:
case OP_ONCE_NC:
- d = find_minlength(re, cc, startcode, options, recurses);
+ d = find_minlength(re, cc, startcode, options, recurses, countptr);
if (d < 0) return d;
branchlength += d;
do cc += GET(cc, 1); while (*cc == OP_ALT);
@@ -415,7 +419,8 @@ for (;;)
int dd;
this_recurse.prev = recurses;
this_recurse.group = cs;
- dd = find_minlength(re, cs, startcode, options, &this_recurse);
+ dd = find_minlength(re, cs, startcode, options, &this_recurse,
+ countptr);
if (dd < d) d = dd;
}
}
@@ -451,7 +456,8 @@ for (;;)
{
this_recurse.prev = recurses;
this_recurse.group = cs;
- d = find_minlength(re, cs, startcode, options, &this_recurse);
+ d = find_minlength(re, cs, startcode, options, &this_recurse,
+ countptr);
}
}
}
@@ -514,7 +520,7 @@ for (;;)
this_recurse.prev = recurses;
this_recurse.group = cs;
branchlength += find_minlength(re, cs, startcode, options,
- &this_recurse);
+ &this_recurse, countptr);
}
}
cc += 1 + LINK_SIZE;
@@ -1453,6 +1459,7 @@ pcre32_study(const pcre32 *external_re, int options, const char **errorptr)
#endif
{
int min;
+int count = 0;
BOOL bits_set = FALSE;
pcre_uint8 start_bits[32];
PUBL(extra) *extra = NULL;
@@ -1539,7 +1546,7 @@ if ((re->options & PCRE_ANCHORED) == 0 &&
/* Find the minimum length of subject string. */
-switch(min = find_minlength(re, code, code, re->options, NULL))
+switch(min = find_minlength(re, code, code, re->options, NULL, &count))
{
case -2: *errorptr = "internal error: missing capturing bracket"; return NULL;
case -3: *errorptr = "internal error: opcode not recognized"; return NULL;
diff --git a/src/3rdparty/pcre/sljit/sljitConfig.h b/src/3rdparty/pcre/sljit/sljitConfig.h
index 10364c3b60..1c8a521aa8 100644
--- a/src/3rdparty/pcre/sljit/sljitConfig.h
+++ b/src/3rdparty/pcre/sljit/sljitConfig.h
@@ -96,6 +96,15 @@
#define SLJIT_EXECUTABLE_ALLOCATOR 1
#endif
+/* Force cdecl calling convention even if a better calling
+ convention (e.g. fastcall) is supported by the C compiler.
+ If this option is enabled, C functions without
+ SLJIT_CALL can also be called from JIT code. */
+#ifndef SLJIT_USE_CDECL_CALLING_CONVENTION
+/* Disabled by default */
+#define SLJIT_USE_CDECL_CALLING_CONVENTION 0
+#endif
+
/* Return with error when an invalid argument is passed. */
#ifndef SLJIT_ARGUMENT_CHECKS
/* Disabled by default */
diff --git a/src/3rdparty/pcre/sljit/sljitConfigInternal.h b/src/3rdparty/pcre/sljit/sljitConfigInternal.h
index 3284012f19..16e3547c93 100644
--- a/src/3rdparty/pcre/sljit/sljitConfigInternal.h
+++ b/src/3rdparty/pcre/sljit/sljitConfigInternal.h
@@ -468,7 +468,12 @@ typedef double sljit_d;
#ifndef SLJIT_CALL
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+#if (defined SLJIT_USE_CDECL_CALLING_CONVENTION && SLJIT_USE_CDECL_CALLING_CONVENTION)
+
+/* Force cdecl. */
+#define SLJIT_CALL
+
+#elif (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
#if defined(__GNUC__) && !defined(__APPLE__)
@@ -608,6 +613,12 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
#define SLJIT_LOCALS_OFFSET_BASE ((23 + 1) * sizeof(sljit_sw))
#endif
+#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
+
+#define SLJIT_NUMBER_OF_REGISTERS 10
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 5
+#define SLJIT_LOCALS_OFFSET_BASE 0
+
#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
#define SLJIT_NUMBER_OF_REGISTERS 0
diff --git a/src/3rdparty/pcre/sljit/sljitLir.c b/src/3rdparty/pcre/sljit/sljitLir.c
index 5039a7e04e..0f1b1c9cce 100644
--- a/src/3rdparty/pcre/sljit/sljitLir.c
+++ b/src/3rdparty/pcre/sljit/sljitLir.c
@@ -845,8 +845,8 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *comp
}
static SLJIT_CONST char* op0_names[] = {
- (char*)"breakpoint", (char*)"nop",
- (char*)"lumul", (char*)"lsmul", (char*)"ludiv", (char*)"lsdiv",
+ (char*)"breakpoint", (char*)"nop", (char*)"lumul", (char*)"lsmul",
+ (char*)"udivmod", (char*)"sdivmod", (char*)"udivi", (char*)"sdivi"
};
static SLJIT_CONST char* op1_names[] = {
@@ -1036,7 +1036,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op0(struct sljit_compiler
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT((op >= SLJIT_BREAKPOINT && op <= SLJIT_LSMUL)
- || ((op & ~SLJIT_INT_OP) >= SLJIT_LUDIV && (op & ~SLJIT_INT_OP) <= SLJIT_LSDIV));
+ || ((op & ~SLJIT_INT_OP) >= SLJIT_UDIVMOD && (op & ~SLJIT_INT_OP) <= SLJIT_SDIVI));
CHECK_ARGUMENT(op < SLJIT_LUMUL || compiler->scratches >= 2);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@@ -1447,6 +1447,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_com
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset)
{
+ SLJIT_UNUSED_ARG(offset);
+
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
FUNCTION_CHECK_DST(dst, dstw);
#endif
@@ -1462,6 +1464,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_co
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
{
+ SLJIT_UNUSED_ARG(init_value);
+
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
FUNCTION_CHECK_DST(dst, dstw);
#endif
diff --git a/src/3rdparty/pcre/sljit/sljitLir.h b/src/3rdparty/pcre/sljit/sljitLir.h
index 24c0f60399..f0969dac2e 100644
--- a/src/3rdparty/pcre/sljit/sljitLir.h
+++ b/src/3rdparty/pcre/sljit/sljitLir.h
@@ -687,7 +687,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *
#define SLJIT_OP0_BASE 0
/* Flags: - (never set any flags)
- Note: breakpoint instruction is not supported by all architectures (namely ppc)
+ Note: breakpoint instruction is not supported by all architectures (e.g. ppc)
It falls back to SLJIT_NOP in those cases. */
#define SLJIT_BREAKPOINT (SLJIT_OP0_BASE + 0)
/* Flags: - (never set any flags)
@@ -696,24 +696,42 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *
#define SLJIT_NOP (SLJIT_OP0_BASE + 1)
/* Flags: - (may destroy flags)
Unsigned multiplication of SLJIT_R0 and SLJIT_R1.
- Result goes to SLJIT_R1:SLJIT_R0 (high:low) word */
+ Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */
#define SLJIT_LUMUL (SLJIT_OP0_BASE + 2)
/* Flags: - (may destroy flags)
Signed multiplication of SLJIT_R0 and SLJIT_R1.
- Result goes to SLJIT_R1:SLJIT_R0 (high:low) word */
+ Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */
#define SLJIT_LSMUL (SLJIT_OP0_BASE + 3)
/* Flags: I - (may destroy flags)
Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1.
- The result is placed in SLJIT_R0 and the remainder goes to SLJIT_R1.
- Note: if SLJIT_R1 contains 0, the behaviour is undefined. */
-#define SLJIT_LUDIV (SLJIT_OP0_BASE + 4)
-#define SLJIT_ILUDIV (SLJIT_LUDIV | SLJIT_INT_OP)
+ The result is placed into SLJIT_R0 and the remainder into SLJIT_R1.
+ Note: if SLJIT_R1 is 0, the behaviour is undefined. */
+#define SLJIT_UDIVMOD (SLJIT_OP0_BASE + 4)
+#define SLJIT_IUDIVMOD (SLJIT_UDIVMOD | SLJIT_INT_OP)
/* Flags: I - (may destroy flags)
Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1.
- The result is placed in SLJIT_R0 and the remainder goes to SLJIT_R1.
- Note: if SLJIT_R1 contains 0, the behaviour is undefined. */
-#define SLJIT_LSDIV (SLJIT_OP0_BASE + 5)
-#define SLJIT_ILSDIV (SLJIT_LSDIV | SLJIT_INT_OP)
+ The result is placed into SLJIT_R0 and the remainder into SLJIT_R1.
+ Note: if SLJIT_R1 is 0, the behaviour is undefined.
+ Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00),
+ the behaviour is undefined. */
+#define SLJIT_SDIVMOD (SLJIT_OP0_BASE + 5)
+#define SLJIT_ISDIVMOD (SLJIT_SDIVMOD | SLJIT_INT_OP)
+/* Flags: I - (may destroy flags)
+ Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1.
+ The result is placed into SLJIT_R0. SLJIT_R1 preserves its value.
+ Note: if SLJIT_R1 is 0, the behaviour is undefined.
+ Note: SLJIT_SDIV is single precision divide. */
+#define SLJIT_UDIVI (SLJIT_OP0_BASE + 6)
+#define SLJIT_IUDIVI (SLJIT_UDIVI | SLJIT_INT_OP)
+/* Flags: I - (may destroy flags)
+ Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1.
+ The result is placed into SLJIT_R0. SLJIT_R1 preserves its value.
+ Note: if SLJIT_R1 is 0, the behaviour is undefined.
+ Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00),
+ the behaviour is undefined.
+ Note: SLJIT_SDIV is single precision divide. */
+#define SLJIT_SDIVI (SLJIT_OP0_BASE + 7)
+#define SLJIT_ISDIVI (SLJIT_SDIVI | SLJIT_INT_OP)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op);
diff --git a/src/3rdparty/pcre/sljit/sljitNativeARM_32.c b/src/3rdparty/pcre/sljit/sljitNativeARM_32.c
index aca1d31fdf..5cd4c71a29 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeARM_32.c
+++ b/src/3rdparty/pcre/sljit/sljitNativeARM_32.c
@@ -1833,18 +1833,33 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
| (reg_map[SLJIT_R0] << 8)
| reg_map[TMP_REG1]);
#endif
- case SLJIT_LUDIV:
- case SLJIT_LSDIV:
- if (compiler->scratches >= 3)
+ case SLJIT_UDIVMOD:
+ case SLJIT_SDIVMOD:
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
+ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
+ SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2, bad_register_mapping);
+
+ if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) {
FAIL_IF(push_inst(compiler, 0xe52d2008 /* str r2, [sp, #-8]! */));
+ FAIL_IF(push_inst(compiler, 0xe58d1004 /* str r1, [sp, #4] */));
+ }
+ else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3))
+ FAIL_IF(push_inst(compiler, 0xe52d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* str r1/r2, [sp, #-8]! */));
+
#if defined(__GNUC__)
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
- (op == SLJIT_LUDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
+ ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
#else
#error "Software divmod functions are needed"
#endif
- if (compiler->scratches >= 3)
- return push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */);
+
+ if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) {
+ FAIL_IF(push_inst(compiler, 0xe59d1004 /* ldr r1, [sp, #4] */));
+ FAIL_IF(push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */));
+ }
+ else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3))
+ return push_inst(compiler, 0xe49d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* ldr r1/r2, [sp], #8 */);
return SLJIT_SUCCESS;
}
diff --git a/src/3rdparty/pcre/sljit/sljitNativeARM_64.c b/src/3rdparty/pcre/sljit/sljitNativeARM_64.c
index b66455f756..044a675eee 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeARM_64.c
+++ b/src/3rdparty/pcre/sljit/sljitNativeARM_64.c
@@ -1087,14 +1087,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil
saved_regs_size += sizeof(sljit_sw);
}
local_size -= saved_regs_size + SLJIT_LOCALS_OFFSET;
- FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10)));
+ if (saved_regs_size > 0)
+ FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10)));
}
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
prev = -1;
for (i = SLJIT_S0; i >= tmp; i--) {
if (prev == -1) {
- prev = i;
+ if (!(offs & (1 << 15))) {
+ prev = i;
+ continue;
+ }
+ FAIL_IF(push_inst(compiler, STRI | RT(i) | RN(TMP_SP) | (offs >> 5)));
+ offs += 1 << 15;
continue;
}
FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(TMP_SP) | offs));
@@ -1104,7 +1110,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
if (prev == -1) {
- prev = i;
+ if (!(offs & (1 << 15))) {
+ prev = i;
+ continue;
+ }
+ FAIL_IF(push_inst(compiler, STRI | RT(i) | RN(TMP_SP) | (offs >> 5)));
+ offs += 1 << 15;
continue;
}
FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(TMP_SP) | offs));
@@ -1112,8 +1123,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil
prev = -1;
}
- if (prev != -1)
- FAIL_IF(push_inst(compiler, STRI | RT(prev) | RN(TMP_SP) | (offs >> 5)));
+ SLJIT_ASSERT(prev == -1);
if (compiler->local_size > (63 * sizeof(sljit_sw))) {
/* The local_size is already adjusted by the saved registers. */
@@ -1188,7 +1198,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi
prev = -1;
for (i = SLJIT_S0; i >= tmp; i--) {
if (prev == -1) {
- prev = i;
+ if (!(offs & (1 << 15))) {
+ prev = i;
+ continue;
+ }
+ FAIL_IF(push_inst(compiler, LDRI | RT(i) | RN(TMP_SP) | (offs >> 5)));
+ offs += 1 << 15;
continue;
}
FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(TMP_SP) | offs));
@@ -1198,7 +1213,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi
for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
if (prev == -1) {
- prev = i;
+ if (!(offs & (1 << 15))) {
+ prev = i;
+ continue;
+ }
+ FAIL_IF(push_inst(compiler, LDRI | RT(i) | RN(TMP_SP) | (offs >> 5)));
+ offs += 1 << 15;
continue;
}
FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(TMP_SP) | offs));
@@ -1206,13 +1226,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi
prev = -1;
}
- if (prev != -1)
- FAIL_IF(push_inst(compiler, LDRI | RT(prev) | RN(TMP_SP) | (offs >> 5)));
+ SLJIT_ASSERT(prev == -1);
if (compiler->local_size <= (63 * sizeof(sljit_sw))) {
FAIL_IF(push_inst(compiler, LDP_PST | 29 | RT2(TMP_LR)
| RN(TMP_SP) | (((local_size >> 3) & 0x7f) << 15)));
- } else {
+ } else if (saved_regs_size > 0) {
FAIL_IF(push_inst(compiler, ADDI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10)));
}
@@ -1242,12 +1261,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
FAIL_IF(push_inst(compiler, MADD | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
return push_inst(compiler, (op == SLJIT_LUMUL ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
- case SLJIT_LUDIV:
- case SLJIT_LSDIV:
+ case SLJIT_UDIVMOD:
+ case SLJIT_SDIVMOD:
FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
- FAIL_IF(push_inst(compiler, ((op == SLJIT_LUDIV ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)));
+ FAIL_IF(push_inst(compiler, ((op == SLJIT_UDIVMOD ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)));
FAIL_IF(push_inst(compiler, (MADD ^ inv_bits) | RD(SLJIT_R1) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
return push_inst(compiler, (SUB ^ inv_bits) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
+ return push_inst(compiler, ((op == SLJIT_UDIVI ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1));
}
return SLJIT_SUCCESS;
diff --git a/src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c b/src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c
index 6e38cec899..f9803f5d44 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c
+++ b/src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c
@@ -1239,6 +1239,9 @@ extern int __aeabi_idivmod(int numerator, int denominator);
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
{
+ sljit_sw saved_reg_list[3];
+ sljit_sw saved_reg_count;
+
CHECK_ERROR();
CHECK(check_sljit_emit_op0(compiler, op));
@@ -1255,24 +1258,53 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
| (reg_map[SLJIT_R0] << 12)
| (reg_map[SLJIT_R0] << 16)
| reg_map[SLJIT_R1]);
- case SLJIT_LUDIV:
- case SLJIT_LSDIV:
- if (compiler->scratches >= 4) {
- FAIL_IF(push_inst32(compiler, 0xf84d2d04 /* str r2, [sp, #-4]! */));
- FAIL_IF(push_inst32(compiler, 0xf84dcd04 /* str ip, [sp, #-4]! */));
- } else if (compiler->scratches >= 3)
- FAIL_IF(push_inst32(compiler, 0xf84d2d08 /* str r2, [sp, #-8]! */));
+ case SLJIT_UDIVMOD:
+ case SLJIT_SDIVMOD:
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
+ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
+ SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 12, bad_register_mapping);
+
+ saved_reg_count = 0;
+ if (compiler->scratches >= 4)
+ saved_reg_list[saved_reg_count++] = 12;
+ if (compiler->scratches >= 3)
+ saved_reg_list[saved_reg_count++] = 2;
+ if (op >= SLJIT_UDIVI)
+ saved_reg_list[saved_reg_count++] = 1;
+
+ if (saved_reg_count > 0) {
+ FAIL_IF(push_inst32(compiler, 0xf84d0d00 | (saved_reg_count >= 3 ? 16 : 8)
+ | (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */));
+ if (saved_reg_count >= 2) {
+ SLJIT_ASSERT(saved_reg_list[1] < 8);
+ FAIL_IF(push_inst16(compiler, 0x9001 | (saved_reg_list[1] << 8) /* str rX, [sp, #4] */));
+ }
+ if (saved_reg_count >= 3) {
+ SLJIT_ASSERT(saved_reg_list[2] < 8);
+ FAIL_IF(push_inst16(compiler, 0x9002 | (saved_reg_list[2] << 8) /* str rX, [sp, #8] */));
+ }
+ }
+
#if defined(__GNUC__)
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
- (op == SLJIT_LUDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
+ ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
#else
#error "Software divmod functions are needed"
#endif
- if (compiler->scratches >= 4) {
- FAIL_IF(push_inst32(compiler, 0xf85dcb04 /* ldr ip, [sp], #4 */));
- return push_inst32(compiler, 0xf85d2b04 /* ldr r2, [sp], #4 */);
- } else if (compiler->scratches >= 3)
- return push_inst32(compiler, 0xf85d2b08 /* ldr r2, [sp], #8 */);
+
+ if (saved_reg_count > 0) {
+ if (saved_reg_count >= 3) {
+ SLJIT_ASSERT(saved_reg_list[2] < 8);
+ FAIL_IF(push_inst16(compiler, 0x9802 | (saved_reg_list[2] << 8) /* ldr rX, [sp, #8] */));
+ }
+ if (saved_reg_count >= 2) {
+ SLJIT_ASSERT(saved_reg_list[1] < 8);
+ FAIL_IF(push_inst16(compiler, 0x9801 | (saved_reg_list[1] << 8) /* ldr rX, [sp, #4] */));
+ }
+ return push_inst32(compiler, 0xf85d0b00 | (saved_reg_count >= 3 ? 16 : 8)
+ | (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */);
+ }
return SLJIT_SUCCESS;
}
diff --git a/src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c b/src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c
index 3e2c9f0232..cf3535f81a 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c
+++ b/src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c
@@ -1053,8 +1053,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
#endif
FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0)));
return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
- case SLJIT_LUDIV:
- case SLJIT_LSDIV:
+ case SLJIT_UDIVMOD:
+ case SLJIT_SDIVMOD:
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
+ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
#if !(defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
@@ -1062,15 +1065,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
if (int_op)
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
else
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
#else
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
#endif
FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0)));
- return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
+ return (op >= SLJIT_UDIVI) ? SLJIT_SUCCESS : push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
}
return SLJIT_SUCCESS;
diff --git a/src/3rdparty/pcre/sljit/sljitNativePPC_common.c b/src/3rdparty/pcre/sljit/sljitNativePPC_common.c
index 08d5356f5a..b6a043f4e4 100644
--- a/src/3rdparty/pcre/sljit/sljitNativePPC_common.c
+++ b/src/3rdparty/pcre/sljit/sljitNativePPC_common.c
@@ -1267,22 +1267,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
return push_inst(compiler, (op == SLJIT_LUMUL ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
#endif
- case SLJIT_LUDIV:
- case SLJIT_LSDIV:
+ case SLJIT_UDIVMOD:
+ case SLJIT_SDIVMOD:
FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- if (int_op) {
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVWU : DIVW) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
- FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
- } else {
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVDU : DIVD) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
- FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
- }
- return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1));
+ FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_UDIVMOD ? DIVWU : DIVW) : (op == SLJIT_UDIVMOD ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
+ FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
#else
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVWU : DIVW) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
+ FAIL_IF(push_inst(compiler, (op == SLJIT_UDIVMOD ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
+#endif
return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1));
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ return push_inst(compiler, (int_op ? (op == SLJIT_UDIVI ? DIVWU : DIVW) : (op == SLJIT_UDIVI ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
+#else
+ return push_inst(compiler, (op == SLJIT_UDIVI ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
#endif
}
diff --git a/src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c b/src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c
index 0b1927a824..327c4267be 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c
+++ b/src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c
@@ -777,20 +777,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
#else
#error "Implementation required"
#endif
- case SLJIT_LUDIV:
- case SLJIT_LSDIV:
+ case SLJIT_UDIVMOD:
+ case SLJIT_SDIVMOD:
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
+ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- if (op == SLJIT_LUDIV)
+ if ((op | 0x2) == SLJIT_UDIVI)
FAIL_IF(push_inst(compiler, WRY | S1(0), MOVABLE_INS));
else {
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_R0) | IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, WRY | S1(TMP_REG1), MOVABLE_INS));
}
- FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
+ if (op <= SLJIT_SDIVMOD)
+ FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
+ if (op >= SLJIT_UDIVI)
+ return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_R1) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R1)));
- FAIL_IF(push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1)));
- return SLJIT_SUCCESS;
+ return push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1));
#else
#error "Implementation required"
#endif
diff --git a/src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c b/src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c
index 1d6aa5a110..4d40392fa8 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c
+++ b/src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c
@@ -35,21 +35,21 @@
#define SIMM_16BIT_MIN (-0x8000)
#define SIMM_17BIT_MAX (0xffff)
#define SIMM_17BIT_MIN (-0x10000)
-#define SIMM_32BIT_MIN (-0x80000000)
#define SIMM_32BIT_MAX (0x7fffffff)
-#define SIMM_48BIT_MIN (0x800000000000L)
+#define SIMM_32BIT_MIN (-0x7fffffff - 1)
#define SIMM_48BIT_MAX (0x7fffffff0000L)
+#define SIMM_48BIT_MIN (-0x800000000000L)
#define IMM16(imm) ((imm) & 0xffff)
#define UIMM_16BIT_MAX (0xffff)
-#define TMP_REG1 (SLJIT_NO_REGISTERS + 1)
-#define TMP_REG2 (SLJIT_NO_REGISTERS + 2)
-#define TMP_REG3 (SLJIT_NO_REGISTERS + 3)
-#define ADDR_TMP (SLJIT_NO_REGISTERS + 4)
+#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
+#define ADDR_TMP (SLJIT_NUMBER_OF_REGISTERS + 5)
#define PIC_ADDR_REG TMP_REG2
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = {
+static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
63, 0, 1, 2, 3, 4, 30, 31, 32, 33, 34, 54, 5, 16, 6, 7
};
@@ -58,11 +58,6 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = {
#define TMP_REG2_mapped 16
#define TMP_REG3_mapped 6
#define ADDR_TMP_mapped 7
-#define SLJIT_SAVED_REG1_mapped 30
-#define SLJIT_SAVED_REG2_mapped 31
-#define SLJIT_SAVED_REG3_mapped 32
-#define SLJIT_SAVED_EREG1_mapped 33
-#define SLJIT_SAVED_EREG2_mapped 34
/* Flags are keept in volatile registers. */
#define EQUAL_FLAG 8
@@ -399,6 +394,9 @@ static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins)
#define SUB(dst, srca, srcb) \
push_3_buffer(compiler, TILEGX_OPC_SUB, dst, srca, srcb, __LINE__)
+#define MUL(dst, srca, srcb) \
+ push_3_buffer(compiler, TILEGX_OPC_MULX, dst, srca, srcb, __LINE__)
+
#define NOR(dst, srca, srcb) \
push_3_buffer(compiler, TILEGX_OPC_NOR, dst, srca, srcb, __LINE__)
@@ -547,8 +545,8 @@ const struct Format* compute_format()
const struct Format* match = NULL;
const struct Format *b = NULL;
- unsigned int i = 0;
- for (i; i < sizeof formats / sizeof formats[0]; i++) {
+ unsigned int i;
+ for (i = 0; i < sizeof formats / sizeof formats[0]; i++) {
b = &formats[i];
if ((b->pipe_mask & compatible_pipes) == b->pipe_mask) {
match = b;
@@ -625,7 +623,6 @@ tilegx_bundle_bits get_bundle_bit(struct jit_instr *inst)
static sljit_si update_buffer(struct sljit_compiler *compiler)
{
- int count;
int i;
int orig_index = inst_buf_index;
struct jit_instr inst0 = inst_buf[0];
@@ -738,8 +735,10 @@ static sljit_si update_buffer(struct sljit_compiler *compiler)
static sljit_si flush_buffer(struct sljit_compiler *compiler)
{
- while (inst_buf_index != 0)
- update_buffer(compiler);
+ while (inst_buf_index != 0) {
+ FAIL_IF(update_buffer(compiler));
+ }
+ return SLJIT_SUCCESS;
}
static sljit_si push_4_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int op3, int line)
@@ -787,6 +786,7 @@ static sljit_si push_3_buffer(struct sljit_compiler *compiler, tilegx_mnemonic o
case TILEGX_OPC_ADD:
case TILEGX_OPC_AND:
case TILEGX_OPC_SUB:
+ case TILEGX_OPC_MULX:
case TILEGX_OPC_OR:
case TILEGX_OPC_XOR:
case TILEGX_OPC_NOR:
@@ -905,7 +905,6 @@ static SLJIT_INLINE sljit_ins * detect_jump_type(struct sljit_jump *jump, sljit_
sljit_sw diff;
sljit_uw target_addr;
sljit_ins *inst;
- sljit_ins saved_inst;
if (jump->flags & SLJIT_REWRITABLE_JUMP)
return code_ptr;
@@ -1009,7 +1008,7 @@ SLJIT_API_FUNC_ATTRIBUTE void * sljit_generate_code(struct sljit_compiler *compi
struct sljit_const *const_;
CHECK_ERROR_PTR();
- check_sljit_generate_code(compiler);
+ CHECK_PTR(check_sljit_generate_code(compiler));
reverse_buf(compiler);
code = (sljit_ins *)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins));
@@ -1178,13 +1177,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil
sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
{
sljit_ins base;
- sljit_ins bundle = 0;
-
+ sljit_si i, tmp;
+
CHECK_ERROR();
- check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
+ CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
- local_size += (saveds + 1) * sizeof(sljit_sw);
+ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
local_size = (local_size + 7) & ~7;
compiler->local_size = local_size;
@@ -1200,56 +1199,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil
local_size = 0;
}
+ /* Save the return address. */
FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8));
FAIL_IF(ST_ADD(ADDR_TMP_mapped, RA, -8));
- if (saveds >= 1)
- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG1_mapped, -8));
-
- if (saveds >= 2)
- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG2_mapped, -8));
-
- if (saveds >= 3)
- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG3_mapped, -8));
-
- if (saveds >= 4)
- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_EREG1_mapped, -8));
-
- if (saveds >= 5)
- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_EREG2_mapped, -8));
-
- if (args >= 1)
- FAIL_IF(ADD(SLJIT_SAVED_REG1_mapped, 0, ZERO));
+ /* Save the S registers. */
+ tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+ for (i = SLJIT_S0; i >= tmp; i--) {
+ FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8));
+ }
- if (args >= 2)
- FAIL_IF(ADD(SLJIT_SAVED_REG2_mapped, 1, ZERO));
+ /* Save the R registers that need to be reserved. */
+ for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+ FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8));
+ }
- if (args >= 3)
- FAIL_IF(ADD(SLJIT_SAVED_REG3_mapped, 2, ZERO));
+ /* Move the arguments to S registers. */
+ for (i = 0; i < args; i++) {
+ FAIL_IF(ADD(reg_map[SLJIT_S0 - i], i, ZERO));
+ }
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler,
+SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
{
- CHECK_ERROR_VOID();
- check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
+ CHECK_ERROR();
+ CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
- local_size += (saveds + 1) * sizeof(sljit_sw);
+ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
compiler->local_size = (local_size + 7) & ~7;
+
+ return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
{
sljit_si local_size;
sljit_ins base;
- int addr_initialized = 0;
+ sljit_si i, tmp;
+ sljit_si saveds;
CHECK_ERROR();
- check_sljit_emit_return(compiler, op, src, srcw);
+ CHECK(check_sljit_emit_return(compiler, op, src, srcw));
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
@@ -1263,50 +1258,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi
local_size = 0;
}
+ /* Restore the return address. */
FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8));
- FAIL_IF(LD(RA, ADDR_TMP_mapped));
-
- if (compiler->saveds >= 5) {
- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 48));
- addr_initialized = 1;
+ FAIL_IF(LD_ADD(RA, ADDR_TMP_mapped, -8));
- FAIL_IF(LD_ADD(SLJIT_SAVED_EREG2_mapped, ADDR_TMP_mapped, 8));
+ /* Restore the S registers. */
+ saveds = compiler->saveds;
+ tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+ for (i = SLJIT_S0; i >= tmp; i--) {
+ FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8));
}
- if (compiler->saveds >= 4) {
- if (addr_initialized == 0) {
- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 40));
- addr_initialized = 1;
- }
-
- FAIL_IF(LD_ADD(SLJIT_SAVED_EREG1_mapped, ADDR_TMP_mapped, 8));
- }
-
- if (compiler->saveds >= 3) {
- if (addr_initialized == 0) {
- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 32));
- addr_initialized = 1;
- }
-
- FAIL_IF(LD_ADD(SLJIT_SAVED_REG3_mapped, ADDR_TMP_mapped, 8));
- }
-
- if (compiler->saveds >= 2) {
- if (addr_initialized == 0) {
- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 24));
- addr_initialized = 1;
- }
-
- FAIL_IF(LD_ADD(SLJIT_SAVED_REG2_mapped, ADDR_TMP_mapped, 8));
- }
-
- if (compiler->saveds >= 1) {
- if (addr_initialized == 0) {
- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 16));
- /* addr_initialized = 1; no need to initialize as it's the last one. */
- }
-
- FAIL_IF(LD_ADD(SLJIT_SAVED_REG1_mapped, ADDR_TMP_mapped, 8));
+ /* Restore the R registers that need to be reserved. */
+ for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+ FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8));
}
if (compiler->local_size <= SIMM_16BIT_MAX)
@@ -1585,7 +1550,7 @@ static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
{
CHECK_ERROR();
- check_sljit_emit_fast_enter(compiler, dst, dstw);
+ CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
/* For UNUSED dst. Uncommon, but possible. */
@@ -1602,7 +1567,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *c
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
{
CHECK_ERROR();
- check_sljit_emit_fast_return(compiler, src, srcw);
+ CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
if (FAST_IS_REG(src))
@@ -1636,9 +1601,11 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj
if (op == SLJIT_MOV_SI)
return BFEXTS(reg_map[dst], reg_map[src2], 0, 31);
- return BFEXTU(reg_map[dst], reg_map[src2], 0, 31);
- } else if (dst != src2)
- SLJIT_ASSERT_STOP();
+ return BFEXTU(reg_map[dst], reg_map[src2], 0, 31);
+ } else if (dst != src2) {
+ SLJIT_ASSERT(src2 == 0);
+ return ADD(reg_map[dst], reg_map[src2], ZERO);
+ }
return SLJIT_SUCCESS;
@@ -1650,8 +1617,10 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj
return BFEXTS(reg_map[dst], reg_map[src2], 0, 7);
return BFEXTU(reg_map[dst], reg_map[src2], 0, 7);
- } else if (dst != src2)
- SLJIT_ASSERT_STOP();
+ } else if (dst != src2) {
+ SLJIT_ASSERT(src2 == 0);
+ return ADD(reg_map[dst], reg_map[src2], ZERO);
+ }
return SLJIT_SUCCESS;
@@ -1663,8 +1632,10 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj
return BFEXTS(reg_map[dst], reg_map[src2], 0, 15);
return BFEXTU(reg_map[dst], reg_map[src2], 0, 15);
- } else if (dst != src2)
- SLJIT_ASSERT_STOP();
+ } else if (dst != src2) {
+ SLJIT_ASSERT(src2 == 0);
+ return ADD(reg_map[dst], reg_map[src2], ZERO);
+ }
return SLJIT_SUCCESS;
@@ -1811,7 +1782,6 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj
else {
/* Rare ocasion. */
FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO));
-
overflow_ra = TMP_EREG2;
}
}
@@ -1903,6 +1873,17 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj
return SLJIT_SUCCESS;
+ case SLJIT_MUL:
+ if (flags & SRC2_IMM) {
+ FAIL_IF(load_immediate(compiler, TMP_REG2_mapped, src2));
+ src2 = TMP_REG2;
+ flags &= ~SRC2_IMM;
+ }
+
+ FAIL_IF(MUL(reg_map[dst], reg_map[src1], reg_map[src2]));
+
+ return SLJIT_SUCCESS;
+
#define EMIT_LOGICAL(op_imm, op_norm) \
if (flags & SRC2_IMM) { \
FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, src2)); \
@@ -1950,8 +1931,8 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj
} else { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_3_buffer( \
- compiler, op_imm, reg_map[dst], reg_map[src1], \
- src2 & 0x3F, __LINE__)); \
+ compiler, op_norm, EQUAL_FLAG, reg_map[src1], \
+ reg_map[src2], __LINE__)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_3_buffer( \
compiler, op_norm, reg_map[dst], reg_map[src1], \
@@ -2105,66 +2086,61 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *com
{
sljit_si sugg_dst_ar, dst_ar;
sljit_si flags = GET_ALL_FLAGS(op);
+ sljit_si mem_type = (op & SLJIT_INT_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
CHECK_ERROR();
- check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type);
+ CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
ADJUST_LOCAL_OFFSET(dst, dstw);
if (dst == SLJIT_UNUSED)
return SLJIT_SUCCESS;
op = GET_OPCODE(op);
+ if (op == SLJIT_MOV_SI || op == SLJIT_MOV_UI)
+ mem_type = INT_DATA | SIGNED_DATA;
sugg_dst_ar = reg_map[(op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2];
compiler->cache_arg = 0;
compiler->cache_argw = 0;
if (op >= SLJIT_ADD && (src & SLJIT_MEM)) {
ADJUST_LOCAL_OFFSET(src, srcw);
- FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1_mapped, src, srcw, dst, dstw));
+ FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, TMP_REG1_mapped, src, srcw, dst, dstw));
src = TMP_REG1;
srcw = 0;
}
- switch (type) {
- case SLJIT_C_EQUAL:
- case SLJIT_C_NOT_EQUAL:
+ switch (type & 0xff) {
+ case SLJIT_EQUAL:
+ case SLJIT_NOT_EQUAL:
FAIL_IF(CMPLTUI(sugg_dst_ar, EQUAL_FLAG, 1));
dst_ar = sugg_dst_ar;
break;
- case SLJIT_C_LESS:
- case SLJIT_C_GREATER_EQUAL:
- case SLJIT_C_FLOAT_LESS:
- case SLJIT_C_FLOAT_GREATER_EQUAL:
+ case SLJIT_LESS:
+ case SLJIT_GREATER_EQUAL:
dst_ar = ULESS_FLAG;
break;
- case SLJIT_C_GREATER:
- case SLJIT_C_LESS_EQUAL:
- case SLJIT_C_FLOAT_GREATER:
- case SLJIT_C_FLOAT_LESS_EQUAL:
+ case SLJIT_GREATER:
+ case SLJIT_LESS_EQUAL:
dst_ar = UGREATER_FLAG;
break;
- case SLJIT_C_SIG_LESS:
- case SLJIT_C_SIG_GREATER_EQUAL:
+ case SLJIT_SIG_LESS:
+ case SLJIT_SIG_GREATER_EQUAL:
dst_ar = LESS_FLAG;
break;
- case SLJIT_C_SIG_GREATER:
- case SLJIT_C_SIG_LESS_EQUAL:
+ case SLJIT_SIG_GREATER:
+ case SLJIT_SIG_LESS_EQUAL:
dst_ar = GREATER_FLAG;
break;
- case SLJIT_C_OVERFLOW:
- case SLJIT_C_NOT_OVERFLOW:
+ case SLJIT_OVERFLOW:
+ case SLJIT_NOT_OVERFLOW:
dst_ar = OVERFLOW_FLAG;
break;
- case SLJIT_C_MUL_OVERFLOW:
- case SLJIT_C_MUL_NOT_OVERFLOW:
+ case SLJIT_MUL_OVERFLOW:
+ case SLJIT_MUL_NOT_OVERFLOW:
FAIL_IF(CMPLTUI(sugg_dst_ar, OVERFLOW_FLAG, 1));
dst_ar = sugg_dst_ar;
type ^= 0x1; /* Flip type bit for the XORI below. */
break;
- case SLJIT_C_FLOAT_EQUAL:
- case SLJIT_C_FLOAT_NOT_EQUAL:
- dst_ar = EQUAL_FLAG;
- break;
default:
SLJIT_ASSERT_STOP();
@@ -2180,11 +2156,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *com
if (op >= SLJIT_ADD) {
if (TMP_REG2_mapped != dst_ar)
FAIL_IF(ADD(TMP_REG2_mapped, dst_ar, ZERO));
- return emit_op(compiler, op | flags, CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0);
+ return emit_op(compiler, op | flags, mem_type | CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0);
}
if (dst & SLJIT_MEM)
- return emit_op_mem(compiler, WORD_DATA, dst_ar, dst, dstw);
+ return emit_op_mem(compiler, mem_type, dst_ar, dst, dstw);
if (sugg_dst_ar != dst_ar)
return ADD(sugg_dst_ar, dst_ar, ZERO);
@@ -2194,7 +2170,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *com
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) {
CHECK_ERROR();
- check_sljit_emit_op0(compiler, op);
+ CHECK(check_sljit_emit_op0(compiler, op));
op = GET_OPCODE(op);
switch (op) {
@@ -2204,10 +2180,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
case SLJIT_BREAKPOINT:
return PI(BPT);
- case SLJIT_UMUL:
- case SLJIT_SMUL:
- case SLJIT_UDIV:
- case SLJIT_SDIV:
+ case SLJIT_LUMUL:
+ case SLJIT_LSMUL:
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
SLJIT_ASSERT_STOP();
}
@@ -2217,7 +2193,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src, sljit_sw srcw)
{
CHECK_ERROR();
- check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw);
+ CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
ADJUST_LOCAL_OFFSET(dst, dstw);
ADJUST_LOCAL_OFFSET(src, srcw);
@@ -2273,7 +2249,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler
return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw);
case SLJIT_CLZ:
- return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, op, (op & SLJIT_INT_OP) ? INT_DATA : WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
}
return SLJIT_SUCCESS;
@@ -2282,7 +2258,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src1, sljit_sw src1w, sljit_si src2, sljit_sw src2w)
{
CHECK_ERROR();
- check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w);
+ CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(dst, dstw);
ADJUST_LOCAL_OFFSET(src1, src1w);
ADJUST_LOCAL_OFFSET(src2, src2w);
@@ -2325,7 +2301,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label * sljit_emit_label(struct sljit_comp
flush_buffer(compiler);
CHECK_ERROR_PTR();
- check_sljit_emit_label(compiler);
+ CHECK_PTR(check_sljit_emit_label(compiler));
if (compiler->last_label && compiler->last_label->size == compiler->size)
return compiler->last_label;
@@ -2344,7 +2320,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compil
flush_buffer(compiler);
CHECK_ERROR();
- check_sljit_emit_ijump(compiler, type, src, srcw);
+ CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
if (FAST_IS_REG(src)) {
@@ -2404,8 +2380,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compil
return SLJIT_SUCCESS;
- } else if (src & SLJIT_MEM)
+ } else if (src & SLJIT_MEM) {
FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw));
+ flush_buffer(compiler);
+ }
FAIL_IF(JR_SOLO(reg_map[src_r]));
@@ -2432,7 +2410,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compil
flush_buffer(compiler);
CHECK_ERROR_PTR();
- check_sljit_emit_jump(compiler, type);
+ CHECK_PTR(check_sljit_emit_jump(compiler, type));
jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump));
PTR_FAIL_IF(!jump);
@@ -2440,48 +2418,42 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compil
type &= 0xff;
switch (type) {
- case SLJIT_C_EQUAL:
- case SLJIT_C_FLOAT_NOT_EQUAL:
+ case SLJIT_EQUAL:
BR_NZ(EQUAL_FLAG);
break;
- case SLJIT_C_NOT_EQUAL:
- case SLJIT_C_FLOAT_EQUAL:
+ case SLJIT_NOT_EQUAL:
BR_Z(EQUAL_FLAG);
break;
- case SLJIT_C_LESS:
- case SLJIT_C_FLOAT_LESS:
+ case SLJIT_LESS:
BR_Z(ULESS_FLAG);
break;
- case SLJIT_C_GREATER_EQUAL:
- case SLJIT_C_FLOAT_GREATER_EQUAL:
+ case SLJIT_GREATER_EQUAL:
BR_NZ(ULESS_FLAG);
break;
- case SLJIT_C_GREATER:
- case SLJIT_C_FLOAT_GREATER:
+ case SLJIT_GREATER:
BR_Z(UGREATER_FLAG);
break;
- case SLJIT_C_LESS_EQUAL:
- case SLJIT_C_FLOAT_LESS_EQUAL:
+ case SLJIT_LESS_EQUAL:
BR_NZ(UGREATER_FLAG);
break;
- case SLJIT_C_SIG_LESS:
+ case SLJIT_SIG_LESS:
BR_Z(LESS_FLAG);
break;
- case SLJIT_C_SIG_GREATER_EQUAL:
+ case SLJIT_SIG_GREATER_EQUAL:
BR_NZ(LESS_FLAG);
break;
- case SLJIT_C_SIG_GREATER:
+ case SLJIT_SIG_GREATER:
BR_Z(GREATER_FLAG);
break;
- case SLJIT_C_SIG_LESS_EQUAL:
+ case SLJIT_SIG_LESS_EQUAL:
BR_NZ(GREATER_FLAG);
break;
- case SLJIT_C_OVERFLOW:
- case SLJIT_C_MUL_OVERFLOW:
+ case SLJIT_OVERFLOW:
+ case SLJIT_MUL_OVERFLOW:
BR_Z(OVERFLOW_FLAG);
break;
- case SLJIT_C_NOT_OVERFLOW:
- case SLJIT_C_MUL_NOT_OVERFLOW:
+ case SLJIT_NOT_OVERFLOW:
+ case SLJIT_MUL_NOT_OVERFLOW:
BR_NZ(OVERFLOW_FLAG);
break;
default:
@@ -2536,7 +2508,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const * sljit_emit_const(struct sljit_comp
flush_buffer(compiler);
CHECK_ERROR_PTR();
- check_sljit_emit_const(compiler, dst, dstw, init_value);
+ CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
ADJUST_LOCAL_OFFSET(dst, dstw);
const_ = (struct sljit_const *)ensure_abuf(compiler, sizeof(struct sljit_const));
@@ -2572,3 +2544,18 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta
inst[3] = (inst[3] & ~(0xFFFFL << 43)) | ((new_constant & 0xFFFFL) << 43);
SLJIT_CACHE_FLUSH(inst, inst + 4);
}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+{
+ CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+ return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_si size)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+ return SLJIT_ERR_UNSUPPORTED;
+}
+
diff --git a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c b/src/3rdparty/pcre/sljit/sljitNativeX86_common.c
index 21b276fb8d..e148c34cd1 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c
+++ b/src/3rdparty/pcre/sljit/sljitNativeX86_common.c
@@ -744,8 +744,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
break;
case SLJIT_LUMUL:
case SLJIT_LSMUL:
- case SLJIT_LUDIV:
- case SLJIT_LSDIV:
+ case SLJIT_UDIVMOD:
+ case SLJIT_SDIVMOD:
+ case SLJIT_UDIVI:
+ case SLJIT_SDIVI:
compiler->flags_saved = 0;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
#ifdef _WIN64
@@ -763,9 +765,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
#endif
compiler->mode32 = op & SLJIT_INT_OP;
#endif
+ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
op = GET_OPCODE(op);
- if (op == SLJIT_LUDIV) {
+ if ((op | 0x2) == SLJIT_UDIVI) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64)
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0);
inst = emit_x86_instruction(compiler, 1, SLJIT_R1, 0, SLJIT_R1, 0);
@@ -776,7 +779,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
*inst = XOR_r_rm;
}
- if (op == SLJIT_LSDIV) {
+ if ((op | 0x2) == SLJIT_SDIVI) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64)
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0);
#endif
@@ -807,10 +810,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
FAIL_IF(!inst);
INC_SIZE(2);
*inst++ = GROUP_F7;
- *inst = MOD_REG | ((op >= SLJIT_LUDIV) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]);
+ *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]);
#else
#ifdef _WIN64
- size = (!compiler->mode32 || op >= SLJIT_LUDIV) ? 3 : 2;
+ size = (!compiler->mode32 || op >= SLJIT_UDIVMOD) ? 3 : 2;
#else
size = (!compiler->mode32) ? 3 : 2;
#endif
@@ -819,11 +822,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
INC_SIZE(size);
#ifdef _WIN64
if (!compiler->mode32)
- *inst++ = REX_W | ((op >= SLJIT_LUDIV) ? REX_B : 0);
- else if (op >= SLJIT_LUDIV)
+ *inst++ = REX_W | ((op >= SLJIT_UDIVMOD) ? REX_B : 0);
+ else if (op >= SLJIT_UDIVMOD)
*inst++ = REX_B;
*inst++ = GROUP_F7;
- *inst = MOD_REG | ((op >= SLJIT_LUDIV) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]);
+ *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]);
#else
if (!compiler->mode32)
*inst++ = REX_W;
@@ -838,15 +841,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler
case SLJIT_LSMUL:
*inst |= IMUL;
break;
- case SLJIT_LUDIV:
+ case SLJIT_UDIVMOD:
+ case SLJIT_UDIVI:
*inst |= DIV;
break;
- case SLJIT_LSDIV:
+ case SLJIT_SDIVMOD:
+ case SLJIT_SDIVI:
*inst |= IDIV;
break;
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64)
- EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0);
+ if (op <= SLJIT_SDIVMOD)
+ EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0);
+#else
+ if (op >= SLJIT_UDIVI)
+ EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0);
#endif
break;
}
@@ -1907,60 +1916,62 @@ static sljit_si emit_test_binary(struct sljit_compiler *compiler,
return SLJIT_SUCCESS;
}
- if (FAST_IS_REG(src1)) {
+ if (!(src1 & SLJIT_IMM)) {
if (src2 & SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (IS_HALFWORD(src2w) || compiler->mode32) {
- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0);
+ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w);
FAIL_IF(!inst);
*inst = GROUP_F7;
}
else {
FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w));
- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, 0);
+ inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, src1w);
FAIL_IF(!inst);
*inst = TEST_rm_r;
}
#else
- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0);
+ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w);
FAIL_IF(!inst);
*inst = GROUP_F7;
#endif
+ return SLJIT_SUCCESS;
}
- else {
+ else if (FAST_IS_REG(src1)) {
inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w);
FAIL_IF(!inst);
*inst = TEST_rm_r;
+ return SLJIT_SUCCESS;
}
- return SLJIT_SUCCESS;
}
- if (FAST_IS_REG(src2)) {
+ if (!(src2 & SLJIT_IMM)) {
if (src1 & SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (IS_HALFWORD(src1w) || compiler->mode32) {
- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, 0);
+ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, src2w);
FAIL_IF(!inst);
*inst = GROUP_F7;
}
else {
FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w));
- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, 0);
+ inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, src2w);
FAIL_IF(!inst);
*inst = TEST_rm_r;
}
#else
- inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, 0);
+ inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, src2w);
FAIL_IF(!inst);
*inst = GROUP_F7;
#endif
+ return SLJIT_SUCCESS;
}
- else {
+ else if (FAST_IS_REG(src2)) {
inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w);
FAIL_IF(!inst);
*inst = TEST_rm_r;
+ return SLJIT_SUCCESS;
}
- return SLJIT_SUCCESS;
}
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
diff --git a/src/angle/src/compiler/preprocessor/preprocessor.pro b/src/angle/src/compiler/preprocessor/preprocessor.pro
index 8c5b1555dc..759a3399b4 100644
--- a/src/angle/src/compiler/preprocessor/preprocessor.pro
+++ b/src/angle/src/compiler/preprocessor/preprocessor.pro
@@ -40,15 +40,15 @@ SOURCES += \
$$ANGLE_DIR/src/compiler/preprocessor/Preprocessor.cpp \
$$ANGLE_DIR/src/compiler/preprocessor/Token.cpp
-# NOTE: 'win_flex' and 'bison' can be found in qt5/gnuwin32/bin
-flex.commands = $$addGnuPath(win_flex) --noline --nounistd --outfile=${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_NAME}
+# NOTE: 'flex' and 'bison' can be found in qt5/gnuwin32/bin
+flex.commands = $$addGnuPath(flex) --noline --nounistd --outfile=${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_NAME}
flex.output = ${QMAKE_FILE_BASE}.cpp
flex.input = FLEX_SOURCES
flex.dependency_type = TYPE_C
flex.variable_out = GENERATED_SOURCES
QMAKE_EXTRA_COMPILERS += flex
-bison.commands = $$addGnuPath(win_bison) --no-lines --skeleton=yacc.c --output=${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_NAME}
+bison.commands = $$addGnuPath(bison) --no-lines --skeleton=yacc.c --output=${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_NAME}
bison.output = ${QMAKE_FILE_BASE}.cpp
bison.input = BISON_SOURCES
bison.dependency_type = TYPE_C
diff --git a/src/angle/src/compiler/translator.pro b/src/angle/src/compiler/translator.pro
index e9d16ca5af..9572a51ad4 100644
--- a/src/angle/src/compiler/translator.pro
+++ b/src/angle/src/compiler/translator.pro
@@ -162,15 +162,15 @@ SOURCES += \
$$ANGLE_DIR/src/third_party/compiler/ArrayBoundsClamper.cpp
-# NOTE: 'win_flex' and 'bison' can be found in qt5/gnuwin32/bin
-flex.commands = $$addGnuPath(win_flex) --noline --nounistd --outfile=${QMAKE_FILE_BASE}_lex.cpp ${QMAKE_FILE_NAME}
+# NOTE: 'flex' and 'bison' can be found in qt5/gnuwin32/bin
+flex.commands = $$addGnuPath(flex) --noline --nounistd --outfile=${QMAKE_FILE_BASE}_lex.cpp ${QMAKE_FILE_NAME}
flex.output = ${QMAKE_FILE_BASE}_lex.cpp
flex.input = FLEX_SOURCES
flex.dependency_type = TYPE_C
flex.variable_out = GENERATED_SOURCES
QMAKE_EXTRA_COMPILERS += flex
-bison.commands = $$addGnuPath(win_bison) --no-lines --skeleton=yacc.c --defines=${QMAKE_FILE_BASE}_tab.h \
+bison.commands = $$addGnuPath(bison) --no-lines --skeleton=yacc.c --defines=${QMAKE_FILE_BASE}_tab.h \
--output=${QMAKE_FILE_BASE}_tab.cpp ${QMAKE_FILE_NAME}
bison.output = ${QMAKE_FILE_BASE}_tab.h
bison.input = BISON_SOURCES
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index a912e65d30..a7da751da4 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -2658,6 +2658,7 @@
\value ItemIsTristate \e{This enum value is deprecated.} Use Qt::ItemIsAutoTristate
instead.
\value ItemNeverHasChildren The item never has child items.
+ This is used for optimization purposes only.
\value ItemIsUserTristate The user can cycle through three separate states.
This value has been added in Qt 5.5.
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 8a86ec5858..51b39b1114 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -263,6 +263,7 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
groupId(). You can examine a file's permissions and ownership in a
single statement using the permission() function.
+ \target NTFS permissions
\note On NTFS file systems, ownership and permissions checking is
disabled by default for performance reasons. To enable it,
include the following line:
@@ -893,6 +894,9 @@ QDir QFileInfo::absoluteDir() const
/*!
Returns \c true if the user can read the file; otherwise returns \c false.
+ \note If the \l{NTFS permissions} check has not been enabled, the result
+ on Windows will merely reflect whether the file exists.
+
\sa isWritable(), isExecutable(), permission()
*/
bool QFileInfo::isReadable() const
@@ -911,6 +915,9 @@ bool QFileInfo::isReadable() const
/*!
Returns \c true if the user can write to the file; otherwise returns \c false.
+ \note If the \l{NTFS permissions} check has not been enabled, the result on
+ Windows will merely reflect whether the file is marked as Read Only.
+
\sa isReadable(), isExecutable(), permission()
*/
bool QFileInfo::isWritable() const
@@ -1137,7 +1144,8 @@ QString QFileInfo::readLink() const
returned.
This function can be time consuming under Unix (in the order of
- milliseconds).
+ milliseconds). On Windows, it will return an empty string unless
+ the \l{NTFS permissions} check has been enabled.
\sa ownerId(), group(), groupId()
*/
@@ -1217,6 +1225,9 @@ uint QFileInfo::groupId() const
On systems where files do not have permissions this function
always returns \c true.
+ \note The result might be inaccurate on Windows if the
+ \l{NTFS permissions} check has not been enabled.
+
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 10
@@ -1240,6 +1251,9 @@ bool QFileInfo::permission(QFile::Permissions permissions) const
/*!
Returns the complete OR-ed together combination of
QFile::Permissions for the file.
+
+ \note The result might be inaccurate on Windows if the
+ \l{NTFS permissions} check has not been enabled.
*/
QFile::Permissions QFileInfo::permissions() const
{
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index cdae149678..8ee8d0b703 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
-** Copyright (C) 2014 Intel Corporation
+** Copyright (C) 2015 Intel Corporation
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -139,7 +139,7 @@ QT_BEGIN_NAMESPACE
Unix environment allows both variable names and contents to contain arbitrary
binary data (except for the NUL character). QProcessEnvironment will preserve
such variables, but does not support manipulating variables whose names or
- values are not encodable by the current locale settings (see
+ values cannot be encoded by the current locale settings (see
QTextCodec::codecForLocale).
On Windows, the variable names are case-insensitive, but case-preserving.
@@ -395,8 +395,8 @@ QString QProcessEnvironment::value(const QString &name, const QString &defaultVa
Use with the QProcess::setEnvironment function is not recommended due to
potential encoding problems under Unix, and worse performance.
- \sa systemEnvironment(), QProcess::systemEnvironment(), QProcess::environment(),
- QProcess::setEnvironment()
+ \sa systemEnvironment(), QProcess::systemEnvironment(),
+ QProcess::setProcessEnvironment()
*/
QStringList QProcessEnvironment::toStringList() const
{
@@ -545,7 +545,7 @@ void QProcessPrivate::Channel::clear()
QProcess can merge the two output channels, so that standard
output and standard error data from the running process both use
the standard output channel. Call setProcessChannelMode() with
- MergedChannels before starting the process to activative
+ MergedChannels before starting the process to activate
this feature. You also have the option of forwarding the output of
the running process to the calling, main process, by passing
ForwardedChannels as the argument. It is also possible to forward
@@ -556,7 +556,7 @@ void QProcessPrivate::Channel::clear()
Certain processes need special environment settings in order to
operate. You can set environment variables for your process by
- calling setEnvironment(). To set a working directory, call
+ calling setProcessEnvironment(). To set a working directory, call
setWorkingDirectory(). By default, processes are run in the
current working directory of the calling process.
@@ -1328,7 +1328,7 @@ QProcess::InputChannelMode QProcess::inputChannelMode() const
/*!
\since 5.2
- Sets the channel mode of the QProcess standard intput
+ Sets the channel mode of the QProcess standard input
channel to the \a mode specified.
This mode will be used the next time start() is called.
@@ -2195,6 +2195,7 @@ void QProcessPrivate::start(QIODevice::OpenMode mode)
qDebug() << "QProcess::start(" << program << ',' << arguments << ',' << mode << ')';
#endif
+ stdinChannel.buffer.clear();
stdoutChannel.buffer.clear();
stderrChannel.buffer.clear();
@@ -2393,7 +2394,7 @@ void QProcess::setArguments(const QStringList &arguments)
The process may not exit as a result of calling this function (it is given
the chance to prompt the user for any unsaved files, etc).
- On Windows, terminate() posts a WM_CLOSE message to all toplevel windows
+ On Windows, terminate() posts a WM_CLOSE message to all top-level windows
of the process and then to the main thread of the process itself. On Unix
and OS X the \c SIGTERM signal is sent.
@@ -2589,14 +2590,14 @@ QT_END_INCLUDE_NAMESPACE
This function does not cache the system environment. Therefore, it's
possible to obtain an updated version of the environment if low-level C
- library functions like \tt setenv ot \tt putenv have been called.
+ library functions like \tt setenv or \tt putenv have been called.
However, note that repeated calls to this function will recreate the
list of environment variables, which is a non-trivial operation.
\note For new code, it is recommended to use QProcessEnvironment::systemEnvironment()
- \sa QProcessEnvironment::systemEnvironment(), environment(), setEnvironment()
+ \sa QProcessEnvironment::systemEnvironment(), setProcessEnvironment()
*/
QStringList QProcess::systemEnvironment()
{
@@ -2619,7 +2620,7 @@ QStringList QProcess::systemEnvironment()
It is returned as a QProcessEnvironment. This function does not
cache the system environment. Therefore, it's possible to obtain
an updated version of the environment if low-level C library
- functions like \tt setenv ot \tt putenv have been called.
+ functions like \tt setenv or \tt putenv have been called.
However, note that repeated calls to this function will recreate the
QProcessEnvironment object, which is a non-trivial operation.
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 5c9db05eff..e77249975c 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -694,13 +694,15 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
return true;
// If we wouldn't write anything, check if we can read stdout.
- if (bytesAvailableInChannel(&stdoutChannel) != 0) {
+ if (stdoutChannel.pipe[0] != INVALID_Q_PIPE
+ && bytesAvailableInChannel(&stdoutChannel) != 0) {
tryReadFromChannel(&stdoutChannel);
timer.resetIncrements();
}
// Check if we can read stderr.
- if (bytesAvailableInChannel(&stderrChannel) != 0) {
+ if (stderrChannel.pipe[0] != INVALID_Q_PIPE
+ && bytesAvailableInChannel(&stderrChannel) != 0) {
tryReadFromChannel(&stderrChannel);
timer.resetIncrements();
}
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 83c52dbf2c..54a2855239 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -507,9 +507,9 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
valid = true;
ready = true;
- bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize;
- bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize;
- bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize;
+ bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize;
+ bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
+ bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
blockSize = statfs_buf.f_bsize;
#if defined(Q_OS_ANDROID) || defined (Q_OS_BSD4)
#if defined(_STATFS_F_FLAGS)
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index add2ac94da..57053f129a 100644
--- a/src/corelib/io/qwindowspipewriter.cpp
+++ b/src/corelib/io/qwindowspipewriter.cpp
@@ -85,7 +85,7 @@ qint64 QWindowsPipeWriter::write(const char *ptr, qint64 maxlen)
return -1;
QMutexLocker locker(&lock);
- data.append(QByteArray(ptr, maxlen));
+ data.append(ptr, maxlen);
waitCondition.wakeOne();
return maxlen;
}
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 4d4cccd7b1..b624c3880e 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -1395,6 +1395,8 @@ bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
Note that the destroyed() signal will be emitted even if the signals
for this object have been blocked.
+ Signals emitted while being blocked are not buffered.
+
\sa signalsBlocked()
*/
diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp
index dd8f385c82..fa40b743d3 100644
--- a/src/corelib/mimetypes/qmimeprovider.cpp
+++ b/src/corelib/mimetypes/qmimeprovider.cpp
@@ -79,10 +79,9 @@ Q_CORE_EXPORT int qmime_secondsBetweenChecks = 5; // exported for the unit test
bool QMimeProviderBase::shouldCheck()
{
- const QDateTime now = QDateTime::currentDateTime();
- if (m_lastCheck.isValid() && m_lastCheck.secsTo(now) < qmime_secondsBetweenChecks)
+ if (m_lastCheck.isValid() && m_lastCheck.elapsed() < qmime_secondsBetweenChecks * 1000)
return false;
- m_lastCheck = now;
+ m_lastCheck.start();
return true;
}
@@ -562,10 +561,13 @@ void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
// load comment and globPatterns
const QString file = data.name + QLatin1String(".xml");
- const QStringList mimeFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QString::fromLatin1("mime/") + file);
+ // shared-mime-info since 1.3 lowercases the xml files
+ QStringList mimeFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QString::fromLatin1("mime/") + file.toLower());
if (mimeFiles.isEmpty()) {
- // TODO: ask Thiago about this
- qWarning() << "No file found for" << file << ", even though the file appeared in a directory listing.";
+ mimeFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QString::fromLatin1("mime/") + file); // pre-1.3
+ }
+ if (mimeFiles.isEmpty()) {
+ qWarning() << "No file found for" << file << ", even though update-mime-info said it would exist.";
qWarning() << "Either it was just removed, or the directory doesn't have executable permission...";
qWarning() << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime"), QStandardPaths::LocateDirectory);
return;
@@ -626,7 +628,7 @@ void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
// Let's assume that shared-mime-info is at least version 0.70
// Otherwise we would need 1) a version check, and 2) code for parsing patterns from the globs file.
#if 1
- if (!mainPattern.isEmpty() && data.globPatterns.first() != mainPattern) {
+ if (!mainPattern.isEmpty() && (data.globPatterns.isEmpty() || data.globPatterns.first() != mainPattern)) {
// ensure it's first in the list of patterns
data.globPatterns.removeAll(mainPattern);
data.globPatterns.prepend(mainPattern);
diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h
index 5a89ac23c3..eaf95942f7 100644
--- a/src/corelib/mimetypes/qmimeprovider_p.h
+++ b/src/corelib/mimetypes/qmimeprovider_p.h
@@ -51,6 +51,7 @@
#include <QtCore/qdatetime.h>
#include <QtCore/qset.h>
+#include <QtCore/qelapsedtimer.h>
QT_BEGIN_NAMESPACE
@@ -77,7 +78,7 @@ public:
QMimeDatabasePrivate *m_db;
protected:
bool shouldCheck();
- QDateTime m_lastCheck;
+ QElapsedTimer m_lastCheck;
};
/*
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index 002a9cc7bc..3269ee3ae8 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -563,7 +563,28 @@ const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = {
};
typedef QFreeList<QMutexPrivate, FreeListConstants> FreeList;
-Q_GLOBAL_STATIC(FreeList, freelist);
+// We cannot use Q_GLOBAL_STATIC because it uses QMutex
+#if defined(Q_COMPILER_THREADSAFE_STATICS)
+FreeList *freelist()
+{
+ static FreeList list;
+ return &list;
+}
+#else
+FreeList *freelist()
+{
+ static QAtomicPointer<FreeList> list;
+ FreeList *local = list.loadAcquire();
+ if (!local) {
+ local = new FreeList;
+ if (!list.testAndSetRelease(0, local)) {
+ delete local;
+ local = list.loadAcquire();
+ }
+ }
+ return local;
+}
+#endif
}
QMutexPrivate *QMutexPrivate::allocate()
diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri
index 3c1ddd984a..2cb00a6cf4 100644
--- a/src/corelib/thread/thread.pri
+++ b/src/corelib/thread/thread.pri
@@ -46,21 +46,21 @@ SOURCES += thread/qatomic.cpp \
unix:SOURCES += thread/qthread_unix.cpp \
thread/qwaitcondition_unix.cpp
-win32:SOURCES += thread/qmutex_win.cpp \
- thread/qthread_win.cpp \
+win32:SOURCES += thread/qthread_win.cpp \
thread/qwaitcondition_win.cpp
-integrity:SOURCES += thread/qmutex_unix.cpp \
- thread/qthread_unix.cpp \
+integrity:SOURCES += thread/qthread_unix.cpp \
thread/qwaitcondition_unix.cpp
-unix: {
- mac {
- SOURCES += thread/qmutex_mac.cpp
- } else:linux-*:!linux-lsb-* {
- SOURCES += thread/qmutex_linux.cpp
- } else {
- SOURCES += thread/qmutex_unix.cpp
- }
+false {
+ # files #included by others, but listed here so IDEs parsing this file know
+ # they are part of QtCore. Usually, qmake can find out that certain files
+ # are #included by others and thus remove from SOURCES, but it gets lost
+ # with qmutex.cpp.
+ SOURCES += \
+ thread/qmutex_linux.cpp \
+ thread/qmutex_mac.cpp \
+ thread/qmutex_unix.cpp \
+ thread/qmutex_win.cpp
}
diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp
index e6c246e8e6..5469eee14d 100644
--- a/src/corelib/tools/qchar.cpp
+++ b/src/corelib/tools/qchar.cpp
@@ -598,12 +598,22 @@ QT_BEGIN_NAMESPACE
\fn QChar::QChar(char ch)
Constructs a QChar corresponding to ASCII/Latin-1 character \a ch.
+
+ \note This constructor is not available when \c QT_NO_CAST_FROM_ASCII
+ is defined.
+
+ \sa QT_NO_CAST_FROM_ASCII
*/
/*!
\fn QChar::QChar(uchar ch)
Constructs a QChar corresponding to ASCII/Latin-1 character \a ch.
+
+ \note This constructor is not available when \c QT_NO_CAST_FROM_ASCII
+ is defined.
+
+ \sa QT_NO_CAST_FROM_ASCII
*/
/*!
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index e445055e1d..eb4eff32b4 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -1681,6 +1681,7 @@ bool QTime::setHMS(int h, int m, int s, int ms)
QTime QTime::addSecs(int s) const
{
+ s %= SECS_PER_DAY;
return addMSecs(s * 1000);
}
diff --git a/src/corelib/tools/qelapsedtimer_mac.cpp b/src/corelib/tools/qelapsedtimer_mac.cpp
index a355bf03e8..e946ac096f 100644
--- a/src/corelib/tools/qelapsedtimer_mac.cpp
+++ b/src/corelib/tools/qelapsedtimer_mac.cpp
@@ -59,8 +59,13 @@ static qint64 absoluteToNSecs(qint64 cpuTime)
{
if (info.denom == 0)
mach_timebase_info(&info);
+#ifdef __LP64__
+ __uint128_t nsecs = static_cast<__uint128_t>(cpuTime) * info.numer / info.denom;
+ return static_cast<qint64>(nsecs);
+#else
qint64 nsecs = cpuTime * info.numer / info.denom;
return nsecs;
+#endif
}
static qint64 absoluteToMSecs(qint64 cpuTime)
diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp
index 8000dc8688..c52e4b5a7c 100644
--- a/src/corelib/tools/qregexp.cpp
+++ b/src/corelib/tools/qregexp.cpp
@@ -116,6 +116,10 @@ int qFindString(const QChar *haystack, int haystackLen, int from,
A good text on regexps is \e {Mastering Regular Expressions}
(Third Edition) by Jeffrey E. F. Friedl, ISBN 0-596-52812-4.
+ \note In Qt 5, the new QRegularExpression class provides a Perl
+ compatible implementation of regular expressions and is recommended
+ in place of QRegExp.
+
\tableofcontents
\section1 Introduction
diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp
index 88a048d826..d8b0bf6e9f 100644
--- a/src/corelib/tools/qregularexpression.cpp
+++ b/src/corelib/tools/qregularexpression.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>.
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+** Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>.
+** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
@@ -1326,48 +1326,45 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
int * const captureOffsets = priv->capturedOffsets.data();
const int captureOffsetsCount = priv->capturedOffsets.size();
- int realOffset = offset + subjectStart;
- const int realSubjectLength = subjectLength + subjectStart;
-
- const unsigned short * const subjectUtf16 = subject.utf16();
+ const unsigned short * const subjectUtf16 = subject.utf16() + subjectStart;
int result;
if (!previousMatchWasEmpty) {
result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, realSubjectLength,
- realOffset, pcreOptions,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
captureOffsets, captureOffsetsCount);
} else {
result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, realSubjectLength,
- realOffset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED,
captureOffsets, captureOffsetsCount);
if (result == PCRE_ERROR_NOMATCH) {
- ++realOffset;
+ ++offset;
if (usingCrLfNewlines
- && realOffset < realSubjectLength
- && subjectUtf16[realOffset - 1] == QLatin1Char('\r')
- && subjectUtf16[realOffset] == QLatin1Char('\n')) {
- ++realOffset;
- } else if (realOffset < realSubjectLength
- && QChar::isLowSurrogate(subjectUtf16[realOffset])) {
- ++realOffset;
+ && offset < subjectLength
+ && subjectUtf16[offset - 1] == QLatin1Char('\r')
+ && subjectUtf16[offset] == QLatin1Char('\n')) {
+ ++offset;
+ } else if (offset < subjectLength
+ && QChar::isLowSurrogate(subjectUtf16[offset])) {
+ ++offset;
}
result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, realSubjectLength,
- realOffset, pcreOptions,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
captureOffsets, captureOffsetsCount);
}
}
#ifdef QREGULAREXPRESSION_DEBUG
qDebug() << "Matching" << pattern << "against" << subject
- << "starting at" << subjectStart << "len" << subjectLength << "real len" << realSubjectLength
- << "offset" << offset << "real offset" << realOffset
+ << "starting at" << subjectStart << "len" << subjectLength
+ << "offset" << offset
<< matchType << matchOptions << previousMatchWasEmpty
<< "result" << result;
#endif
@@ -2057,7 +2054,7 @@ QString QRegularExpressionMatch::captured(int nth) const
if (start == -1) // didn't capture
return QString();
- return d->subject.mid(start, capturedLength(nth));
+ return d->subject.mid(start + d->subjectStart, capturedLength(nth));
}
/*!
@@ -2078,7 +2075,7 @@ QStringRef QRegularExpressionMatch::capturedRef(int nth) const
if (start == -1) // didn't capture
return QStringRef();
- return d->subject.midRef(start, capturedLength(nth));
+ return d->subject.midRef(start + d->subjectStart, capturedLength(nth));
}
/*!
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index f124cede36..ef12b23caa 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -212,6 +212,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
int blue_scale = 0;
int alpha_scale = 0;
+ if (!d->isSequential())
+ d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4 ? BMP_WIN : bi.biSize)); // goto start of colormap or masks
+
if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
return false;
@@ -299,9 +302,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
image.setDotsPerMeterX(bi.biXPelsPerMeter);
image.setDotsPerMeterY(bi.biYPelsPerMeter);
- if (!d->isSequential())
- d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
-
if (ncols > 0) { // read color table
uchar rgb[4];
int rgb_len = t == BMP_OLD ? 3 : 4;
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index aea6fc133f..045e36323f 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -4237,9 +4237,6 @@ QImage QImage::alphaChannel() const
if (!d)
return QImage();
- if (d->format == QImage::Format_Alpha8)
- return *this;
-
int w = d->width;
int h = d->height;
@@ -4269,6 +4266,10 @@ QImage QImage::alphaChannel() const
src_data += d->bytes_per_line;
dest_data += image.d->bytes_per_line;
}
+ } else if (d->format == Format_Alpha8) {
+ const uchar *src_data = d->data;
+ uchar *dest_data = image.d->data;
+ memcpy(dest_data, src_data, d->bytes_per_line * h);
} else {
QImage alpha32 = *this;
bool canSkipConversion = (d->format == Format_ARGB32 || d->format == Format_ARGB32_Premultiplied);
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 5e2a5b86a4..d0aab734dd 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -449,8 +449,7 @@ static QWindowGeometrySpecification windowGeometrySpecification;
\row
\li Miscellaneous
\li startingUp(),
- closingDown(),
- type().
+ closingDown().
\endtable
\sa QCoreApplication, QAbstractEventDispatcher, QEventLoop
diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp
index 0ff5c36119..3e267f2e0b 100644
--- a/src/gui/kernel/qshortcutmap.cpp
+++ b/src/gui/kernel/qshortcutmap.cpp
@@ -386,9 +386,7 @@ QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e)
result = find(e);
if (result == QKeySequence::NoMatch && (e->modifiers() & Qt::KeypadModifier)) {
// Try to find a match without keypad modifier
- QKeyEvent event = *e;
- event.setModifiers(e->modifiers() & ~Qt::KeypadModifier);
- result = find(&event);
+ result = find(e, Qt::KeypadModifier);
}
if (result == QKeySequence::NoMatch && e->modifiers() & Qt::ShiftModifier) {
// If Shift + Key_Backtab, also try Shift + Qt::Key_Tab
@@ -441,13 +439,13 @@ bool QShortcutMap::hasShortcutForKeySequence(const QKeySequence &seq) const
which can be access through matches().
\sa matches
*/
-QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e)
+QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifiers)
{
Q_D(QShortcutMap);
if (!d->sequences.count())
return QKeySequence::NoMatch;
- createNewSequences(e, d->newEntries);
+ createNewSequences(e, d->newEntries, ignoredModifiers);
#if defined(DEBUG_QSHORTCUTMAP)
qDebug() << "Possible shortcut key sequences:" << d->newEntries;
#endif
@@ -549,7 +547,7 @@ void QShortcutMap::clearSequence(QVector<QKeySequence> &ksl)
Alters \a seq to the new sequence state, based on the
current sequence state, and the new key event \a e.
*/
-void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl)
+void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl, int ignoredModifiers)
{
Q_D(QShortcutMap);
QList<int> possibleKeys = QKeyMapper::possibleKeys(e);
@@ -579,7 +577,7 @@ void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl)
curKsl.setKey(0, 2);
curKsl.setKey(0, 3);
}
- curKsl.setKey(possibleKeys.at(pkNum), index);
+ curKsl.setKey(possibleKeys.at(pkNum) & ~ignoredModifiers, index);
}
}
}
diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h
index 242c021ca4..2376d27c78 100644
--- a/src/gui/kernel/qshortcutmap_p.h
+++ b/src/gui/kernel/qshortcutmap_p.h
@@ -88,10 +88,10 @@ private:
QKeySequence::SequenceMatch state();
void dispatchEvent(QKeyEvent *e);
- QKeySequence::SequenceMatch find(QKeyEvent *e);
+ QKeySequence::SequenceMatch find(QKeyEvent *e, int ignoredModifiers = 0);
QKeySequence::SequenceMatch matches(const QKeySequence &seq1, const QKeySequence &seq2) const;
QVector<const QShortcutEntry *> matches() const;
- void createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl);
+ void createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl, int ignoredModifiers);
void clearSequence(QVector<QKeySequence> &ksl);
int translateModifiers(Qt::KeyboardModifiers modifiers);
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp
index 41d53be31e..9714aa4bec 100644
--- a/src/gui/opengl/qopenglshaderprogram.cpp
+++ b/src/gui/opengl/qopenglshaderprogram.cpp
@@ -525,7 +525,8 @@ bool QOpenGLShader::compileSourceCode(const char *source)
// The precision qualifiers are useful on OpenGL/ES systems,
// but usually not present on desktop systems.
- const QSurfaceFormat currentSurfaceFormat = QOpenGLContext::currentContext()->format();
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ const QSurfaceFormat currentSurfaceFormat = ctx->format();
QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(QOpenGLContext::currentContext());
if (currentSurfaceFormat.renderableType() == QSurfaceFormat::OpenGL
|| ctx_d->workaround_missingPrecisionQualifiers
@@ -545,10 +546,16 @@ bool QOpenGLShader::compileSourceCode(const char *source)
}
#endif
- // Append #line directive in order to compensate for text insertion
- QByteArray lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8();
- sourceChunks.append(lineDirective.constData());
- sourceChunkLengths.append(GLint(lineDirective.length()));
+ QByteArray lineDirective;
+ // #line is rejected by some drivers:
+ // "2.1 Mesa 8.1-devel (git-48a3d4e)" or "MESA 2.1 Mesa 8.1-devel"
+ const char *version = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VERSION));
+ if (!version || !strstr(version, "2.1 Mesa 8")) {
+ // Append #line directive in order to compensate for text insertion
+ lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8();
+ sourceChunks.append(lineDirective.constData());
+ sourceChunkLengths.append(GLint(lineDirective.length()));
+ }
// Append rest of shader code
sourceChunks.append(source + versionDirectivePosition.position);
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp
index 7b6a71737d..33dccc5374 100644
--- a/src/gui/painting/qimagescale.cpp
+++ b/src/gui/painting/qimagescale.cpp
@@ -305,7 +305,10 @@ static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest,
for (int x = 0; x < dw; x++) {
const unsigned int *pix = sptr + xpoints[x];
const int xap = xapoints[x];
- *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap);
+ if (xap > 0)
+ *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
dptr++;
}
}
diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp
index 75bf31cde1..34d72bf493 100644
--- a/src/gui/painting/qrasterizer.cpp
+++ b/src/gui/painting/qrasterizer.cpp
@@ -863,8 +863,8 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
const Q16Dot16 iLeft = int(left);
const Q16Dot16 iRight = int(right);
const Q16Dot16 leftWidth = IntToQ16Dot16(iLeft + 1)
- - FloatToQ16Dot16(left);
- const Q16Dot16 rightWidth = FloatToQ16Dot16(right)
+ - qSafeFloatToQ16Dot16(left);
+ const Q16Dot16 rightWidth = qSafeFloatToQ16Dot16(right)
- IntToQ16Dot16(iRight);
Q16Dot16 coverage[3];
@@ -898,8 +898,8 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
const Q16Dot16 iTopFP = IntToQ16Dot16(int(pa.y()));
const Q16Dot16 iBottomFP = IntToQ16Dot16(int(pb.y()));
- const Q16Dot16 yPa = FloatToQ16Dot16(pa.y());
- const Q16Dot16 yPb = FloatToQ16Dot16(pb.y());
+ const Q16Dot16 yPa = qSafeFloatToQ16Dot16(pa.y());
+ const Q16Dot16 yPb = qSafeFloatToQ16Dot16(pb.y());
for (Q16Dot16 yFP = iTopFP; yFP <= iBottomFP; yFP += Q16Dot16Factor) {
const Q16Dot16 rowHeight = qMin(yFP + Q16Dot16Factor, yPb)
- qMax(yFP, yPa);
@@ -983,16 +983,16 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
const Q16Dot16 iRightFP = IntToQ16Dot16(int(right.y()));
const Q16Dot16 iBottomFP = IntToQ16Dot16(int(bottomBound));
- Q16Dot16 leftIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topLeftSlope);
- Q16Dot16 rightIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topRightSlope);
+ Q16Dot16 leftIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topLeftSlope);
+ Q16Dot16 rightIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topRightSlope);
Q16Dot16 leftIntersectBf = 0;
Q16Dot16 rightIntersectBf = 0;
if (iLeftFP < iTopFP)
- leftIntersectBf = FloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope);
+ leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope);
if (iRightFP < iTopFP)
- rightIntersectBf = FloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope);
+ rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope);
Q16Dot16 rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
Q16Dot16 topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
@@ -1000,10 +1000,10 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
int leftMin, leftMax, rightMin, rightMax;
- const Q16Dot16 yTopFP = FloatToQ16Dot16(top.y());
- const Q16Dot16 yLeftFP = FloatToQ16Dot16(left.y());
- const Q16Dot16 yRightFP = FloatToQ16Dot16(right.y());
- const Q16Dot16 yBottomFP = FloatToQ16Dot16(bottom.y());
+ const Q16Dot16 yTopFP = qSafeFloatToQ16Dot16(top.y());
+ const Q16Dot16 yLeftFP = qSafeFloatToQ16Dot16(left.y());
+ const Q16Dot16 yRightFP = qSafeFloatToQ16Dot16(right.y());
+ const Q16Dot16 yBottomFP = qSafeFloatToQ16Dot16(bottom.y());
rowTop = qMax(iTopFP, yTopFP);
topLeftIntersectAf = leftIntersectAf +
@@ -1021,7 +1021,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
if (yFP == iLeftFP) {
const int y = Q16Dot16ToInt(yFP);
- leftIntersectBf = FloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope);
+ leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope);
topLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowTopLeft - yFP);
bottomLeftIntersectAf = leftIntersectAf + Q16Dot16Multiply(topLeftSlopeFP, rowBottomLeft - yFP);
} else {
@@ -1031,7 +1031,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
if (yFP == iRightFP) {
const int y = Q16Dot16ToInt(yFP);
- rightIntersectBf = FloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope);
+ rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope);
topRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowTopRight - yFP);
bottomRightIntersectAf = rightIntersectAf + Q16Dot16Multiply(topRightSlopeFP, rowBottomRight - yFP);
} else {
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index f9d924d10a..2087bad9f6 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -74,6 +74,16 @@ static inline bool qtransform_equals_no_translate(const QTransform &a, const QTr
}
}
+template<typename T>
+static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *output)
+{
+ if (source + sizeof(T) > end)
+ return false;
+
+ *output = qFromBigEndian<T>(source);
+ return true;
+}
+
// Harfbuzz helper functions
#ifdef QT_ENABLE_HARFBUZZ_NG
@@ -1039,26 +1049,38 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
return;
const uchar *table = reinterpret_cast<const uchar *>(tab.constData());
+ const uchar *end = table + tab.size();
+
+ quint16 version;
+ if (!qSafeFromBigEndian(table, end, &version))
+ return;
- unsigned short version = qFromBigEndian<quint16>(table);
if (version != 0) {
// qDebug("wrong version");
return;
}
- unsigned short numTables = qFromBigEndian<quint16>(table + 2);
+ quint16 numTables;
+ if (!qSafeFromBigEndian(table + 2, end, &numTables))
+ return;
+
{
int offset = 4;
for(int i = 0; i < numTables; ++i) {
- if (offset + 6 > tab.size()) {
-// qDebug("offset out of bounds");
- goto end;
- }
const uchar *header = table + offset;
- ushort version = qFromBigEndian<quint16>(header);
- ushort length = qFromBigEndian<quint16>(header+2);
- ushort coverage = qFromBigEndian<quint16>(header+4);
+ quint16 version;
+ if (!qSafeFromBigEndian(header, end, &version))
+ goto end;
+
+ quint16 length;
+ if (!qSafeFromBigEndian(header + 2, end, &length))
+ goto end;
+
+ quint16 coverage;
+ if (!qSafeFromBigEndian(header + 4, end, &coverage))
+ goto end;
+
// qDebug("subtable: version=%d, coverage=%x",version, coverage);
if(version == 0 && coverage == 0x0001) {
if (offset + length > tab.size()) {
@@ -1067,7 +1089,10 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
}
const uchar *data = table + offset + 6;
- ushort nPairs = qFromBigEndian<quint16>(data);
+ quint16 nPairs;
+ if (!qSafeFromBigEndian(data, end, &nPairs))
+ goto end;
+
if(nPairs * 6 + 8 > length - 6) {
// qDebug("corrupt table!");
// corrupt table
@@ -1077,8 +1102,21 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
int off = 8;
for(int i = 0; i < nPairs; ++i) {
QFontEngine::KernPair p;
- p.left_right = (((uint)qFromBigEndian<quint16>(data+off)) << 16) + qFromBigEndian<quint16>(data+off+2);
- p.adjust = QFixed(((int)(short)qFromBigEndian<quint16>(data+off+4))) / scalingFactor;
+
+ quint16 tmp;
+ if (!qSafeFromBigEndian(data + off, end, &tmp))
+ goto end;
+
+ p.left_right = uint(tmp) << 16;
+ if (!qSafeFromBigEndian(data + off + 2, end, &tmp))
+ goto end;
+
+ p.left_right |= tmp;
+
+ if (!qSafeFromBigEndian(data + off + 4, end, &tmp))
+ goto end;
+
+ p.adjust = QFixed(int(short(tmp))) / scalingFactor;
kerning_pairs.append(p);
off += 6;
}
@@ -1098,26 +1136,31 @@ int QFontEngine::glyphCount() const
QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
if (maxpTable.size() < 6)
return 0;
- return qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(maxpTable.constData() + 4));
+
+ const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4);
+ const uchar *end = source + maxpTable.size();
+
+ quint16 count = 0;
+ qSafeFromBigEndian(source, end, &count);
+ return count;
}
const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
{
const uchar *header = table;
- if (tableSize < 4)
- return 0;
-
const uchar *endPtr = table + tableSize;
// version check
- if (qFromBigEndian<quint16>(header) != 0)
+ quint16 version;
+ if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0)
return 0;
- unsigned short numTables = qFromBigEndian<quint16>(header + 2);
- const uchar *maps = table + 4;
- if (maps + 8 * numTables > endPtr)
+ quint16 numTables;
+ if (!qSafeFromBigEndian(header + 2, endPtr, &numTables))
return 0;
+ const uchar *maps = table + 4;
+
enum {
Invalid,
AppleRoman,
@@ -1132,8 +1175,14 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
int tableToUse = -1;
int score = Invalid;
for (int n = 0; n < numTables; ++n) {
- const quint16 platformId = qFromBigEndian<quint16>(maps + 8 * n);
- const quint16 platformSpecificId = qFromBigEndian<quint16>(maps + 8 * n + 2);
+ quint16 platformId;
+ if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
+ return 0;
+
+ quint16 platformSpecificId;
+ if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))
+ return 0;
+
switch (platformId) {
case 0: // Unicode
if (score < Unicode &&
@@ -1187,20 +1236,30 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
resolveTable:
*isSymbolFont = (symbolTable > -1);
- unsigned int unicode_table = qFromBigEndian<quint32>(maps + 8*tableToUse + 4);
+ quint32 unicode_table;
+ if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))
+ return 0;
- if (!unicode_table || unicode_table + 8 > tableSize)
+ if (!unicode_table)
return 0;
// get the header of the unicode table
header = table + unicode_table;
- unsigned short format = qFromBigEndian<quint16>(header);
- unsigned int length;
- if(format < 8)
- length = qFromBigEndian<quint16>(header + 2);
- else
- length = qFromBigEndian<quint32>(header + 4);
+ quint16 format;
+ if (!qSafeFromBigEndian(header, endPtr, &format))
+ return 0;
+
+ quint32 length;
+ if (format < 8) {
+ quint16 tmp;
+ if (!qSafeFromBigEndian(header + 2, endPtr, &tmp))
+ return 0;
+ length = tmp;
+ } else {
+ if (!qSafeFromBigEndian(header + 4, endPtr, &length))
+ return 0;
+ }
if (table + unicode_table + length > endPtr)
return 0;
@@ -1215,7 +1274,7 @@ resolveTable:
// Check that none of the latin1 range are in the unicode table
bool unicodeTableHasLatin1 = false;
for (int uc=0x00; uc<0x100; ++uc) {
- if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
+ if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
unicodeTableHasLatin1 = true;
break;
}
@@ -1225,7 +1284,7 @@ resolveTable:
bool unicodeTableHasSymbols = false;
if (!unicodeTableHasLatin1) {
for (int uc=0xf000; uc<0xf100; ++uc) {
- if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
+ if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
unicodeTableHasSymbols = true;
break;
}
@@ -1243,12 +1302,17 @@ resolveTable:
return table + unicode_table;
}
-quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
+quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
{
- unsigned short format = qFromBigEndian<quint16>(cmap);
+ const uchar *end = cmap + cmapSize;
+ quint16 format;
+ if (!qSafeFromBigEndian(cmap, end, &format))
+ return 0;
+
if (format == 0) {
- if (unicode < 256)
- return (int) *(cmap+6+unicode);
+ const uchar *ptr = cmap + 6 + unicode;
+ if (unicode < 256 && ptr < end)
+ return quint32(*ptr);
} else if (format == 4) {
/* some fonts come with invalid cmap tables, where the last segment
specified end = start = rangeoffset = 0xffff, delta = 0x0001
@@ -1257,25 +1321,49 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
*/
if(unicode >= 0xffff)
return 0;
- quint16 segCountX2 = qFromBigEndian<quint16>(cmap + 6);
+
+ quint16 segCountX2;
+ if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
+ return 0;
+
const unsigned char *ends = cmap + 14;
+
int i = 0;
- for (; i < segCountX2/2 && qFromBigEndian<quint16>(ends + 2*i) < unicode; i++) {}
+ for (; i < segCountX2/2; ++i) {
+ quint16 codePoint;
+ if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
+ return 0;
+ if (codePoint >= unicode)
+ break;
+ }
const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
- quint16 startIndex = qFromBigEndian<quint16>(idx);
+ quint16 startIndex;
+ if (!qSafeFromBigEndian(idx, end, &startIndex))
+ return 0;
if (startIndex > unicode)
return 0;
idx += segCountX2;
- qint16 idDelta = (qint16)qFromBigEndian<quint16>(idx);
+
+ quint16 tmp;
+ if (!qSafeFromBigEndian(idx, end, &tmp))
+ return 0;
+ qint16 idDelta = qint16(tmp);
+
idx += segCountX2;
- quint16 idRangeoffset_t = (quint16)qFromBigEndian<quint16>(idx);
+
+ quint16 idRangeoffset_t;
+ if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
+ return 0;
quint16 glyphIndex;
if (idRangeoffset_t) {
- quint16 id = qFromBigEndian<quint16>(idRangeoffset_t + 2*(unicode - startIndex) + idx);
+ quint16 id;
+ if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
+ return 0;
+
if (id)
glyphIndex = (idDelta + id) % 0x10000;
else
@@ -1285,13 +1373,19 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
}
return glyphIndex;
} else if (format == 6) {
- quint16 tableSize = qFromBigEndian<quint16>(cmap + 2);
+ quint16 tableSize;
+ if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
+ return 0;
- quint16 firstCode6 = qFromBigEndian<quint16>(cmap + 6);
+ quint16 firstCode6;
+ if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
+ return 0;
if (unicode < firstCode6)
return 0;
- quint16 entryCount6 = qFromBigEndian<quint16>(cmap + 8);
+ quint16 entryCount6;
+ if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
+ return 0;
if (entryCount6 * 2 + 10 > tableSize)
return 0;
@@ -1300,9 +1394,14 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
return 0;
quint16 entryIndex6 = unicode - firstCode6;
- return qFromBigEndian<quint16>(cmap + 10 + (entryIndex6 * 2));
+
+ quint16 index = 0;
+ qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
+ return index;
} else if (format == 12) {
- quint32 nGroups = qFromBigEndian<quint32>(cmap + 12);
+ quint32 nGroups;
+ if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
+ return 0;
cmap += 16; // move to start of groups
@@ -1310,13 +1409,24 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
while (left <= right) {
int middle = left + ( ( right - left ) >> 1 );
- quint32 startCharCode = qFromBigEndian<quint32>(cmap + 12*middle);
+ quint32 startCharCode;
+ if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
+ return 0;
+
if(unicode < startCharCode)
right = middle - 1;
else {
- quint32 endCharCode = qFromBigEndian<quint32>(cmap + 12*middle + 4);
- if(unicode <= endCharCode)
- return qFromBigEndian<quint32>(cmap + 12*middle + 8) + unicode - startCharCode;
+ quint32 endCharCode;
+ if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
+ return 0;
+
+ if (unicode <= endCharCode) {
+ quint32 index;
+ if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
+ return 0;
+
+ return index + unicode - startCharCode;
+ }
left = middle + 1;
}
}
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 5329a5f11a..780104bc37 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -240,7 +240,7 @@ public:
QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform) const;
static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
- static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode);
+ static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode);
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily);
diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp
index a678b4c8ea..f2e05631a3 100644
--- a/src/gui/text/qfontengine_qpf2.cpp
+++ b/src/gui/text/qfontengine_qpf2.cpp
@@ -322,9 +322,9 @@ bool QFontEngineQPF2::getSfntTableData(uint tag, uchar *buffer, uint *length) co
glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const
{
- glyph_t glyph = getTrueTypeGlyphIndex(cmap, ucs4);
+ glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
if (glyph == 0 && symbol && ucs4 < 0x100)
- glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
if (!findGlyph(glyph))
glyph = 0;
@@ -348,16 +348,16 @@ bool QFontEngineQPF2::stringToCMap(const QChar *str, int len, QGlyphLayout *glyp
QStringIterator it(str, str + len);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
++glyph_pos;
}
} else {
QStringIterator it(str, str + len);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
#if 0 && defined(DEBUG_FONTENGINE)
QChar c(uc);
if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index d56b9cf1b1..0c729c74d1 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1656,8 +1656,8 @@ namespace {
bool checkFullOtherwiseExtend(QScriptLine &line);
QFixed calculateNewWidth(const QScriptLine &line) const {
- return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth
- - qMin(rightBearing, QFixed());
+ return line.textWidth + tmpData.textWidth + spaceData.textWidth
+ + softHyphenWidth + negativeRightBearing();
}
inline glyph_t currentGlyph() const
@@ -1677,33 +1677,51 @@ namespace {
}
}
- inline void adjustRightBearing(glyph_t glyph)
+ inline void calculateRightBearing(glyph_t glyph)
{
qreal rb;
fontEngine->getGlyphBearings(glyph, 0, &rb);
- rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
+
+ // We only care about negative right bearings, so we limit the range
+ // of the bearing here so that we can assume it's negative in the rest
+ // of the code, as well ase use QFixed(1) as a sentinel to represent
+ // the state where we have yet to compute the right bearing.
+ rightBearing = qMin(QFixed::fromReal(rb), QFixed(0));
}
- inline void adjustRightBearing()
+ inline void calculateRightBearing()
{
if (currentPosition <= 0)
return;
- adjustRightBearing(currentGlyph());
+ calculateRightBearing(currentGlyph());
}
- inline void adjustPreviousRightBearing()
+ inline void calculateRightBearingForPreviousGlyph()
{
if (previousGlyph > 0)
- adjustRightBearing(previousGlyph);
+ calculateRightBearing(previousGlyph);
}
+ static const QFixed RightBearingNotCalculated;
+
inline void resetRightBearing()
{
- rightBearing = QFixed(1); // Any positive number is defined as invalid since only
- // negative right bearings are interesting to us.
+ rightBearing = RightBearingNotCalculated;
+ }
+
+ // We express the negative right bearing as an absolute number
+ // so that it can be applied to the width using addition.
+ inline QFixed negativeRightBearing() const
+ {
+ if (rightBearing == RightBearingNotCalculated)
+ return QFixed(0);
+
+ return qAbs(rightBearing);
}
};
+const QFixed LineBreakHelper::RightBearingNotCalculated = QFixed(1);
+
inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
{
LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
@@ -1856,7 +1874,7 @@ void QTextLine::layout_helper(int maxGlyphs)
current, lbh.logClusters, lbh.glyphs);
} else {
lbh.tmpData.length++;
- lbh.adjustPreviousRightBearing();
+ lbh.calculateRightBearingForPreviousGlyph();
}
line += lbh.tmpData;
goto found;
@@ -1938,22 +1956,29 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]];
}
- // The actual width of the text needs to take the right bearing into account. The
- // right bearing is left-ward, which means that if the rightmost pixel is to the right
- // of the advance of the glyph, the bearing will be negative. We flip the sign
- // for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
- // We ignore the right bearing if the minimum negative bearing is too little to
- // expand the text beyond the edge.
if (sb_or_ws|breakany) {
- QFixed rightBearing = lbh.rightBearing; // store previous right bearing
+ // To compute the final width of the text we need to take negative right bearing
+ // into account (negative right bearing means the glyph has pixel data past the
+ // advance length). Note that the negative right bearing is an absolute number,
+ // so that we can apply it to the width using straight forward addition.
+
+ // Store previous right bearing (for the already accepted glyph) in case we
+ // end up breaking due to the current glyph being too wide.
+ QFixed previousRightBearing = lbh.rightBearing;
+
+ // We ignore the right bearing if the minimum negative bearing is too little to
+ // expand the text beyond the edge.
if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
- lbh.adjustRightBearing();
+ lbh.calculateRightBearing();
+
if (lbh.checkFullOtherwiseExtend(line)) {
- // we are too wide, fix right bearing
- if (rightBearing <= 0)
- lbh.rightBearing = rightBearing; // take from cache
+ // We are too wide to accept the next glyph with its bearing, so we restore the
+ // right bearing to that of the previous glyph (the one that was already accepted),
+ // so that the bearing can be be applied to the final width of the text below.
+ if (previousRightBearing != LineBreakHelper::RightBearingNotCalculated)
+ lbh.rightBearing = previousRightBearing;
else
- lbh.adjustPreviousRightBearing();
+ lbh.calculateRightBearingForPreviousGlyph();
if (!breakany) {
line.textWidth += lbh.softHyphenWidth;
@@ -1970,10 +1995,14 @@ void QTextLine::layout_helper(int maxGlyphs)
LB_DEBUG("reached end of line");
lbh.checkFullOtherwiseExtend(line);
found:
- if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
- lbh.adjustRightBearing();
line.textAdvance = line.textWidth;
- line.textWidth -= qMin(QFixed(), lbh.rightBearing);
+
+ // If right bearing has not been calculated yet, do that now
+ if (lbh.rightBearing == LineBreakHelper::RightBearingNotCalculated && !lbh.whiteSpaceOrObject)
+ lbh.calculateRightBearing();
+
+ // Then apply any negative right bearing
+ line.textWidth += lbh.negativeRightBearing();
if (line.length == 0) {
LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f",
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 16ed67fbc0..c2d986ef3d 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -971,7 +971,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
for (int i = 0; i < channelCount; ++i) {
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
channels[i].resendCurrent = false;
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
// if this is not possible, error will be emitted and connection terminated
if (!channels[i].resetUploadData())
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 98247b7df0..8980ed7a41 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
+// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
+// connection times out)
+// We use 3 because we can get a _q_error 3 times depending on the timing:
+static const int reconnectAttemptsDefault = 3;
+
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
: socket(0)
, ssl(false)
@@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
, resendCurrent(false)
, lastStatus(0)
, pendingEncrypt(false)
- , reconnectAttempts(2)
+ , reconnectAttempts(reconnectAttemptsDefault)
, authMethod(QAuthenticatorPrivate::None)
, proxyAuthMethod(QAuthenticatorPrivate::None)
, authenticationCredentialsSent(false)
@@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init()
socket->setProxy(QNetworkProxy::NoProxy);
#endif
- // We want all signals (except the interactive ones) be connected as QueuedConnection
- // because else we're falling into cases where we recurse back into the socket code
- // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
- // is safer.
+ // After some back and forth in all the last years, this is now a DirectConnection because otherwise
+ // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
+ // which behave slightly differently on Windows vs Linux
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(connected()),
this, SLOT(_q_connected()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(readyRead()),
this, SLOT(_q_readyRead()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
// The disconnected() and error() signals may already come
// while calling connectToHost().
@@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init()
qRegisterMetaType<QAbstractSocket::SocketError>();
QObject::connect(socket, SIGNAL(disconnected()),
this, SLOT(_q_disconnected()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(_q_error(QAbstractSocket::SocketError)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
#ifndef QT_NO_NETWORKPROXY
@@ -147,7 +151,7 @@ void QHttpNetworkConnectionChannel::init()
// won't be a sslSocket if encrypt is false
QObject::connect(sslSocket, SIGNAL(encrypted()),
this, SLOT(_q_encrypted()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(_q_sslErrors(QList<QSslError>)),
Qt::DirectConnection);
@@ -156,7 +160,7 @@ void QHttpNetworkConnectionChannel::init()
Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
this, SLOT(_q_encryptedBytesWritten(qint64)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
@@ -400,7 +404,7 @@ void QHttpNetworkConnectionChannel::allDone()
// reset the reconnection attempts after we receive a complete reply.
// in case of failures, each channel will attempt two reconnects before emitting error.
- reconnectAttempts = 2;
+ reconnectAttempts = reconnectAttemptsDefault;
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
if (state != QHttpNetworkConnectionChannel::ClosingState)
@@ -668,6 +672,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
+void QHttpNetworkConnectionChannel::resendCurrentRequest()
+{
+ requeueCurrentlyPipelinedRequests();
+ if (reply)
+ resendCurrent = true;
+ if (qobject_cast<QHttpNetworkConnection*>(connection))
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+}
+
bool QHttpNetworkConnectionChannel::isSocketBusy() const
{
return (state & QHttpNetworkConnectionChannel::BusyState);
@@ -711,8 +724,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
return;
}
- // read the available data before closing
- if (isSocketWaiting() || isSocketReading()) {
+ // read the available data before closing (also done in _q_error for other codepaths)
+ if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
if (reply) {
state = QHttpNetworkConnectionChannel::ReadingState;
_q_receiveReply();
@@ -724,7 +737,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
state = QHttpNetworkConnectionChannel::IdleState;
requeueCurrentlyPipelinedRequests();
- close();
+
+ pendingEncrypt = false;
}
@@ -806,11 +820,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
errorCode = QNetworkReply::ConnectionRefusedError;
break;
case QAbstractSocket::RemoteHostClosedError:
- // try to reconnect/resend before sending an error.
- // while "Reading" the _q_disconnected() will handle this.
- if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
+ // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
+ // The reconnectAttempts handling catches the cases where we can re-send the request.
+ if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
+ // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
+ // is sent on them. No need to error the other replies below. Just bail out here.
+ // The _q_disconnected will handle the possibly pipelined replies
+ return;
+ } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ // Try to reconnect/resend before sending an error.
+ // While "Reading" the _q_disconnected() will handle this.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
} else {
errorCode = QNetworkReply::RemoteHostClosedError;
@@ -821,11 +843,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
if (!reply->d_func()->expectContent()) {
// No content expected, this is a valid way to have the connection closed by the server
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
return;
}
if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
// There was no content-length header and it's not chunked encoding,
// so this is a valid way to have the connection closed by the server
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
return;
}
// ok, we got a disconnect even though we did not expect it
@@ -835,24 +861,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// we can ignore the readbuffersize as the data is already
// in memory and we will not receive more data on the socket.
reply->setReadBufferSize(0);
+ reply->setDownstreamLimited(false);
_q_receiveReply();
-#ifndef QT_NO_SSL
- if (ssl) {
- // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
- // So we need to check this if the socket is a QSslSocket. When the socket is flushed
- // it will force a decrypt of the encrypted data in the plainsocket.
- QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
- qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
- while (sslSocket->encryptedBytesAvailable()) {
- sslSocket->flush();
- _q_receiveReply();
- qint64 afterFlush = sslSocket->encryptedBytesAvailable();
- if (afterFlush == beforeFlush)
- break;
- beforeFlush = afterFlush;
- }
+ if (!reply) {
+ // No more reply assigned after the previous call? Then it had been finished successfully.
+ requeueCurrentlyPipelinedRequests();
+ state = QHttpNetworkConnectionChannel::IdleState;
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
}
-#endif
}
errorCode = QNetworkReply::RemoteHostClosedError;
@@ -863,7 +880,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::SocketTimeoutError:
// try to reconnect/resend before sending an error.
if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::TimeoutError;
@@ -877,7 +894,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionClosedError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyConnectionClosedError;
@@ -885,7 +902,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionTimeoutError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyTimeoutError;
@@ -933,8 +950,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
- if (that) //signal emission triggered event loop
- close();
+ if (that) {
+ //signal emission triggered event loop
+ if (!socket)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else if (socket->state() == QAbstractSocket::UnconnectedState)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else
+ state = QHttpNetworkConnectionChannel::ClosingState;
+
+ // pendingEncrypt must only be true in between connected and encrypted states
+ pendingEncrypt = false;
+ }
}
#ifndef QT_NO_NETWORKPROXY
@@ -958,7 +985,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor
void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
{
- sendRequest();
+ if (reply)
+ sendRequest();
}
#ifndef QT_NO_SSL
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 16d6c3b40f..37ad6c9b0a 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -169,6 +169,7 @@ public:
void handleUnexpectedEOF();
void closeAndResendCurrentRequest();
+ void resendCurrentRequest();
bool isSocketBusy() const;
bool isSocketWriting() const;
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 172d4dab5b..dd108ad5c7 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -208,7 +208,7 @@ QByteArray QHttpNetworkReply::readAny()
return QByteArray();
// we'll take the last buffer, so schedule another read from http
- if (d->downstreamLimited && d->responseData.bufferCount() == 1)
+ if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
d->connection->d_func()->readMoreLater(this);
return d->responseData.read();
}
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index 55187755bf..a2083158f1 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -237,7 +237,12 @@ void QHttpProtocolHandler::_q_readyRead()
}
if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
- m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
+ if (m_socket->bytesAvailable()) {
+ // We might get a spurious call from readMoreLater()
+ // call of the QHttpNetworkConnection even while the socket is disconnecting.
+ // Therefore check if there is actually bytes available before changing the channel state.
+ m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
+ }
if (m_reply)
_q_receiveReply();
}
@@ -250,7 +255,6 @@ bool QHttpProtocolHandler::sendRequest()
if (!m_reply) {
// heh, how should that happen!
qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
- m_channel->state = QHttpNetworkConnectionChannel::IdleState;
return false;
}
diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp
index 78d4970ca1..49daa22ec8 100644
--- a/src/network/bearer/qnetworkconfigmanager_p.cpp
+++ b/src/network/bearer/qnetworkconfigmanager_p.cpp
@@ -466,15 +466,18 @@ QList<QBearerEngine *> QNetworkConfigurationManagerPrivate::engines() const
void QNetworkConfigurationManagerPrivate::startPolling()
{
QMutexLocker locker(&mutex);
-
- if(!pollTimer) {
+ if (!pollTimer) {
pollTimer = new QTimer(this);
- pollTimer->setInterval(10000);
+ bool ok;
+ int interval = qgetenv("QT_BEARER_POLL_TIMEOUT").toInt(&ok);
+ if (!ok)
+ interval = 10000;//default 10 seconds
+ pollTimer->setInterval(interval);
pollTimer->setSingleShot(true);
connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollEngines()));
}
- if(pollTimer->isActive())
+ if (pollTimer->isActive())
return;
foreach (QBearerEngine *engine, sessionEngines) {
@@ -483,6 +486,7 @@ void QNetworkConfigurationManagerPrivate::startPolling()
break;
}
}
+ performAsyncConfigurationUpdate();
}
void QNetworkConfigurationManagerPrivate::pollEngines()
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 371b9e0264..009bc90bf5 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -774,6 +774,7 @@ bool QAbstractSocketPrivate::canReadNotification()
void QAbstractSocketPrivate::canCloseNotification()
{
Q_Q(QAbstractSocket);
+ // Note that this method is only called on Windows. Other platforms close in the canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canCloseNotification()");
@@ -783,7 +784,11 @@ void QAbstractSocketPrivate::canCloseNotification()
if (isBuffered) {
// Try to read to the buffer, if the read fail we can close the socket.
newBytes = buffer.size();
- if (!readFromSocket()) {
+ qint64 oldReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer
+ bool hadReadFromSocket = readFromSocket();
+ readBufferMaxSize = oldReadBufferMaxSize;
+ if (!hadReadFromSocket) {
q->disconnectFromHost();
return;
}
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index c15045b180..092a414f99 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -2408,6 +2408,14 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
qCDebug(lcSsl) << "\tstate =" << q->state();
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
#endif
+ // this moves encrypted bytes from plain socket into our buffer
+ if (plainSocket->bytesAvailable()) {
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
+ transmit();
+ readBufferMaxSize = tmpReadBufferMaxSize;
+ }
+
q->setSocketError(plainSocket->error());
q->setErrorString(plainSocket->errorString());
emit q->error(error);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 1634d65eb6..8e1d0c13b1 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -1513,6 +1513,13 @@ void QSslSocketBackendPrivate::disconnected()
{
if (plainSocket->bytesAvailable() <= 0)
destroySslContext();
+ else {
+ // Move all bytes into the plain buffer
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
+ transmit();
+ readBufferMaxSize = tmpReadBufferMaxSize;
+ }
//if there is still buffered data in the plain socket, don't destroy the ssl context yet.
//it will be destroyed when the socket is deleted.
}
diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
index 8929a038e0..905f7695bb 100644
--- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
+++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
@@ -241,7 +241,8 @@ void QEGLPlatformContext::adopt(const QVariant &nativeHandle, QPlatformOpenGLCon
void QEGLPlatformContext::initialize()
{
- updateFormatFromGL();
+ if (m_eglContext != EGL_NO_CONTEXT)
+ updateFormatFromGL();
}
// Base implementation for pbuffers. Subclasses will handle the specialized cases for
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 6a4f7ed8ee..ca92103826 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -44,6 +44,8 @@ QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
QCocoaBackingStore::~QCocoaBackingStore()
{
+ if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle()))
+ [cocoaWindow->m_qtView clearBackingStore:this];
}
QPaintDevice *QCocoaBackingStore::paintDevice()
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 05ab8ae2c7..14a61554a3 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -51,8 +51,7 @@ QT_END_NAMESPACE
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
@interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> {
- QImage m_backingStore;
- qreal m_pixelRatio;
+ QCocoaBackingStore* m_backingStore;
QPoint m_backingStoreOffset;
CGImageRef m_maskImage;
uchar *m_maskData;
@@ -86,6 +85,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)setQCocoaGLContext:(QCocoaGLContext *)context;
#endif
- (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset;
+- (void)clearBackingStore:(QCocoaBackingStore *)backingStore;
- (void)setMaskRegion:(const QRegion *)region;
- (void)invalidateWindowShadowIfNeeded;
- (void)drawRect:(NSRect)dirtyRect;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index edcbd16dca..4db55c1b73 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -134,7 +134,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
{
self = [super initWithFrame : NSMakeRect(0,0, 300,300)];
if (self) {
- m_pixelRatio = 1.;
+ m_backingStore = 0;
m_maskImage = 0;
m_shouldInvalidateWindowShadow = false;
m_window = 0;
@@ -376,7 +376,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
if (!m_platformWindow->m_inSetGeometry)
QWindowSystemInterface::flushWindowSystemEvents();
else
- m_backingStore = QImage();
+ m_backingStore = 0;
}
}
@@ -481,12 +481,16 @@ QT_WARNING_POP
- (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset
{
- m_backingStore = backingStore->toImage();
- m_pixelRatio = backingStore->getBackingStoreDevicePixelRatio();
- m_backingStoreOffset = offset * m_pixelRatio;
- foreach (QRect rect, region.rects()) {
+ m_backingStore = backingStore;
+ m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
+ foreach (QRect rect, region.rects())
[self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
- }
+}
+
+- (void)clearBackingStore:(QCocoaBackingStore *)backingStore
+{
+ if (backingStore == m_backingStore)
+ m_backingStore = 0;
}
- (BOOL) hasMask
@@ -549,7 +553,7 @@ QT_WARNING_POP
if (m_platformWindow->m_drawContentBorderGradient)
NSDrawWindowBackground(dirtyRect);
- if (m_backingStore.isNull())
+ if (!m_backingStore)
return;
// Calculate source and target rects. The target rect is the dirtyRect:
@@ -557,10 +561,11 @@ QT_WARNING_POP
// The backing store source rect will be larger on retina displays.
// Scale dirtyRect by the device pixel ratio:
- CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * m_pixelRatio,
- dirtyRect.origin.y * m_pixelRatio,
- dirtyRect.size.width * m_pixelRatio,
- dirtyRect.size.height * m_pixelRatio);
+ const qreal devicePixelRatio = m_backingStore->getBackingStoreDevicePixelRatio();
+ CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio,
+ dirtyRect.origin.y * devicePixelRatio,
+ dirtyRect.size.width * devicePixelRatio,
+ dirtyRect.size.height * devicePixelRatio);
NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext];
CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort];
@@ -586,7 +591,7 @@ QT_WARNING_POP
dirtyBackingRect.size.width,
dirtyBackingRect.size.height
);
- CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore);
+ CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore->toImage());
CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect);
// Optimization: Copy frame buffer content instead of blending for
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index e2c61e1161..e4917593db 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -344,6 +344,46 @@
// -------------------------------------------------------------------------
+- (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers
+{
+ QKeyEvent press(QEvent::KeyPress, key, modifiers);
+ QKeyEvent release(QEvent::KeyRelease, key, modifiers);
+ [self sendEventToFocusObject:press];
+ [self sendEventToFocusObject:release];
+}
+
+- (void)cut:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendKeyPressRelease:Qt::Key_X modifiers:Qt::ControlModifier];
+}
+
+- (void)copy:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendKeyPressRelease:Qt::Key_C modifiers:Qt::ControlModifier];
+}
+
+- (void)paste:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendKeyPressRelease:Qt::Key_V modifiers:Qt::ControlModifier];
+}
+
+- (void)selectAll:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendKeyPressRelease:Qt::Key_A modifiers:Qt::ControlModifier];
+}
+
+- (void)delete:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendKeyPressRelease:Qt::Key_Delete modifiers:Qt::ControlModifier];
+}
+
+// -------------------------------------------------------------------------
+
- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
{
// As documented, we should not report textWillChange/textDidChange unless the text
@@ -560,7 +600,7 @@
if (cursorPos != int(r.location + r.length) || cursorPos != anchorPos) {
attrs = QList<QInputMethodEvent::Attribute>();
- attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, cursorPos, (cursorPos - anchorPos), 0);
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, qMin(cursorPos, anchorPos), qAbs(cursorPos - anchorPos), 0);
e = QInputMethodEvent(m_markedText, attrs);
[self sendEventToFocusObject:e];
}
@@ -678,10 +718,7 @@
return;
if ([text isEqualToString:@"\n"]) {
- QKeyEvent press(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
- QKeyEvent release(QEvent::KeyRelease, Qt::Key_Return, Qt::NoModifier);
- [self sendEventToFocusObject:press];
- [self sendEventToFocusObject:release];
+ [self sendKeyPressRelease:Qt::Key_Return modifiers:Qt::NoModifier];
if (self.returnKeyType == UIReturnKeyDone || self.returnKeyType == UIReturnKeyGo
|| self.returnKeyType == UIReturnKeySend || self.returnKeyType == UIReturnKeySearch)
@@ -700,10 +737,7 @@
// Since we're posting im events directly to the focus object, we should do the
// same for key events. Otherwise they might end up in a different place or out
// of sync with im events.
- QKeyEvent press(QEvent::KeyPress, (int)Qt::Key_Backspace, Qt::NoModifier);
- QKeyEvent release(QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier);
- [self sendEventToFocusObject:press];
- [self sendEventToFocusObject:release];
+ [self sendKeyPressRelease:Qt::Key_Backspace modifiers:Qt::NoModifier];
}
@end
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index 4ea5fc7de1..be89521c04 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -190,8 +190,9 @@
- (void)setBounds:(CGRect)newBounds
{
+ Q_UNUSED(newBounds);
CGRect transformedWindowBounds = [self convertRect:self.window.bounds fromView:self.window];
- [super setBounds:CGRectMake(0, 0, CGRectGetWidth(newBounds), CGRectGetHeight(transformedWindowBounds))];
+ [super setBounds:CGRectMake(0, 0, CGRectGetWidth(transformedWindowBounds), CGRectGetHeight(transformedWindowBounds))];
}
- (void)setCenter:(CGPoint)newCenter
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index 16b9118e81..3685197430 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -181,9 +181,8 @@ void QWindowsFontEngine::getCMap()
bool symb = false;
if (ttf) {
cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
- int size = 0;
cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
- cmapTable.size(), &symb, &size);
+ cmapTable.size(), &symb, &cmapSize);
}
if (!cmap) {
ttf = false;
@@ -218,16 +217,16 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
++glyph_pos;
}
} else if (ttf) {
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
++glyph_pos;
}
} else {
@@ -275,6 +274,7 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name,
hasOutline(0),
lw(0),
cmap(0),
+ cmapSize(0),
lbearing(SHRT_MIN),
rbearing(SHRT_MIN),
x_height(-1),
@@ -346,11 +346,11 @@ glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const
#if !defined(Q_OS_WINCE)
if (symbol) {
- glyph = getTrueTypeGlyphIndex(cmap, ucs4);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
if (glyph == 0 && ucs4 < 0x100)
- glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
} else if (ttf) {
- glyph = getTrueTypeGlyphIndex(cmap, ucs4);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
#else
if (tm.tmFirstChar > 60000) {
glyph = ucs4;
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
index 6df69c34db..409b44264e 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.h
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -146,6 +146,7 @@ private:
TEXTMETRIC tm;
int lw;
const unsigned char *cmap;
+ int cmapSize;
QByteArray cmapTable;
mutable qreal lbearing;
mutable qreal rbearing;
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 485b876fc7..554a6c8b4c 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -199,18 +199,27 @@ void QWindowsInputContext::reset()
doneContext();
}
-void QWindowsInputContext::setFocusObject(QObject *object)
+void QWindowsInputContext::setFocusObject(QObject *)
{
// ### fixme: On Windows 8.1, it has been observed that the Input context
// remains active when this happens resulting in a lock-up. Consecutive
// key events still have VK_PROCESSKEY set and are thus ignored.
if (m_compositionContext.isComposing)
- imeNotifyCancelComposition(m_compositionContext.hwnd);
+ reset();
+ updateEnabled();
+}
+void QWindowsInputContext::updateEnabled()
+{
+ if (!QGuiApplication::focusObject())
+ return;
const QWindow *window = QGuiApplication::focusWindow();
- if (object && window && window->handle()) {
+ if (window && window->handle()) {
QWindowsWindow *platformWindow = QWindowsWindow::baseWindowOf(window);
- if (inputMethodAccepted()) {
+ const bool accepted = inputMethodAccepted();
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaInputMethods) << __FUNCTION__ << window << "accepted=" << accepted;
+ if (accepted) {
// Re-enable IME by associating default context saved on first disabling.
if (platformWindow->testFlag(QWindowsWindow::InputMethodDisabled)) {
ImmAssociateContext(platformWindow->handle(), QWindowsInputContext::m_defaultContext);
@@ -234,6 +243,8 @@ void QWindowsInputContext::setFocusObject(QObject *object)
void QWindowsInputContext::update(Qt::InputMethodQueries queries)
{
+ if (queries & Qt::ImEnabled)
+ updateEnabled();
QPlatformInputContext::update(queries);
}
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h
index 83a39989f6..110986c20c 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.h
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.h
@@ -87,6 +87,7 @@ private:
void doneContext();
void startContextComposition();
void endContextComposition();
+ void updateEnabled();
const DWORD m_WM_MSIME_MOUSE;
static HIMC m_defaultContext;
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index f86ab9fee3..622352e987 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -990,12 +990,11 @@ QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, co
{
QVector<FORMATETC> formatetcs;
if (mimeData->hasImage() && mimeType == QLatin1String("application/x-qt-image")) {
- //add DIBV5 if image has alpha channel
+ //add DIBV5 if image has alpha channel. Do not add CF_PNG here as it will confuse MS Office (QTBUG47656).
QImage image = qvariant_cast<QImage>(mimeData->imageData());
if (!image.isNull() && image.hasAlphaChannel())
formatetcs += setCf(CF_DIBV5);
formatetcs += setCf(CF_DIB);
- formatetcs += setCf(CF_PNG); // QTBUG-86848, Paste into GIMP queries for PNG.
}
return formatetcs;
}
@@ -1024,11 +1023,7 @@ bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMi
const QImage image = qvariant_cast<QImage>(mimeData->imageData());
if (image.isNull())
return false;
- // QTBUG-11463, deny CF_DIB support for images with alpha to prevent loss of
- // transparency in conversion.
- return cf == CF_DIBV5
- || (cf == CF_DIB && !image.hasAlphaChannel())
- || cf == int(CF_PNG);
+ return cf == CF_DIBV5 || (cf == CF_DIB) || cf == int(CF_PNG);
}
bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 1b5d7b87bc..f9b34334df 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1045,8 +1045,8 @@ void QWindowsWindow::setDropSiteEnabled(bool dropEnabled)
RegisterDragDrop(m_data.hwnd, m_dropTarget);
CoLockObjectExternal(m_dropTarget, true, true);
} else {
- m_dropTarget->Release();
CoLockObjectExternal(m_dropTarget, false, true);
+ m_dropTarget->Release();
RevokeDragDrop(m_data.hwnd);
m_dropTarget = 0;
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 6ca369326b..7a5480a8a5 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -967,15 +967,6 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q
xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event);
xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(xiEvent);
-#ifdef XCB_USE_XINPUT22
- // Synthesize mouse events since otherwise there are no mouse events from
- // the pen on the XI 2.2+ path.
- if (xi2MouseEvents() && eventListener)
- eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event));
-#else
- Q_UNUSED(eventListener);
-#endif
-
switch (xiEvent->evtype) {
case XI_ButtonPress: {
Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
@@ -1058,6 +1049,16 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q
handled = false;
break;
}
+
+#ifdef XCB_USE_XINPUT22
+ // Synthesize mouse events since otherwise there are no mouse events from
+ // the pen on the XI 2.2+ path.
+ if (xi2MouseEvents() && eventListener)
+ eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event));
+#else
+ Q_UNUSED(eventListener);
+#endif
+
return handled;
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index f9a85cdf44..1ff052f2c0 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2208,17 +2208,17 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event)
switch (ev->evtype) {
case XI_ButtonPress:
- qCDebug(lcQpaXInput, "XI2 mouse press, button %d", button);
+ qCDebug(lcQpaXInput, "XI2 mouse press, button %d, time %d", button, ev->time);
conn->setButton(button, true);
handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time);
break;
case XI_ButtonRelease:
- qCDebug(lcQpaXInput, "XI2 mouse release, button %d", button);
+ qCDebug(lcQpaXInput, "XI2 mouse release, button %d, time %d", button, ev->time);
conn->setButton(button, false);
handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time);
break;
case XI_Motion:
- qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d", event_x, event_y);
+ qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d, time %d", event_x, event_y, ev->time);
handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time);
break;
default:
diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp
index f3be45262b..502ff7d98a 100644
--- a/src/printsupport/dialogs/qprintdialog_unix.cpp
+++ b/src/printsupport/dialogs/qprintdialog_unix.cpp
@@ -803,7 +803,7 @@ void QUnixPrintWidgetPrivate::applyPrinterProperties()
QString cur = QDir::currentPath();
if (home.at(home.length()-1) != QLatin1Char('/'))
home += QLatin1Char('/');
- if (cur.at(cur.length()-1) != QLatin1Char('/'))
+ if (!cur.isEmpty() && cur.at(cur.length()-1) != QLatin1Char('/'))
cur += QLatin1Char('/');
if (cur.left(home.length()) != home)
cur = home;
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
index 5c67652cdb..f4e40b6582 100644
--- a/src/sql/drivers/psql/qsql_psql.cpp
+++ b/src/sql/drivers/psql/qsql_psql.cpp
@@ -1332,6 +1332,9 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
if (r.isEmpty())
r = QSqlDriver::formatValue(field, trimStrings);
break;
+ case QVariant::Uuid:
+ r = QLatin1Char('\'') + field.value().toString() + QLatin1Char('\'');
+ break;
default:
r = QSqlDriver::formatValue(field, trimStrings);
break;
diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp
index 0259ce216b..5f5c402a4a 100644
--- a/src/widgets/graphicsview/qgraphicsitem.cpp
+++ b/src/widgets/graphicsview/qgraphicsitem.cpp
@@ -1425,10 +1425,13 @@ QGraphicsItem::~QGraphicsItem()
QObjectPrivate *p = QObjectPrivate::get(o);
p->wasDeleted = true;
if (p->declarativeData) {
- if (QAbstractDeclarativeData::destroyed)
- QAbstractDeclarativeData::destroyed(p->declarativeData, o);
- if (QAbstractDeclarativeData::destroyed_qml1)
- QAbstractDeclarativeData::destroyed_qml1(p->declarativeData, o);
+ if (static_cast<QAbstractDeclarativeDataImpl*>(p->declarativeData)->ownedByQml1) {
+ if (QAbstractDeclarativeData::destroyed_qml1)
+ QAbstractDeclarativeData::destroyed_qml1(p->declarativeData, o);
+ } else {
+ if (QAbstractDeclarativeData::destroyed)
+ QAbstractDeclarativeData::destroyed(p->declarativeData, o);
+ }
p->declarativeData = 0;
}
}
diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp
index 9b3e270fdd..57092a7cdc 100644
--- a/src/widgets/itemviews/qtreeview.cpp
+++ b/src/widgets/itemviews/qtreeview.cpp
@@ -433,6 +433,9 @@ void QTreeView::setRootIsDecorated(bool show)
The height is obtained from the first item in the view. It is updated
when the data changes on that item.
+ \note If the editor size hint is bigger than the cell size hint, then the
+ size hint of the editor will be used.
+
By default, this property is \c false.
*/
bool QTreeView::uniformRowHeights() const
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index f82fac836a..d8c14de060 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -339,8 +339,7 @@ void QApplicationPrivate::createEventDispatcher()
\li Miscellaneous
\li closeAllWindows(),
startingUp(),
- closingDown(),
- type().
+ closingDown().
\endtable
\sa QCoreApplication, QAbstractEventDispatcher, QEventLoop, QSettings
diff --git a/src/widgets/kernel/qlayoutitem.cpp b/src/widgets/kernel/qlayoutitem.cpp
index 3d444136e3..03988aab99 100644
--- a/src/widgets/kernel/qlayoutitem.cpp
+++ b/src/widgets/kernel/qlayoutitem.cpp
@@ -92,7 +92,7 @@ inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
be expressed using hasHeightForWidth(), heightForWidth(), and
minimumHeightForWidth(). For more explanation see the \e{Qt
Quarterly} article
- \l{http://doc.qt.digia.com/qq/qq04-height-for-width.html}{Trading
+ \l{http://doc.qt.io/archives/qq/qq04-height-for-width.html}{Trading
Height for Width}.
\sa QLayout
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 91641db60d..32c52ade56 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1634,10 +1634,13 @@ QWidget::~QWidget()
}
if (d->declarativeData) {
- if (QAbstractDeclarativeData::destroyed)
- QAbstractDeclarativeData::destroyed(d->declarativeData, this);
- if (QAbstractDeclarativeData::destroyed_qml1)
- QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this);
+ if (static_cast<QAbstractDeclarativeDataImpl*>(d->declarativeData)->ownedByQml1) {
+ if (QAbstractDeclarativeData::destroyed_qml1)
+ QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this);
+ } else {
+ if (QAbstractDeclarativeData::destroyed)
+ QAbstractDeclarativeData::destroyed(d->declarativeData, this);
+ }
d->declarativeData = 0; // don't activate again in ~QObject
}
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 58436a7d92..deaac4e263 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -445,11 +445,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
receiver = popupChild;
if (receiver != popup)
widgetPos = receiver->mapFromGlobal(event->globalPos());
- QWidget *alien = m_widget->childAt(m_widget->mapFromGlobal(event->globalPos()));
+ QWidget *alien = receiver->childAt(receiver->mapFromGlobal(event->globalPos()));
QMouseEvent e(event->type(), widgetPos, event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers(), event->source());
e.setTimestamp(event->timestamp());
- QApplicationPrivate::sendMouseEvent(receiver, &e, alien, m_widget, &qt_button_down, qt_last_mouse_receiver);
+ QApplicationPrivate::sendMouseEvent(receiver, &e, alien, receiver->window(), &qt_button_down, qt_last_mouse_receiver);
qt_last_mouse_receiver = receiver;
} else {
// close disabled popups when a mouse button is pressed or released
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
index aa1a783577..3219952f7f 100644
--- a/src/widgets/styles/qmacstyle_mac.mm
+++ b/src/widgets/styles/qmacstyle_mac.mm
@@ -4682,7 +4682,8 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
tdi.value = pb->progress;
tdi.attributes = vertical ? 0 : kThemeTrackHorizontal;
- if (isIndeterminate || tdi.value < tdi.max) {
+ const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion > QSysInfo::MV_10_9;
+ if (isIndeterminate || (tdi.value < tdi.max && !usingYosemiteOrLater)) {
if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject)))
tdi.trackInfo.progress.phase = animation->animationStep();
else if (opt->styleObject)
diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp
index 5e51866d8f..b368477a39 100644
--- a/src/widgets/styles/qstyle.cpp
+++ b/src/widgets/styles/qstyle.cpp
@@ -541,17 +541,21 @@ QRect QStyle::itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pi
QRect result;
int x, y, w, h;
rect.getRect(&x, &y, &w, &h);
+
+ const int pixmapWidth = pixmap.width()/pixmap.devicePixelRatio();
+ const int pixmapHeight = pixmap.height()/pixmap.devicePixelRatio();
+
if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
- y += h/2 - pixmap.height()/2;
+ y += h/2 - pixmapHeight/2;
else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
- y += h - pixmap.height();
+ y += h - pixmapHeight;
if ((alignment & Qt::AlignRight) == Qt::AlignRight)
- x += w - pixmap.width();
+ x += w - pixmapWidth;
else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
- x += w/2 - pixmap.width()/2;
+ x += w/2 - pixmapWidth/2;
else if ((alignment & Qt::AlignLeft) != Qt::AlignLeft && QApplication::isRightToLeft())
- x += w - pixmap.width();
- result = QRect(x, y, pixmap.width(), pixmap.height());
+ x += w - pixmapWidth;
+ result = QRect(x, y, pixmapWidth, pixmapHeight);
return result;
}
@@ -2263,8 +2267,9 @@ int QStyle::sliderValueFromPosition(int min, int max, int pos, int span, bool up
standard palette is not used. In particular, the Windows XP,
Vista, and Mac styles do not use the standard palette, but make
use of native theme engines. With these styles, you should not set
- the palette with QApplication::setStandardPalette().
+ the palette with QApplication::setPalette().
+ \sa QApplication::setPalette()
*/
QPalette QStyle::standardPalette() const
{
diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp
index af085747ec..af2a66a838 100644
--- a/src/widgets/widgets/qcombobox.cpp
+++ b/src/widgets/widgets/qcombobox.cpp
@@ -1772,6 +1772,8 @@ void QComboBox::setLineEdit(QLineEdit *edit)
connect(d->lineEdit, SIGNAL(editingFinished()), this, SLOT(_q_editingFinished()));
connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(editTextChanged(QString)));
connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(currentTextChanged(QString)));
+ connect(d->lineEdit, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(updateMicroFocus()));
+ connect(d->lineEdit, SIGNAL(selectionChanged()), this, SLOT(updateMicroFocus()));
d->lineEdit->setFrame(false);
d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
d->updateFocusPolicy();
diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp
index b798bca4d1..a68f5a41ed 100644
--- a/src/widgets/widgets/qlineedit_p.cpp
+++ b/src/widgets/widgets/qlineedit_p.cpp
@@ -188,6 +188,9 @@ void QLineEditPrivate::init(const QString& txt)
QObject::connect(control, SIGNAL(selectionChanged()),
q, SLOT(update()));
+ QObject::connect(control, SIGNAL(selectionChanged()),
+ q, SLOT(updateMicroFocus()));
+
QObject::connect(control, SIGNAL(displayTextChanged(QString)),
q, SLOT(update()));
@@ -321,6 +324,24 @@ void QLineEditIconButton::paintEvent(QPaintEvent *)
painter.drawPixmap(pixmapRect, iconPixmap);
}
+void QLineEditIconButton::actionEvent(QActionEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::ActionChanged: {
+ const QAction *action = e->action();
+ if (isVisible() != action->isVisible()) {
+ setVisible(action->isVisible());
+ if (QLineEdit *le = qobject_cast<QLineEdit *>(parentWidget()))
+ static_cast<QLineEditPrivate *>(qt_widget_private(le))->positionSideWidgets();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ QToolButton::actionEvent(e);
+}
+
void QLineEditIconButton::setOpacity(qreal value)
{
if (!qFuzzyCompare(m_opacity, value)) {
@@ -412,12 +433,14 @@ void QLineEditPrivate::positionSideWidgets()
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);
+ if (e.widget->isVisible())
+ 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);
+ if (e.widget->isVisible())
+ widgetGeometry.moveLeft(widgetGeometry.left() - delta);
}
}
}
diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h
index 57055757eb..b47866b827 100644
--- a/src/widgets/widgets/qlineedit_p.h
+++ b/src/widgets/widgets/qlineedit_p.h
@@ -61,6 +61,8 @@
#include "private/qwidgetlinecontrol_p.h"
+#include <algorithm>
+
QT_BEGIN_NAMESPACE
// QLineEditIconButton: This is a simple helper class that represents clickable icons that fade in with text
@@ -81,6 +83,7 @@ public:
#endif
protected:
+ void actionEvent(QActionEvent *e) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private slots:
@@ -227,14 +230,23 @@ private:
};
Q_DECLARE_TYPEINFO(QLineEditPrivate::SideWidgetEntry, Q_PRIMITIVE_TYPE);
+static bool isSideWidgetVisible(const QLineEditPrivate::SideWidgetEntry &e)
+{
+ return e.widget->isVisible();
+}
+
inline int QLineEditPrivate::effectiveLeftTextMargin() const
{
- return leftTextMargin + leftSideWidgetList().size() * (QLineEditIconButton::IconMargin + iconSize().width());
+ return leftTextMargin + (QLineEditIconButton::IconMargin + iconSize().width())
+ * int(std::count_if(leftSideWidgetList().constBegin(), leftSideWidgetList().constEnd(),
+ isSideWidgetVisible));
}
inline int QLineEditPrivate::effectiveRightTextMargin() const
{
- return rightTextMargin + rightSideWidgetList().size() * (QLineEditIconButton::IconMargin + iconSize().width());
+ return rightTextMargin + (QLineEditIconButton::IconMargin + iconSize().width())
+ * int(std::count_if(rightSideWidgetList().constBegin(), rightSideWidgetList().constEnd(),
+ isSideWidgetVisible));
}
#endif // QT_NO_LINEEDIT
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp
index 9e76ff082c..91775e3862 100644
--- a/src/widgets/widgets/qmenubar.cpp
+++ b/src/widgets/widgets/qmenubar.cpp
@@ -1044,8 +1044,8 @@ void QMenuBar::mousePressEvent(QMouseEvent *e)
if(d->currentAction == action && d->popupState) {
if(QMenu *menu = d->activeMenu) {
d->activeMenu = 0;
+ menu->setAttribute(Qt::WA_NoMouseReplay);
menu->hide();
- d->closePopupMode = 1;
}
} else {
d->setCurrentAction(action, true);
diff --git a/tests/auto/corelib/io/qprocess/qprocess.pri b/tests/auto/corelib/io/qprocess/qprocess.pri
index 430251fbf1..a43c823846 100644
--- a/tests/auto/corelib/io/qprocess/qprocess.pri
+++ b/tests/auto/corelib/io/qprocess/qprocess.pri
@@ -4,6 +4,7 @@ SUBPROGRAMS = \
testProcessEcho2 \
testProcessEcho3 \
testProcessEnvironment \
+ testProcessHang \
testProcessNormal \
testProcessOutput \
testProcessDeadWhileReading \
diff --git a/tests/auto/corelib/io/qprocess/testProcessHang/main.cpp b/tests/auto/corelib/io/qprocess/testProcessHang/main.cpp
new file mode 100644
index 0000000000..e06502f738
--- /dev/null
+++ b/tests/auto/corelib/io/qprocess/testProcessHang/main.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <stdio.h>
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+# include <windows.h>
+
+void sleepForever()
+{
+ ::Sleep(INFINITE);
+}
+#else
+# include <unistd.h>
+
+void sleepForever()
+{
+ ::pause();
+}
+#endif
+
+int main()
+{
+ puts("ready.");
+ fflush(stdout);
+ fprintf(stderr, "ready.\n");
+ fflush(stderr);
+
+ // sleep forever, simulating a hung application
+ sleepForever();
+ return 0;
+}
diff --git a/tests/auto/corelib/io/qprocess/testProcessHang/testProcessHang.pro b/tests/auto/corelib/io/qprocess/testProcessHang/testProcessHang.pro
new file mode 100644
index 0000000000..e236e05c7d
--- /dev/null
+++ b/tests/auto/corelib/io/qprocess/testProcessHang/testProcessHang.pro
@@ -0,0 +1,4 @@
+SOURCES = main.cpp
+CONFIG -= qt app_bundle
+CONFIG += console
+DESTDIR = ./
diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
index 0d4c53a7a9..caefc3fc21 100644
--- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
+++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Intel Corporation.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -116,7 +117,8 @@ private slots:
void setStandardInputFile();
void setStandardOutputFile_data();
void setStandardOutputFile();
- void setStandardOutputFile2();
+ void setStandardOutputFileNullDevice();
+ void setStandardOutputFileAndWaitForBytesWritten();
void setStandardOutputProcess_data();
void setStandardOutputProcess();
void removeFileWhileProcessIsRunning();
@@ -150,6 +152,9 @@ private slots:
void onlyOneStartedSignal();
void finishProcessBeforeReadingDone();
void waitForStartedWithoutStart();
+ void startStopStartStop();
+ void startStopStartStopBuffers_data();
+ void startStopStartStopBuffers();
// keep these at the end, since they use lots of processes and sometimes
// caused obscure failures to occur in tests that followed them (esp. on the Mac)
@@ -1970,22 +1975,6 @@ void tst_QProcess::setStandardOutputFile_data()
<< true;
}
-#ifndef Q_OS_WINCE
-void tst_QProcess::setStandardOutputFile2()
-{
- static const char testdata[] = "Test data.";
-
- QProcess process;
- process.setStandardOutputFile(QProcess::nullDevice());
- process.start("testProcessEcho2/testProcessEcho2");
- process.write(testdata, sizeof testdata);
- QPROCESS_VERIFY(process,waitForFinished());
- QCOMPARE(process.bytesAvailable(), Q_INT64_C(0));
-
- QVERIFY(!QFileInfo(QProcess::nullDevice()).isFile());
-}
-#endif
-
void tst_QProcess::setStandardOutputFile()
{
static const char data[] = "Original data. ";
@@ -2034,6 +2023,40 @@ void tst_QProcess::setStandardOutputFile()
QCOMPARE(all.size(), expectedsize);
}
+
+void tst_QProcess::setStandardOutputFileNullDevice()
+{
+ static const char testdata[] = "Test data.";
+
+ QProcess process;
+ process.setStandardOutputFile(QProcess::nullDevice());
+ process.start("testProcessEcho2/testProcessEcho2");
+ process.write(testdata, sizeof testdata);
+ QPROCESS_VERIFY(process,waitForFinished());
+ QCOMPARE(process.bytesAvailable(), Q_INT64_C(0));
+
+ QVERIFY(!QFileInfo(QProcess::nullDevice()).isFile());
+}
+
+void tst_QProcess::setStandardOutputFileAndWaitForBytesWritten()
+{
+ static const char testdata[] = "Test data.";
+
+ QFile file("data");
+ QProcess process;
+ process.setStandardOutputFile(file.fileName());
+ process.start("testProcessEcho2/testProcessEcho2");
+ process.write(testdata, sizeof testdata);
+ process.waitForBytesWritten();
+ QPROCESS_VERIFY(process, waitForFinished());
+
+ // open the file again and verify the data
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QByteArray all = file.readAll();
+ file.close();
+
+ QCOMPARE(all, QByteArray::fromRawData(testdata, sizeof testdata - 1));
+}
#endif
#ifndef Q_OS_WINCE
@@ -2041,17 +2064,19 @@ void tst_QProcess::setStandardOutputFile()
void tst_QProcess::setStandardOutputProcess_data()
{
QTest::addColumn<bool>("merged");
- QTest::newRow("separate") << false;
- QTest::newRow("merged") << true;
+ QTest::addColumn<bool>("waitForBytesWritten");
+ QTest::newRow("separate") << false << false;
+ QTest::newRow("separate with waitForBytesWritten") << false << true;
+ QTest::newRow("merged") << true << false;
}
void tst_QProcess::setStandardOutputProcess()
{
-
QProcess source;
QProcess sink;
QFETCH(bool, merged);
+ QFETCH(bool, waitForBytesWritten);
source.setReadChannelMode(merged ? QProcess::MergedChannels : QProcess::SeparateChannels);
source.setStandardOutputProcess(&sink);
@@ -2060,6 +2085,8 @@ void tst_QProcess::setStandardOutputProcess()
QByteArray data("Hello, World");
source.write(data);
+ if (waitForBytesWritten)
+ source.waitForBytesWritten();
source.closeWriteChannel();
QPROCESS_VERIFY(source, waitForFinished());
QPROCESS_VERIFY(sink, waitForFinished());
@@ -2333,12 +2360,110 @@ void tst_QProcess::finishProcessBeforeReadingDone()
QCOMPARE(lines.last(), QStringLiteral("10239 -this is a number"));
}
+//-----------------------------------------------------------------------------
void tst_QProcess::waitForStartedWithoutStart()
{
QProcess process;
QVERIFY(!process.waitForStarted(5000));
}
+//-----------------------------------------------------------------------------
+void tst_QProcess::startStopStartStop()
+{
+ // we actually do start-stop x 3 :-)
+ QProcess process;
+ process.start("testProcessNormal/testProcessNormal");
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+
+ process.start("testExitCodes/testExitCodes", QStringList() << "1");
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 1);
+
+ process.start("testProcessNormal/testProcessNormal");
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+}
+
+//-----------------------------------------------------------------------------
+void tst_QProcess::startStopStartStopBuffers_data()
+{
+ QTest::addColumn<int>("channelMode1");
+ QTest::addColumn<int>("channelMode2");
+
+ QTest::newRow("separate-separate") << int(QProcess::SeparateChannels) << int(QProcess::SeparateChannels);
+ QTest::newRow("separate-merged") << int(QProcess::SeparateChannels) << int(QProcess::MergedChannels);
+ QTest::newRow("merged-separate") << int(QProcess::MergedChannels) << int(QProcess::SeparateChannels);
+ QTest::newRow("merged-merged") << int(QProcess::MergedChannels) << int(QProcess::MergedChannels);
+ QTest::newRow("merged-forwarded") << int(QProcess::MergedChannels) << int(QProcess::ForwardedChannels);
+}
+
+void tst_QProcess::startStopStartStopBuffers()
+{
+ QFETCH(int, channelMode1);
+ QFETCH(int, channelMode2);
+
+ QProcess process;
+ process.setProcessChannelMode(QProcess::ProcessChannelMode(channelMode1));
+ process.start("testProcessHang/testProcessHang");
+ QVERIFY2(process.waitForReadyRead(), process.errorString().toLocal8Bit());
+ if (channelMode1 == QProcess::SeparateChannels || channelMode1 == QProcess::ForwardedOutputChannel) {
+ process.setReadChannel(QProcess::StandardError);
+ if (process.bytesAvailable() == 0)
+ QVERIFY(process.waitForReadyRead());
+ process.setReadChannel(QProcess::StandardOutput);
+ }
+
+ // We want to test that the write buffer still has bytes after the child
+ // exiting. We do that by writing to a child process that never reads. We
+ // just have to write more data than a pipe can hold, so that even if
+ // QProcess finds the pipe writable (during waitForFinished() or in the
+ // QWindowsPipeWriter thread), some data will remain. The worst case I know
+ // of is Linux, which defaults to 64 kB of buffer.
+
+ process.write(QByteArray(128 * 1024, 'a'));
+ QVERIFY(process.bytesToWrite() > 0);
+ process.kill();
+
+ QVERIFY(process.waitForFinished());
+
+#ifndef Q_OS_WIN
+ // confirm that our buffers are still full
+ // Note: this doesn't work on Windows because our buffers are drained into
+ // QWindowsPipeWriter before being sent to the child process.
+ QVERIFY(process.bytesToWrite() > 0);
+ QVERIFY(process.bytesAvailable() > 0); // channelMode1 is not ForwardedChannels
+ if (channelMode1 == QProcess::SeparateChannels || channelMode1 == QProcess::ForwardedOutputChannel) {
+ process.setReadChannel(QProcess::StandardError);
+ QVERIFY(process.bytesAvailable() > 0);
+ process.setReadChannel(QProcess::StandardOutput);
+ }
+#endif
+
+ process.setProcessChannelMode(QProcess::ProcessChannelMode(channelMode2));
+ process.start("testProcessEcho2/testProcessEcho2", QIODevice::ReadWrite | QIODevice::Text);
+
+ // the buffers should now be empty
+ QCOMPARE(process.bytesToWrite(), qint64(0));
+ QCOMPARE(process.bytesAvailable(), qint64(0));
+ process.setReadChannel(QProcess::StandardError);
+ QCOMPARE(process.bytesAvailable(), qint64(0));
+ process.setReadChannel(QProcess::StandardOutput);
+
+ process.write("line3\n");
+ process.closeWriteChannel();
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+
+ if (channelMode2 == QProcess::MergedChannels) {
+ QCOMPARE(process.readAll(), QByteArray("lliinnee33\n\n"));
+ } else if (channelMode2 != QProcess::ForwardedChannels) {
+ QCOMPARE(process.readAllStandardOutput(), QByteArray("line3\n"));
+ if (channelMode2 == QProcess::SeparateChannels)
+ QCOMPARE(process.readAllStandardError(), QByteArray("line3\n"));
+ }
+}
+
#endif //QT_NO_PROCESS
QTEST_MAIN(tst_QProcess)
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/qmimedatabase-cache.pro b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/qmimedatabase-cache.pro
index d0dbf077c8..d0b834824a 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/qmimedatabase-cache.pro
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/qmimedatabase-cache.pro
@@ -11,3 +11,5 @@ RESOURCES += ../testdata.qrc
*-g++*:QMAKE_CXXFLAGS += -W -Wall -Wextra -Wshadow -Wno-long-long -Wnon-virtual-dtor
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+unix:!mac:!qnx: DEFINES += USE_XDG_DATA_DIRS
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/tst_qmimedatabase-cache.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/tst_qmimedatabase-cache.cpp
index 7f78312582..2113672821 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/tst_qmimedatabase-cache.cpp
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/tst_qmimedatabase-cache.cpp
@@ -39,7 +39,7 @@
#include "../tst_qmimedatabase.cpp"
-void tst_QMimeDatabase::init()
+void tst_QMimeDatabase::initTestCaseInternal()
{
#ifdef QT_NO_PROCESS
QSKIP("No qprocess support", SkipAll);
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/qmimedatabase-xml.pro b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/qmimedatabase-xml.pro
index 6d7cbc6016..4add6c2bcd 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/qmimedatabase-xml.pro
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/qmimedatabase-xml.pro
@@ -12,3 +12,5 @@ RESOURCES += ../testdata.qrc
*-g++*:QMAKE_CXXFLAGS += -W -Wall -Wextra -Wshadow -Wno-long-long -Wnon-virtual-dtor
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+unix:!mac:!qnx: DEFINES += USE_XDG_DATA_DIRS
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/tst_qmimedatabase-xml.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/tst_qmimedatabase-xml.cpp
index e24b1b1249..c4a1dab697 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/tst_qmimedatabase-xml.cpp
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/tst_qmimedatabase-xml.cpp
@@ -33,7 +33,7 @@
#include "../tst_qmimedatabase.h"
-void tst_QMimeDatabase::init()
+void tst_QMimeDatabase::initTestCaseInternal()
{
qputenv("QT_NO_MIME_CACHE", "1");
}
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc b/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc
index 48d3204473..4654a61660 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc
@@ -2,6 +2,7 @@
<qresource prefix="/qt-project.org/qmime">
<file alias="yast2-metapackage-handler-mimetypes.xml">yast2-metapackage-handler-mimetypes.xml</file>
<file alias="qml-again.xml">qml-again.xml</file>
+ <file alias="text-x-objcsrc.xml">text-x-objcsrc.xml</file>
<file alias="test.qml">test.qml</file>
</qresource>
</RCC>
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/text-x-objcsrc.xml b/tests/auto/corelib/mimetypes/qmimedatabase/text-x-objcsrc.xml
new file mode 100644
index 0000000000..e262dc634d
--- /dev/null
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/text-x-objcsrc.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="text/x-objcsrc">
+ <comment>Objective-C source code</comment>
+ <glob-deleteall/>
+ </mime-type>
+</mime-info>
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
index 12abaf47c5..dd04849f87 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
@@ -38,6 +38,8 @@
#include <QtCore/QElapsedTimer>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
+#include <QtCore/QStandardPaths>
+#include <QtCore/QTemporaryDir>
#include <QtCore/QTextStream>
#include <QFutureSynchronizer>
#include <QtConcurrent/QtConcurrentRun>
@@ -46,6 +48,7 @@
static const char yastFileName[] ="yast2-metapackage-handler-mimetypes.xml";
static const char qmlAgainFileName[] ="qml-again.xml";
+static const char textXObjCSrcFileName[] ="text-x-objcsrc.xml";
#define RESOURCE_PREFIX ":/qt-project.org/qmime/"
void initializeLang()
@@ -117,30 +120,31 @@ tst_QMimeDatabase::tst_QMimeDatabase()
void tst_QMimeDatabase::initTestCase()
{
+ QStandardPaths::setTestModeEnabled(true);
+ m_localMimeDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/mime";
+ if (QDir(m_localMimeDir).exists()) {
+ QVERIFY2(QDir(m_localMimeDir).removeRecursively(), qPrintable(m_localMimeDir + ": " + qt_error_string()));
+ }
+ QString errorMessage;
+
+#ifdef USE_XDG_DATA_DIRS
+ // Create a temporary "global" XDG data dir for later use
+ // It will initially contain a copy of freedesktop.org.xml
QVERIFY2(m_temporaryDir.isValid(),
("Could not create temporary subdir: " + m_temporaryDir.errorString()).toUtf8());
-
- // Create a "global" and a "local" XDG data dir, right here.
- // The local dir will be empty initially, while the global dir will contain a copy of freedesktop.org.xml
-
const QDir here = QDir(m_temporaryDir.path());
-
m_globalXdgDir = m_temporaryDir.path() + QStringLiteral("/global");
- m_localXdgDir = m_temporaryDir.path() + QStringLiteral("/local");
-
const QString globalPackageDir = m_globalXdgDir + QStringLiteral("/mime/packages");
- QVERIFY(here.mkpath(globalPackageDir) && here.mkpath(m_localXdgDir));
+ QVERIFY(here.mkpath(globalPackageDir));
qputenv("XDG_DATA_DIRS", QFile::encodeName(m_globalXdgDir));
- qputenv("XDG_DATA_HOME", QFile::encodeName(m_localXdgDir));
- qDebug() << "\nLocal XDG_DATA_HOME: " << m_localXdgDir
- << "\nGlobal XDG_DATA_DIRS: " << m_globalXdgDir;
+ qDebug() << "\nGlobal XDG_DATA_DIRS: " << m_globalXdgDir;
const QString freeDesktopXml = QStringLiteral("freedesktop.org.xml");
const QString xmlFileName = QLatin1String(RESOURCE_PREFIX) + freeDesktopXml;
const QString xmlTargetFileName = globalPackageDir + QLatin1Char('/') + freeDesktopXml;
- QString errorMessage;
QVERIFY2(copyResourceFile(xmlFileName, xmlTargetFileName, &errorMessage), qPrintable(errorMessage));
+#endif
m_testSuite = QFINDTESTDATA("testfiles");
if (m_testSuite.isEmpty())
@@ -151,8 +155,22 @@ void tst_QMimeDatabase::initTestCase()
QVERIFY2(QFile::exists(m_yastMimeTypes), qPrintable(errorMessage.arg(yastFileName)));
m_qmlAgainFileName = QLatin1String(RESOURCE_PREFIX) + qmlAgainFileName;
QVERIFY2(QFile::exists(m_qmlAgainFileName), qPrintable(errorMessage.arg(qmlAgainFileName)));
+ m_textXObjCSrcFileName = QLatin1String(RESOURCE_PREFIX) + textXObjCSrcFileName;
+ QVERIFY2(QFile::exists(m_textXObjCSrcFileName), qPrintable(errorMessage.arg(textXObjCSrcFileName)));
+
+ initTestCaseInternal();
+ m_isUsingCacheProvider = !qEnvironmentVariableIsSet("QT_NO_MIME_CACHE");
+}
- init();
+void tst_QMimeDatabase::init()
+{
+ // clean up local data from previous runs
+ QDir(m_localMimeDir).removeRecursively();
+}
+
+void tst_QMimeDatabase::cleanupTestCase()
+{
+ QDir(m_localMimeDir).removeRecursively();
}
void tst_QMimeDatabase::mimeTypeForName()
@@ -853,6 +871,10 @@ QT_END_NAMESPACE
void tst_QMimeDatabase::installNewGlobalMimeType()
{
+#if !defined(USE_XDG_DATA_DIRS)
+ QSKIP("This test requires XDG_DATA_DIRS");
+#endif
+
#ifdef QT_NO_PROCESS
QSKIP("This test requires QProcess support");
#else
@@ -867,6 +889,8 @@ void tst_QMimeDatabase::installNewGlobalMimeType()
QFile::remove(destFile);
const QString destQmlFile = destDir + QLatin1String(qmlAgainFileName);
QFile::remove(destQmlFile);
+ const QString destTextXObjCSrcFile = destDir + QLatin1String(textXObjCSrcFileName);
+ QFile::remove(destTextXObjCSrcFile);
//qDebug() << destFile;
if (!QFileInfo(destDir).isDir())
@@ -874,11 +898,12 @@ void tst_QMimeDatabase::installNewGlobalMimeType()
QString errorMessage;
QVERIFY2(copyResourceFile(m_yastMimeTypes, destFile, &errorMessage), qPrintable(errorMessage));
QVERIFY2(copyResourceFile(m_qmlAgainFileName, destQmlFile, &errorMessage), qPrintable(errorMessage));
- if (!waitAndRunUpdateMimeDatabase(mimeDir))
+ QVERIFY2(copyResourceFile(m_textXObjCSrcFileName, destTextXObjCSrcFile, &errorMessage), qPrintable(errorMessage));
+ if (m_isUsingCacheProvider && !waitAndRunUpdateMimeDatabase(mimeDir))
QSKIP("shared-mime-info not found, skipping mime.cache test");
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
- QString::fromLatin1("text/x-suse-ymu"));
+ QString::fromLatin1("text/x-SuSE-ymu"));
QVERIFY(db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
checkHasMimeType("text/x-suse-ymp");
@@ -890,10 +915,18 @@ void tst_QMimeDatabase::installNewGlobalMimeType()
QCOMPARE(db.mimeTypeForFile(qmlTestFile).name(),
QString::fromLatin1("text/x-qml"));
+ // ensure we can access the empty glob list
+ {
+ QMimeType objcsrc = db.mimeTypeForName(QStringLiteral("text/x-objcsrc"));
+ QVERIFY(objcsrc.isValid());
+ qDebug() << objcsrc.globPatterns();
+ }
+
// Now test removing it again
- QFile::remove(destFile);
- QFile::remove(destQmlFile);
- if (!waitAndRunUpdateMimeDatabase(mimeDir))
+ QVERIFY(QFile::remove(destFile));
+ QVERIFY(QFile::remove(destQmlFile));
+ QVERIFY(QFile::remove(destTextXObjCSrcFile));
+ if (m_isUsingCacheProvider && !waitAndRunUpdateMimeDatabase(mimeDir))
QSKIP("shared-mime-info not found, skipping mime.cache test");
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
QString::fromLatin1("application/octet-stream"));
@@ -911,8 +944,7 @@ void tst_QMimeDatabase::installNewLocalMimeType()
QMimeDatabase db;
QVERIFY(!db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
- const QString mimeDir = m_localXdgDir + QLatin1String("/mime");
- const QString destDir = mimeDir + QLatin1String("/packages/");
+ const QString destDir = m_localMimeDir + QLatin1String("/packages/");
QDir().mkpath(destDir);
const QString destFile = destDir + QLatin1String(yastFileName);
QFile::remove(destFile);
@@ -921,15 +953,16 @@ void tst_QMimeDatabase::installNewLocalMimeType()
QString errorMessage;
QVERIFY2(copyResourceFile(m_yastMimeTypes, destFile, &errorMessage), qPrintable(errorMessage));
QVERIFY2(copyResourceFile(m_qmlAgainFileName, destQmlFile, &errorMessage), qPrintable(errorMessage));
- if (!runUpdateMimeDatabase(mimeDir)) {
+ if (m_isUsingCacheProvider && !runUpdateMimeDatabase(m_localMimeDir)) {
const QString skipWarning = QStringLiteral("shared-mime-info not found, skipping mime.cache test (")
- + QDir::toNativeSeparators(mimeDir) + QLatin1Char(')');
+ + QDir::toNativeSeparators(m_localMimeDir) + QLatin1Char(')');
QSKIP(qPrintable(skipWarning));
}
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
- QString::fromLatin1("text/x-suse-ymu"));
+ QString::fromLatin1("text/x-SuSE-ymu"));
QVERIFY(db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
+ QCOMPARE(db.mimeTypeForName(QLatin1String("text/x-SuSE-ymu")).comment(), QString("URL of a YaST Meta Package"));
checkHasMimeType("text/x-suse-ymp");
// Test that a double-definition of a mimetype doesn't lead to sniffing ("conflicting globs").
@@ -941,16 +974,16 @@ void tst_QMimeDatabase::installNewLocalMimeType()
QString::fromLatin1("text/x-qml"));
// Now test removing the local mimetypes again (note, this leaves a mostly-empty mime.cache file)
- QFile::remove(destFile);
- QFile::remove(destQmlFile);
- if (!waitAndRunUpdateMimeDatabase(mimeDir))
+ QVERIFY(QFile::remove(destFile));
+ QVERIFY(QFile::remove(destQmlFile));
+ if (m_isUsingCacheProvider && !waitAndRunUpdateMimeDatabase(m_localMimeDir))
QSKIP("shared-mime-info not found, skipping mime.cache test");
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
QString::fromLatin1("application/octet-stream"));
QVERIFY(!db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
// And now the user goes wild and uses rm -rf
- QFile::remove(mimeDir + QString::fromLatin1("/mime.cache"));
+ QFile::remove(m_localMimeDir + QString::fromLatin1("/mime.cache"));
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
QString::fromLatin1("application/octet-stream"));
QVERIFY(!db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h
index 26def8f290..f12beafe86 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h
@@ -46,6 +46,8 @@ public:
private slots:
void initTestCase();
+ void init();
+ void cleanupTestCase();
void mimeTypeForName();
void mimeTypeForFileName_data();
@@ -86,14 +88,16 @@ private slots:
void installNewLocalMimeType();
private:
- void init(); // test-specific
+ void initTestCaseInternal(); // test-specific
QString m_globalXdgDir;
- QString m_localXdgDir;
+ QString m_localMimeDir;
QString m_yastMimeTypes;
QString m_qmlAgainFileName;
+ QString m_textXObjCSrcFileName;
QTemporaryDir m_temporaryDir;
QString m_testSuite;
+ bool m_isUsingCacheProvider;
};
#endif // TST_QMIMEDATABASE_H
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/yast2-metapackage-handler-mimetypes.xml b/tests/auto/corelib/mimetypes/qmimedatabase/yast2-metapackage-handler-mimetypes.xml
index ef3035ef4a..bb352b7ba2 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/yast2-metapackage-handler-mimetypes.xml
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/yast2-metapackage-handler-mimetypes.xml
@@ -7,7 +7,7 @@
<glob pattern="*.ymp"/>
</mime-type>
- <mime-type type="text/x-suse-ymu">
+ <mime-type type="text/x-SuSE-ymu">
<comment>URL of a YaST Meta Package</comment>
<glob pattern="*.ymu"/>
</mime-type>
diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp
index 6b7614b7b9..8ddd4979b6 100644
--- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp
+++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>.
-** Copyright (C) 2013 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+** Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>.
+** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: http://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -306,19 +306,6 @@ static void testMatch(const QRegularExpression &regexp,
matchType,
matchOptions,
result);
-
- // offset <= 0 tested above; now also test stringrefs not spanning over
- // the entire subject. Note that the offset can be negative, hence the above
- // tests can't be merged into this one
- for (int i = 1; i <= offset; ++i) {
- testMatchImpl<QREMatch>(regexp,
- matchingMethodForStringRef,
- QStringRef(&subject, i, subject.length() - i),
- offset - i,
- matchType,
- matchOptions,
- result);
- }
}
typedef QRegularExpressionMatch (QRegularExpression::*QREMatchStringPMF)(const QString &, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const;
@@ -737,6 +724,18 @@ void tst_QRegularExpression::normalMatch_data()
// ***
m.clear();
+ m.isValid = true; m.hasMatch = true;
+ m.captured << "bcd";
+ QTest::newRow("match12")
+ << QRegularExpression("\\Bbcd\\B")
+ << "abcde"
+ << 1
+ << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption)
+ << m;
+
+ // ***
+
+ m.clear();
m.isValid = true;
QTest::newRow("nomatch01") << QRegularExpression("\\d+")
<< "a string"
@@ -1710,3 +1709,360 @@ void tst_QRegularExpression::JOptionUsage()
re.optimize();
QCOMPARE(re.isValid(), isValid);
}
+
+void tst_QRegularExpression::QStringAndQStringRefEquivalence()
+{
+ const QString subject = QStringLiteral("Mississippi");
+ {
+ const QRegularExpression re("\\Biss\\B");
+ QVERIFY(re.isValid());
+ {
+ const QRegularExpressionMatch match = re.match(subject);
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 1);
+ QCOMPARE(match.capturedEnd(), 4);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(QStringRef(&subject));
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 1);
+ QCOMPARE(match.capturedEnd(), 4);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject, 1);
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 1);
+ QCOMPARE(match.capturedEnd(), 4);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(QStringRef(&subject), 1);
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 1);
+ QCOMPARE(match.capturedEnd(), 4);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject.mid(1));
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject.midRef(1));
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject.mid(1), 1);
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject.midRef(1), 1);
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject, 4);
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 4);
+ QCOMPARE(match.capturedEnd(), 7);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(QStringRef(&subject), 4);
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 4);
+ QCOMPARE(match.capturedEnd(), 7);
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject.mid(4));
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(!match.hasMatch());
+ }
+ {
+ const QRegularExpressionMatch match = re.match(subject.midRef(4));
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(!match.hasMatch());
+ }
+
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match1 = i.next();
+ consistencyCheck(match1);
+ QVERIFY(match1.isValid());
+ QVERIFY(match1.hasMatch());
+ QCOMPARE(match1.captured(), QStringLiteral("iss"));
+ QCOMPARE(match1.capturedStart(), 1);
+ QCOMPARE(match1.capturedEnd(), 4);
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match2 = i.next();
+ consistencyCheck(match2);
+ QVERIFY(match2.isValid());
+ QVERIFY(match2.hasMatch());
+ QCOMPARE(match2.captured(), QStringLiteral("iss"));
+ QCOMPARE(match2.capturedStart(), 4);
+ QCOMPARE(match2.capturedEnd(), 7);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(QStringRef(&subject));
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match1 = i.next();
+ consistencyCheck(match1);
+ QVERIFY(match1.isValid());
+ QVERIFY(match1.hasMatch());
+ QCOMPARE(match1.captured(), QStringLiteral("iss"));
+ QCOMPARE(match1.capturedStart(), 1);
+ QCOMPARE(match1.capturedEnd(), 4);
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match2 = i.next();
+ consistencyCheck(match2);
+ QVERIFY(match2.isValid());
+ QVERIFY(match2.hasMatch());
+ QCOMPARE(match2.captured(), QStringLiteral("iss"));
+ QCOMPARE(match2.capturedStart(), 4);
+ QCOMPARE(match2.capturedEnd(), 7);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject, 1);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match1 = i.next();
+ consistencyCheck(match1);
+ QVERIFY(match1.isValid());
+ QVERIFY(match1.hasMatch());
+ QCOMPARE(match1.captured(), QStringLiteral("iss"));
+ QCOMPARE(match1.capturedStart(), 1);
+ QCOMPARE(match1.capturedEnd(), 4);
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match2 = i.next();
+ consistencyCheck(match2);
+ QVERIFY(match2.isValid());
+ QVERIFY(match2.hasMatch());
+ QCOMPARE(match2.captured(), QStringLiteral("iss"));
+ QCOMPARE(match2.capturedStart(), 4);
+ QCOMPARE(match2.capturedEnd(), 7);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(QStringRef(&subject), 1);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match1 = i.next();
+ consistencyCheck(match1);
+ QVERIFY(match1.isValid());
+ QVERIFY(match1.hasMatch());
+ QCOMPARE(match1.captured(), QStringLiteral("iss"));
+ QCOMPARE(match1.capturedStart(), 1);
+ QCOMPARE(match1.capturedEnd(), 4);
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match2 = i.next();
+ consistencyCheck(match2);
+ QVERIFY(match2.isValid());
+ QVERIFY(match2.hasMatch());
+ QCOMPARE(match2.captured(), QStringLiteral("iss"));
+ QCOMPARE(match2.capturedStart(), 4);
+ QCOMPARE(match2.capturedEnd(), 7);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.mid(1));
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(1));
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.mid(1), 1);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(1), 1);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.mid(1), 1);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(1), 1);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 3);
+ QCOMPARE(match.capturedEnd(), 6);
+
+ QVERIFY(!i.hasNext());
+ }
+
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject, 4);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 4);
+ QCOMPARE(match.capturedEnd(), 7);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(QStringRef(&subject), 4);
+ QVERIFY(i.isValid());
+
+ consistencyCheck(i);
+ QVERIFY(i.hasNext());
+ const QRegularExpressionMatch match = i.next();
+ consistencyCheck(match);
+ QVERIFY(match.isValid());
+ QVERIFY(match.hasMatch());
+ QCOMPARE(match.captured(), QStringLiteral("iss"));
+ QCOMPARE(match.capturedStart(), 4);
+ QCOMPARE(match.capturedEnd(), 7);
+
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.mid(4));
+ consistencyCheck(i);
+ QVERIFY(i.isValid());
+ QVERIFY(!i.hasNext());
+ }
+ {
+ QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(4));
+ consistencyCheck(i);
+ QVERIFY(i.isValid());
+ QVERIFY(!i.hasNext());
+ }
+ }
+}
diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h
index 578a4129ec..aed262d15d 100644
--- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h
+++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h
@@ -72,6 +72,7 @@ private slots:
void regularExpressionMatch();
void JOptionUsage_data();
void JOptionUsage();
+ void QStringAndQStringRefEquivalence();
private:
void provideRegularExpressions();
diff --git a/tests/auto/corelib/tools/qtime/tst_qtime.cpp b/tests/auto/corelib/tools/qtime/tst_qtime.cpp
index 9a9101b7e9..213b817c3d 100644
--- a/tests/auto/corelib/tools/qtime/tst_qtime.cpp
+++ b/tests/auto/corelib/tools/qtime/tst_qtime.cpp
@@ -84,6 +84,8 @@ void tst_QTime::addSecs_data()
QTest::newRow("Data0") << QTime(0,0,0) << 200 << QTime(0,3,20);
QTest::newRow("Data1") << QTime(0,0,0) << 20 << QTime(0,0,20);
+ QTest::newRow("overflow") << QTime(0,0,0) << (INT_MAX / 1000 + 1)
+ << QTime(0,0,0).addSecs((INT_MAX / 1000 + 1) % 86400);
}
void tst_QTime::addSecs()
diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST
index 7c9b8db3c3..3ec580ddde 100644
--- a/tests/auto/network/access/qnetworkreply/BLACKLIST
+++ b/tests/auto/network/access/qnetworkreply/BLACKLIST
@@ -1,16 +1,8 @@
osx
[ioGetFromBuiltinHttp:http+limited]
-osx
ubuntu-14.04
[ioGetFromBuiltinHttp:https+limited]
-osx
ubuntu-14.04
-[ioGetFromHttpBrokenServer:no-newline]
-osx
-[synchronousRequest:https]
-osx
-[SslHandshakeFailedError]
-osx
[httpAbort]
*
[backgroundRequestInterruption:ftp, bg, nobg]
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index 4d41d4beb1..debdc6bcb3 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -1078,7 +1078,7 @@ protected:
// clean up QAbstractSocket's residue:
while (client->bytesToWrite() > 0) {
qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
- if (!client->waitForBytesWritten(2000)) {
+ if (!client->waitForBytesWritten(10000)) {
qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
return;
}
@@ -1098,7 +1098,7 @@ protected:
measuredSentBytes += writeNextData(client, bytesToWrite);
while (client->bytesToWrite() > 0) {
- if (!client->waitForBytesWritten(2000)) {
+ if (!client->waitForBytesWritten(10000)) {
qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
return;
}
@@ -8203,7 +8203,7 @@ public slots:
m_receivedData += data;
if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
m_parsedHeaders = true;
- QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
+ QTimer::singleShot(qrand()%60, this, SLOT(closeDelayed())); // simulate random network latency
// This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
// In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
// This test catches that.
@@ -8309,11 +8309,12 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
// get the request started and the incoming socket connected
QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!QTestEventLoop::instance().timeout());
//qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
// Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
- QVERIFY(server.m_correctUploads > 5);
+ QVERIFY(server.m_correctUploads > 2);
// Because actually important is that we don't get any corruption:
QCOMPARE(server.m_corruptUploads, 0);
diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
index dc41a93906..2331bc19aa 100644
--- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
+++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
@@ -848,7 +848,11 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer_data()
QTest::addColumn<bool>("bind");
QTest::addColumn<QHostAddress>("peerAddress");
QHostAddress localhost(QHostAddress::LocalHost);
- QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first();
+ QList<QHostAddress> serverAddresses(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses());
+ if (serverAddresses.isEmpty())
+ return;
+
+ QHostAddress remote = serverAddresses.first();
QTest::newRow("localhost-unbound") << false << localhost;
QTest::newRow("localhost-bound") << true << localhost;
@@ -858,6 +862,8 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer_data()
void tst_QUdpSocket::writeDatagramToNonExistingPeer()
{
+ if (QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().isEmpty())
+ QFAIL("Could not find test server address");
QFETCH(bool, bind);
QFETCH(QHostAddress, peerAddress);
@@ -879,7 +885,11 @@ void tst_QUdpSocket::writeToNonExistingPeer_data()
{
QTest::addColumn<QHostAddress>("peerAddress");
QHostAddress localhost(QHostAddress::LocalHost);
- QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first();
+ QList<QHostAddress> serverAddresses(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses());
+ if (serverAddresses.isEmpty())
+ return;
+
+ QHostAddress remote = serverAddresses.first();
// write (required to be connected)
QTest::newRow("localhost") << localhost;
QTest::newRow("remote") << remote;
@@ -888,6 +898,8 @@ void tst_QUdpSocket::writeToNonExistingPeer_data()
void tst_QUdpSocket::writeToNonExistingPeer()
{
QSKIP("Connected-mode UDP sockets and their behaviour are erratic");
+ if (QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().isEmpty())
+ QFAIL("Could not find test server address");
QFETCH(QHostAddress, peerAddress);
quint16 peerPort = 34534;
qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
@@ -1114,6 +1126,9 @@ void tst_QUdpSocket::multicastTtlOption_data()
void tst_QUdpSocket::multicastTtlOption()
{
+#ifdef Q_OS_WINRT
+ QSKIP("WinRT does not support multicast.");
+#endif
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QHostAddress, bindAddress);
QFETCH(int, ttl);
@@ -1156,6 +1171,9 @@ void tst_QUdpSocket::multicastLoopbackOption_data()
void tst_QUdpSocket::multicastLoopbackOption()
{
+#ifdef Q_OS_WINRT
+ QSKIP("WinRT does not support multicast.");
+#endif
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QHostAddress, bindAddress);
QFETCH(int, loopback);
@@ -1186,6 +1204,9 @@ void tst_QUdpSocket::multicastJoinBeforeBind_data()
void tst_QUdpSocket::multicastJoinBeforeBind()
{
+#ifdef Q_OS_WINRT
+ QSKIP("WinRT does not support multicast.");
+#endif
QFETCH(QHostAddress, groupAddress);
QUdpSocket udpSocket;
@@ -1206,6 +1227,9 @@ void tst_QUdpSocket::multicastLeaveAfterClose_data()
void tst_QUdpSocket::multicastLeaveAfterClose()
{
+#ifdef Q_OS_WINRT
+ QSKIP("WinRT does not support multicast.");
+#endif
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QHostAddress, groupAddress);
if (setProxy)
@@ -1247,6 +1271,9 @@ void tst_QUdpSocket::setMulticastInterface_data()
void tst_QUdpSocket::setMulticastInterface()
{
+#ifdef Q_OS_WINRT
+ QSKIP("WinRT does not support multicast.");
+#endif
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QNetworkInterface, iface);
QFETCH(QHostAddress, address);
@@ -1295,6 +1322,9 @@ void tst_QUdpSocket::multicast_data()
void tst_QUdpSocket::multicast()
{
+#ifdef Q_OS_WINRT
+ QSKIP("WinRT does not support multicast.");
+#endif
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QHostAddress, bindAddress);
QFETCH(bool, bindResult);
diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
index 69007bd250..62c2c0a916 100644
--- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
+++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
@@ -1715,7 +1715,7 @@ static QRect characterRect(const QTextEdit &edit, int offset)
int h = fm.height();
qreal x = line.cursorToX(relativeOffset);
- QRect r(layoutPosition.x() + x, layoutPosition.y() + line.y(), w, h);
+ QRect r(layoutPosition.x() + x, layoutPosition.y() + line.y() + line.ascent() + fm.descent() - h, w, h);
r.moveTo(edit.viewport()->mapToGlobal(r.topLeft()));
return r;
diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
index 5c8f6eeeb8..a41d80d7dd 100644
--- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
+++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
@@ -306,6 +306,7 @@ private slots:
void clearButton();
void clearButtonVisibleAfterSettingText_QTBUG_45518();
void sideWidgets();
+ void sideWidgetsActionEvents();
void shouldShowPlaceholderText_data();
void shouldShowPlaceholderText();
@@ -4318,6 +4319,13 @@ void tst_QLineEdit::clearButtonVisibleAfterSettingText_QTBUG_45518()
#endif // QT_BUILD_INTERNAL
}
+static inline QIcon sideWidgetTestIcon()
+{
+ QImage image(QSize(20, 20), QImage::Format_ARGB32);
+ image.fill(Qt::yellow);
+ return QIcon(QPixmap::fromImage(image));
+}
+
void tst_QLineEdit::sideWidgets()
{
QWidget testWidget;
@@ -4325,9 +4333,7 @@ void tst_QLineEdit::sideWidgets()
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);
+ QAction *iconAction = new QAction(sideWidgetTestIcon(), QString(), lineEdit);
QWidgetAction *label1Action = new QWidgetAction(lineEdit);
label1Action->setDefaultWidget(new QLabel(QStringLiteral("l1")));
QWidgetAction *label2Action = new QWidgetAction(lineEdit);
@@ -4354,6 +4360,38 @@ void tst_QLineEdit::sideWidgets()
lineEdit->addAction(iconAction);
}
+void tst_QLineEdit::sideWidgetsActionEvents()
+{
+ // QTBUG-39660, verify whether action events are handled by the widget.
+ 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));
+ QAction *iconAction = lineEdit->addAction(sideWidgetTestIcon(), QLineEdit::LeadingPosition);
+ testWidget.move(300, 300);
+ testWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&testWidget));
+
+ QWidget *toolButton = Q_NULLPTR;
+ foreach (QWidget *w, iconAction->associatedWidgets()) {
+ if (qobject_cast<QToolButton *>(w)) {
+ toolButton = w;
+ break;
+ }
+ }
+ QVERIFY(toolButton);
+
+ QVERIFY(toolButton->isVisible());
+ QVERIFY(toolButton->isEnabled());
+
+ iconAction->setEnabled(false);
+ QVERIFY(!toolButton->isEnabled());
+
+ iconAction->setVisible(false);
+ QVERIFY(!toolButton->isVisible());
+}
+
Q_DECLARE_METATYPE(Qt::AlignmentFlag)
void tst_QLineEdit::shouldShowPlaceholderText_data()
{
diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
index 9e24f373eb..baf60551c4 100644
--- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
+++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
@@ -128,7 +128,7 @@ private slots:
void taskQTBUG4965_escapeEaten();
#endif
void taskQTBUG11823_crashwithInvisibleActions();
- void closeOnSecondClick();
+ void closeOnSecondClickAndOpenOnThirdClick();
void cornerWidgets_data();
void cornerWidgets();
@@ -1312,7 +1312,7 @@ void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions()
QCOMPARE(menubar.activeAction(), m); //the active action shouldn't have changed
}
-void tst_QMenuBar::closeOnSecondClick() // QTBUG-32807, menu should close on 2nd click.
+void tst_QMenuBar::closeOnSecondClickAndOpenOnThirdClick() // QTBUG-32807, menu should close on 2nd click.
{
QMainWindow mainWindow;
mainWindow.resize(300, 200);
@@ -1322,17 +1322,20 @@ void tst_QMenuBar::closeOnSecondClick() // QTBUG-32807, menu should close on 2nd
#endif
QMenuBar *menuBar = mainWindow.menuBar();
menuBar->setNativeMenuBar(false);
- QMenu *fileMenu = menuBar->addMenu(QStringLiteral("closeOnSecondClick"));
+ QMenu *fileMenu = menuBar->addMenu(QStringLiteral("OpenCloseOpen"));
fileMenu->addAction(QStringLiteral("Quit"));
mainWindow.show();
QApplication::setActiveWindow(&mainWindow);
QVERIFY(QTest::qWaitForWindowActive(&mainWindow));
const QPoint center = menuBar->actionGeometry(fileMenu->menuAction()).center();
+ const QPoint globalPos = menuBar->mapToGlobal(center);
QTest::mouseMove(menuBar, center);
QTest::mouseClick(menuBar, Qt::LeftButton, 0, center);
QTRY_VERIFY(fileMenu->isVisible());
- QTest::mouseClick(menuBar, Qt::LeftButton, 0, center);
+ QTest::mouseClick(fileMenu, Qt::LeftButton, 0, fileMenu->mapFromGlobal(globalPos));
QTRY_VERIFY(!fileMenu->isVisible());
+ QTest::mouseClick(menuBar, Qt::LeftButton, 0, center);
+ QTRY_VERIFY(fileMenu->isVisible());
}
Q_DECLARE_METATYPE(Qt::Corner)