summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-11-30 00:51:32 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2017-11-30 00:51:32 +0000
commit498ef7f9d77fca75bcba2f657aaac38c8dc78aea (patch)
tree025636092945c4d8c0e9de6fa69db15da204b648 /src
parent4d0add31fd0a69aca7c7c852f22531dd98922c62 (diff)
parent153e8b49adfe210cb00490284a14c94c08e03c3f (diff)
Merge "Merge remote-tracking branch 'origin/5.10' into dev" into refs/staging/dev
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/freetype/BDF-LICENSE.txt43
-rw-r--r--src/3rdparty/freetype/LICENSE.txt551
-rw-r--r--src/3rdparty/freetype/PCF-LICENSE.txt20
-rw-r--r--src/3rdparty/freetype/ZLIB-LICENSE.txt20
-rw-r--r--src/3rdparty/freetype/qt_attribution.json69
-rw-r--r--src/3rdparty/libpng/ANNOUNCE77
-rw-r--r--src/3rdparty/libpng/CHANGES51
-rw-r--r--src/3rdparty/libpng/LICENSE4
-rw-r--r--src/3rdparty/libpng/README2
-rw-r--r--src/3rdparty/libpng/libpng-manual.txt21
-rw-r--r--src/3rdparty/libpng/png.c32
-rw-r--r--src/3rdparty/libpng/png.h28
-rw-r--r--src/3rdparty/libpng/pngconf.h2
-rw-r--r--src/3rdparty/libpng/pnglibconf.h4
-rw-r--r--src/3rdparty/libpng/pngread.c14
-rw-r--r--src/3rdparty/libpng/pngrtran.c22
-rw-r--r--src/3rdparty/libpng/pngrutil.c47
-rw-r--r--src/3rdparty/libpng/pngtrans.c6
-rw-r--r--src/3rdparty/libpng/pngwrite.c2
-rw-r--r--src/3rdparty/libpng/qt_attribution.json2
-rw-r--r--src/corelib/global/qcompilerdetection.h6
-rw-r--r--src/corelib/global/qfloat16.h2
-rw-r--r--src/corelib/global/qrandom.cpp926
-rw-r--r--src/corelib/global/qrandom.h183
-rw-r--r--src/corelib/global/qrandom_p.h18
-rw-r--r--src/corelib/io/qfileselector.cpp6
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp4
-rw-r--r--src/corelib/io/qiodevice.cpp2
-rw-r--r--src/corelib/io/qprocess_win.cpp7
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp34
-rw-r--r--src/corelib/io/qtemporaryfile.cpp2
-rw-r--r--src/corelib/io/qurl.cpp14
-rw-r--r--src/corelib/kernel/qfunctions_winrt.h1
-rw-r--r--src/corelib/kernel/qwineventnotifier.cpp5
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp2
-rw-r--r--src/corelib/thread/qmutex.h6
-rw-r--r--src/corelib/thread/qsemaphore.h6
-rw-r--r--src/corelib/tools/qdatetimeparser.cpp1
-rw-r--r--src/corelib/tools/qhash.cpp1
-rw-r--r--src/corelib/tools/qversionnumber.cpp4
-rw-r--r--src/dbus/qdbusinternalfilters.cpp2
-rw-r--r--src/gui/image/qimagereader.cpp10
-rw-r--r--src/gui/image/qpixmap_blitter.cpp3
-rw-r--r--src/gui/kernel/qhighdpiscaling_p.h3
-rw-r--r--src/gui/kernel/qopenglcontext.cpp1
-rw-r--r--src/gui/kernel/qwindow.cpp7
-rw-r--r--src/gui/opengl/qopenglgradientcache.cpp3
-rw-r--r--src/gui/painting/qcoregraphics.mm1
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp3
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp3
-rw-r--r--src/gui/text/qfont.cpp22
-rw-r--r--src/gui/text/qtexttable.cpp4
-rw-r--r--src/gui/vulkan/qvulkaninstance.h4
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp44
-rw-r--r--src/gui/vulkan/qvulkanwindow.h4
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp2
-rw-r--r--src/network/access/qhttp2protocolhandler_p.h10
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp82
-rw-r--r--src/network/kernel/kernel.pri2
-rw-r--r--src/network/kernel/qdnslookup.cpp11
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp20
-rw-r--r--src/network/ssl/qsslkey_qt.cpp2
-rw-r--r--src/network/ssl/qsslsocket.cpp14
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp3
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp30
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h2
-rw-r--r--src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp12
-rw-r--r--src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp2
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp14
-rw-r--r--src/plugins/platforms/cocoa/messages.cpp2
-rw-r--r--src/plugins/platforms/cocoa/messages.h11
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm37
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm16
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm11
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm14
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm20
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm18
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm32
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm1
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm25
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp32
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp2
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci.cpp2
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql.cpp191
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql_p.h24
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm567
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p.h4
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p_p.h72
-rw-r--r--src/testlib/qtest_gui.h2
-rw-r--r--src/testlib/qtesthelpers_p.h112
-rw-r--r--src/testlib/testlib.pro3
-rw-r--r--src/tools/moc/main.cpp1
-rw-r--r--src/tools/moc/preprocessor.cpp2
-rw-r--r--src/widgets/accessible/simplewidgets.cpp2
-rw-r--r--src/widgets/dialogs/qwizard.cpp4
-rw-r--r--src/widgets/itemviews/qheaderview.cpp8
-rw-r--r--src/widgets/itemviews/qlistview.cpp15
-rw-r--r--src/widgets/kernel/qaction.cpp2
-rw-r--r--src/widgets/kernel/qlayout.cpp3
-rw-r--r--src/widgets/kernel/qshortcut.cpp2
-rw-r--r--src/widgets/kernel/qwidget.cpp2
-rw-r--r--src/widgets/widgets/qabstractbutton.cpp3
-rw-r--r--src/widgets/widgets/qmainwindow.cpp1
-rw-r--r--src/widgets/widgets/qmenu.cpp114
-rw-r--r--src/widgets/widgets/qmenu_p.h151
-rw-r--r--src/widgets/widgets/qmenubar.cpp54
-rw-r--r--src/widgets/widgets/qmenubar_p.h4
115 files changed, 2806 insertions, 1357 deletions
diff --git a/src/3rdparty/freetype/BDF-LICENSE.txt b/src/3rdparty/freetype/BDF-LICENSE.txt
new file mode 100644
index 0000000000..6fb375cf8b
--- /dev/null
+++ b/src/3rdparty/freetype/BDF-LICENSE.txt
@@ -0,0 +1,43 @@
+Copyright (C) 2001-2002 by Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*** Portions of the driver (that is, bdflib.c and bdf.h):
+
+Copyright 2000 Computing Research Labs, New Mexico State University
+Copyright 2001-2002, 2011 Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/3rdparty/freetype/LICENSE.txt b/src/3rdparty/freetype/LICENSE.txt
new file mode 100644
index 0000000000..382225f105
--- /dev/null
+++ b/src/3rdparty/freetype/LICENSE.txt
@@ -0,0 +1,551 @@
+The FreeType 2 font engine is copyrighted work and cannot be used
+legally without a software license. In order to make this project
+usable to a vast majority of developers, we distribute it under two
+mutually exclusive open-source licenses.
+
+This means that *you* must choose *one* of the two licenses described
+below, then obey all its terms and conditions when using FreeType 2 in
+any of your projects or products.
+
+ - The FreeType License, found in the file `FTL.TXT', which is similar
+ to the original BSD license *with* an advertising clause that forces
+ you to explicitly cite the FreeType project in your product's
+ documentation. All details are in the license file. This license
+ is suited to products which don't use the GNU General Public
+ License.
+
+ Note that this license is compatible to the GNU General Public
+ License version 3, but not version 2.
+
+ - The GNU General Public License version 2, found in `GPLv2.TXT' (any
+ later version can be used also), for programs which already use the
+ GPL. Note that the FTL is incompatible with GPLv2 due to its
+ advertisement clause.
+
+The contributed BDF and PCF drivers come with a license similar to that
+of the X Window System. It is compatible to the above two licenses (see
+file src/bdf/README and src/pcf/README).
+
+The gzip module uses the zlib license (see src/gzip/zlib.h) which too is
+compatible to the above two licenses.
+
+The MD5 checksum support (only used for debugging in development builds)
+is in the public domain.
+
+
+--- FDL.TXT ---
+
+ The FreeType Project LICENSE
+ ----------------------------
+
+ 2006-Jan-27
+
+ Copyright 1996-2002, 2006 by
+ David Turner, Robert Wilhelm, and Werner Lemberg
+
+
+
+Introduction
+============
+
+ The FreeType Project is distributed in several archive packages;
+ some of them may contain, in addition to the FreeType font engine,
+ various tools and contributions which rely on, or relate to, the
+ FreeType Project.
+
+ This license applies to all files found in such packages, and
+ which do not fall under their own explicit license. The license
+ affects thus the FreeType font engine, the test programs,
+ documentation and makefiles, at the very least.
+
+ This license was inspired by the BSD, Artistic, and IJG
+ (Independent JPEG Group) licenses, which all encourage inclusion
+ and use of free software in commercial and freeware products
+ alike. As a consequence, its main points are that:
+
+ o We don't promise that this software works. However, we will be
+ interested in any kind of bug reports. (`as is' distribution)
+
+ o You can use this software for whatever you want, in parts or
+ full form, without having to pay us. (`royalty-free' usage)
+
+ o You may not pretend that you wrote this software. If you use
+ it, or only parts of it, in a program, you must acknowledge
+ somewhere in your documentation that you have used the
+ FreeType code. (`credits')
+
+ We specifically permit and encourage the inclusion of this
+ software, with or without modifications, in commercial products.
+ We disclaim all warranties covering The FreeType Project and
+ assume no liability related to The FreeType Project.
+
+
+ Finally, many people asked us for a preferred form for a
+ credit/disclaimer to use in compliance with this license. We thus
+ encourage you to use the following text:
+
+ """
+ Portions of this software are copyright © <year> The FreeType
+ Project (www.freetype.org). All rights reserved.
+ """
+
+ Please replace <year> with the value from the FreeType version you
+ actually use.
+
+
+Legal Terms
+===========
+
+0. Definitions
+--------------
+
+ Throughout this license, the terms `package', `FreeType Project',
+ and `FreeType archive' refer to the set of files originally
+ distributed by the authors (David Turner, Robert Wilhelm, and
+ Werner Lemberg) as the `FreeType Project', be they named as alpha,
+ beta or final release.
+
+ `You' refers to the licensee, or person using the project, where
+ `using' is a generic term including compiling the project's source
+ code as well as linking it to form a `program' or `executable'.
+ This program is referred to as `a program using the FreeType
+ engine'.
+
+ This license applies to all files distributed in the original
+ FreeType Project, including all source code, binaries and
+ documentation, unless otherwise stated in the file in its
+ original, unmodified form as distributed in the original archive.
+ If you are unsure whether or not a particular file is covered by
+ this license, you must contact us to verify this.
+
+ The FreeType Project is copyright (C) 1996-2000 by David Turner,
+ Robert Wilhelm, and Werner Lemberg. All rights reserved except as
+ specified below.
+
+1. No Warranty
+--------------
+
+ THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
+ USE, OF THE FREETYPE PROJECT.
+
+2. Redistribution
+-----------------
+
+ This license grants a worldwide, royalty-free, perpetual and
+ irrevocable right and license to use, execute, perform, compile,
+ display, copy, create derivative works of, distribute and
+ sublicense the FreeType Project (in both source and object code
+ forms) and derivative works thereof for any purpose; and to
+ authorize others to exercise some or all of the rights granted
+ herein, subject to the following conditions:
+
+ o Redistribution of source code must retain this license file
+ (`FTL.TXT') unaltered; any additions, deletions or changes to
+ the original files must be clearly indicated in accompanying
+ documentation. The copyright notices of the unaltered,
+ original files must be preserved in all copies of source
+ files.
+
+ o Redistribution in binary form must provide a disclaimer that
+ states that the software is based in part of the work of the
+ FreeType Team, in the distribution documentation. We also
+ encourage you to put an URL to the FreeType web page in your
+ documentation, though this isn't mandatory.
+
+ These conditions apply to any software derived from or based on
+ the FreeType Project, not just the unmodified files. If you use
+ our work, you must acknowledge us. However, no fee need be paid
+ to us.
+
+3. Advertising
+--------------
+
+ Neither the FreeType authors and contributors nor you shall use
+ the name of the other for commercial, advertising, or promotional
+ purposes without specific prior written permission.
+
+ We suggest, but do not require, that you use one or more of the
+ following phrases to refer to this software in your documentation
+ or advertising materials: `FreeType Project', `FreeType Engine',
+ `FreeType library', or `FreeType Distribution'.
+
+ As you have not signed this license, you are not required to
+ accept it. However, as the FreeType Project is copyrighted
+ material, only this license, or another one contracted with the
+ authors, grants you the right to use, distribute, and modify it.
+ Therefore, by using, distributing, or modifying the FreeType
+ Project, you indicate that you understand and accept all the terms
+ of this license.
+
+4. Contacts
+-----------
+
+ There are two mailing lists related to FreeType:
+
+ o freetype@nongnu.org
+
+ Discusses general use and applications of FreeType, as well as
+ future and wanted additions to the library and distribution.
+ If you are looking for support, start in this list if you
+ haven't found anything to help you in the documentation.
+
+ o freetype-devel@nongnu.org
+
+ Discusses bugs, as well as engine internals, design issues,
+ specific licenses, porting, etc.
+
+ Our home page can be found at
+
+ http://www.freetype.org
+
+--- end of FDL.TXT ---
+
+--- GPLv2.TXT ---
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+--- end of GPLv2.TXT ---
+
diff --git a/src/3rdparty/freetype/PCF-LICENSE.txt b/src/3rdparty/freetype/PCF-LICENSE.txt
new file mode 100644
index 0000000000..3f3a3b3f0c
--- /dev/null
+++ b/src/3rdparty/freetype/PCF-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (C) 2000 by Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/3rdparty/freetype/ZLIB-LICENSE.txt b/src/3rdparty/freetype/ZLIB-LICENSE.txt
new file mode 100644
index 0000000000..abbdfcc017
--- /dev/null
+++ b/src/3rdparty/freetype/ZLIB-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
+Jean-loup Gailly Mark Adler
+jloup@gzip.org madler@alumni.caltech.edu
diff --git a/src/3rdparty/freetype/qt_attribution.json b/src/3rdparty/freetype/qt_attribution.json
index 6c11f1b617..e00f2062b0 100644
--- a/src/3rdparty/freetype/qt_attribution.json
+++ b/src/3rdparty/freetype/qt_attribution.json
@@ -1,13 +1,56 @@
-{
- "Id": "freetype",
- "Name": "Freetype 2",
- "QDocModule": "qtgui",
- "QtUsage": "Optionally used in Qt GUI and platform plugins. Configure with -no-freetype, or -system-freetype to avoid.",
-
- "Description": "FreeType is a freely available software library to render fonts.",
- "Homepage": "http://www.freetype.org",
- "License": "Freetype Project License or GNU General Public License v2.0 only",
- "LicenseId": "FTL or GPL-2.0",
- "LicenseFile": "docs/LICENSE.TXT",
- "Copyright": "Copyright 2006-2015 by David Turner, Robert Wilhelm, and Werner Lemberg."
-}
+[
+ {
+ "Id": "freetype",
+ "Name": "Freetype 2",
+ "QDocModule": "qtgui",
+ "QtUsage": "Optionally used in Qt GUI and platform plugins. Configure with -no-freetype, or -system-freetype to avoid.",
+
+ "Description": "FreeType is a freely available software library to render fonts.",
+ "Homepage": "http://www.freetype.org",
+ "License": "Freetype Project License or GNU General Public License v2.0 only",
+ "LicenseId": "FTL OR GPL-2.0",
+ "LicenseFile": "LICENSE.TXT",
+ "Copyright": "Copyright 2006-2015 by David Turner, Robert Wilhelm, and Werner Lemberg."
+ },
+ {
+ "Id": "freetype-zlib",
+ "Name": "Freetype 2 - zlib",
+ "QDocModule": "qtgui",
+ "QtUsage": "Optionally used in Qt GUI and platform plugins. Configure with -no-freetype, or -system-freetype to avoid.",
+
+ "Description": "FreeType is a freely available software library to render fonts.",
+ "Homepage": "http://www.freetype.org",
+ "License": "zlib License",
+ "LicenseId": "Zlib",
+ "LicenseFile": "ZLIB-LICENSE.TXT",
+ "Copyright": "Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler"
+ },
+ {
+ "Id": "freetype-bdf",
+ "Name": "Freetype 2 - Bitmap Distribution Format (BDF) support",
+ "QDocModule": "qtgui",
+ "QtUsage": "Optionally used in Qt GUI and platform plugins. Configure with -no-freetype, or -system-freetype to avoid.",
+
+ "Description": "FreeType is a freely available software library to render fonts.",
+ "Homepage": "http://www.freetype.org",
+ "License": "MIT License",
+ "LicenseId": "MIT",
+ "LicenseFile": "BDF-LICENSE.TXT",
+ "Copyright": "Copyright (C) 2001-2002 by Francesco Zappa Nardelli
+Copyright 2000 Computing Research Labs, New Mexico State University
+Copyright 2001-2002, 2011 Francesco Zappa Nardelli"
+ },
+ {
+ "Id": "freetype-pcf",
+ "Name": "Freetype 2 - Portable Compiled Format (PCF) support",
+ "QDocModule": "qtgui",
+ "QtUsage": "Optionally used in Qt GUI and platform plugins. Configure with -no-freetype, or -system-freetype to avoid.",
+
+ "Description": "FreeType is a freely available software library to render fonts.",
+ "Homepage": "http://www.freetype.org",
+ "License": "MIT License",
+ "LicenseId": "MIT",
+ "LicenseFile": "PCF-LICENSE.TXT",
+ "Copyright": "Copyright (C) 2000 by Francesco Zappa Nardelli"
+ }
+]
diff --git a/src/3rdparty/libpng/ANNOUNCE b/src/3rdparty/libpng/ANNOUNCE
index 3cbe5a926e..0f66c0d1da 100644
--- a/src/3rdparty/libpng/ANNOUNCE
+++ b/src/3rdparty/libpng/ANNOUNCE
@@ -1,4 +1,4 @@
-Libpng 1.6.32 - August 24, 2017
+Libpng 1.6.34 - September 29, 2017
This is a public release of libpng, intended for use in production codes.
@@ -7,79 +7,24 @@ Files available for download:
Source files with LF line endings (for Unix/Linux) and with a
"configure" script
- libpng-1.6.32.tar.xz (LZMA-compressed, recommended)
- libpng-1.6.32.tar.gz
+ libpng-1.6.34.tar.xz (LZMA-compressed, recommended)
+ libpng-1.6.34.tar.gz
Source files with CRLF line endings (for Windows), without the
"configure" script
- lpng1632.7z (LZMA-compressed, recommended)
- lpng1632.zip
+ lpng1634.7z (LZMA-compressed, recommended)
+ lpng1634.zip
Other information:
- libpng-1.6.32-README.txt
- libpng-1.6.32-LICENSE.txt
- libpng-1.6.32-*.asc (armored detached GPG signatures)
+ libpng-1.6.34-README.txt
+ libpng-1.6.34-LICENSE.txt
+ libpng-1.6.34-*.asc (armored detached GPG signatures)
-Changes since the last public release (1.6.31):
- Avoid possible NULL dereference in png_handle_eXIf when benign_errors
- are allowed. Avoid leaking the input buffer "eXIf_buf".
- Eliminated png_ptr->num_exif member from pngstruct.h and added num_exif
- to arguments for png_get_eXIf() and png_set_eXIf().
- Added calls to png_handle_eXIf(() in pngread.c and png_write_eXIf() in
- pngwrite.c, and made various other fixes to png_write_eXIf().
- Changed name of png_get_eXIF and png_set_eXIf() to png_get_eXIf_1() and
- png_set_eXIf_1(), respectively, to avoid breaking API compatibility
- with libpng-1.6.31.
- Updated contrib/libtests/pngunknown.c with eXIf chunk.
- Initialized btoa[] in pngstest.c
- Stop memory leak when returning from png_handle_eXIf() with an error
- (Bug report from the OSS-fuzz project).
- Replaced local eXIf_buf with info_ptr-eXIf_buf in png_handle_eXIf().
- Update libpng.3 and libpng-manual.txt about eXIf functions.
- Restored png_get_eXIf() and png_set_eXIf() to maintain API compatability.
- Removed png_get_eXIf_1() and png_set_eXIf_1().
- Check length of all chunks except IDAT against user limit to fix an
- OSS-fuzz issue.
- Check length of IDAT against maximum possible IDAT size, accounting
- for height, rowbytes, interlacing and zlib/deflate overhead.
- Restored png_get_eXIf_1() and png_set_eXIf_1(), because strlen(eXIf_buf)
- does not work (the eXIf chunk data can contain zeroes).
- Require cmake-2.8.8 in CMakeLists.txt. Revised symlink creation,
- no longer using deprecated cmake LOCATION feature (Clifford Yapp).
- Fixed five-byte error in the calculation of IDAT maximum possible size.
- Moved chunk-length check into a png_check_chunk_length() private
- function (Suggested by Max Stepin).
- Moved bad pngs from tests to contrib/libtests/crashers
- Moved testing of bad pngs into a separate tests/pngtest-badpngs script
- Added the --xfail (expected FAIL) option to pngtest.c. It writes XFAIL
- in the output but PASS for the libpng test.
- Require cmake-3.0.2 in CMakeLists.txt (Clifford Yapp).
- Fix "const" declaration info_ptr argument to png_get_eXIf_1() and the
- num_exif argument to png_get_eXIf_1() (Github Issue 171).
- Added "eXIf" to "chunks_to_ignore[]" in png_set_keep_unknown_chunks().
- Added huge_IDAT.png and empty_ancillary_chunks.png to testpngs/crashers.
- Make pngtest --strict, --relax, --xfail options imply -m (multiple).
- Removed unused chunk_name parameter from png_check_chunk_length().
- Relocated setting free_me for eXIf data, to stop an OSS-fuzz leak.
- Initialize profile_header[] in png_handle_iCCP() to fix OSS-fuzz issue.
- Initialize png_ptr->row_buf[0] to 255 in png_read_row() to fix OSS-fuzz UMR.
- Attempt to fix a UMR in png_set_text_2() to fix OSS-fuzz issue.
- Increase minimum zlib stream from 9 to 14 in png_handle_iCCP(), to account
- for the minimum 'deflate' stream, and relocate the test to a point
- after the keyword has been read.
- Check that the eXIf chunk has at least 2 bytes and begins with "II" or "MM".
- Added a set of "huge_xxxx_chunk.png" files to contrib/testpngs/crashers,
- one for each known chunk type, with length = 2GB-1.
- Check for 0 return from png_get_rowbytes() and added some (size_t) typecasts
- in contrib/pngminus/*.c to stop some Coverity issues (162705, 162706,
- and 162707).
- Renamed chunks in contrib/testpngs/crashers to avoid having files whose
- names differ only in case; this causes problems with some platforms
- (github issue #172).
- Added contrib/oss-fuzz directory which contains files used by the oss-fuzz
- project (https://github.com/google/oss-fuzz/tree/master/projects/libpng).
+Changes since the last public release (1.6.33):
+ Removed contrib/pngsuite/i*.png; some of these were incorrect and caused
+ test failures.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit
diff --git a/src/3rdparty/libpng/CHANGES b/src/3rdparty/libpng/CHANGES
index 14e60dd269..4b82118910 100644
--- a/src/3rdparty/libpng/CHANGES
+++ b/src/3rdparty/libpng/CHANGES
@@ -833,7 +833,7 @@ Version 1.0.7beta11 [May 7, 2000]
Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes
which are no longer used.
Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is
- defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED
+ defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXt_SUPPORTED
is defined.
Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory
overrun when old applications fill the info_ptr->text structure directly.
@@ -5939,7 +5939,7 @@ Version 1.6.32beta06 [August 2, 2017]
Version 1.6.32beta07 [August 3, 2017]
Check length of all chunks except IDAT against user limit to fix an
- OSS-fuzz issue.
+ OSS-fuzz issue (Fixes CVE-2017-12652).
Version 1.6.32beta08 [August 3, 2017]
Check length of IDAT against maximum possible IDAT size, accounting
@@ -5994,6 +5994,53 @@ Version 1.6.32rc02 [August 22, 2017]
Version 1.6.32 [August 24, 2017]
No changes.
+Version 1.6.33beta01 [August 28, 2017]
+ Added PNGMINUS_UNUSED macro to contrib/pngminus/p*.c and added missing
+ parenthesis in contrib/pngminus/pnm2png.c (bug report by Christian Hesse).
+ Fixed off-by-one error in png_do_check_palette_indexes() (Bug report
+ by Mick P., Source Forge Issue #269).
+
+Version 1.6.33beta02 [September 3, 2017]
+ Initialize png_handler.row_ptr in contrib/oss-fuzz/libpng_read_fuzzer.cc
+ to fix shortlived oss-fuzz issue 3234.
+ Compute a larger limit on IDAT because some applications write a deflate
+ buffer for each row (Bug report by Andrew Church).
+ Use current date (DATE) instead of release-date (RDATE) in last
+ changed date of contrib/oss-fuzz files.
+ Enabled ARM support in CMakeLists.txt (Bernd Kuhls).
+
+Version 1.6.33beta03 [September 14, 2017]
+ Fixed incorrect typecast of some arguments to png_malloc() and
+ png_calloc() that were png_uint_32 instead of png_alloc_size_t
+ (Bug report by "irwir" in Github libpng issue #175).
+ Use pnglibconf.h.prebuilt when building for ANDROID with cmake (Github
+ issue 162, by rcdailey).
+
+Version 1.6.33rc01 [September 20, 2017]
+ Initialize memory allocated by png_inflate to zero, using memset, to
+ stop an oss-fuzz "use of uninitialized value" detection in png_set_text_2()
+ due to truncated iTXt or zTXt chunk.
+ Initialize memory allocated by png_read_buffer to zero, using memset, to
+ stop an oss-fuzz "use of uninitialized value" detection in
+ png_icc_check_tag_table() due to truncated iCCP chunk.
+ Removed a redundant test (suggested by "irwir" in Github issue #180).
+
+Version 1.6.33rc02 [September 23, 2017]
+ Added an interlaced version of each file in contrib/pngsuite.
+ Relocate new memset() call in pngrutil.c.
+ Removed more redundant tests (suggested by "irwir" in Github issue #180).
+ Add support for loading images with associated alpha in the Simplified
+ API (Samuel Williams).
+
+Version 1.6.33 [September 28, 2017]
+ Revert contrib/oss-fuzz/libpng_read_fuzzer.cc to libpng-1.6.32 state.
+ Initialize png_handler.row_ptr in contrib/oss-fuzz/libpng_read_fuzzer.cc
+ Add end_info structure and png_read_end() to the libpng fuzzer.
+
+Version 1.6.34 [September 29, 2017]
+ Removed contrib/pngsuite/i*.png; some of these were incorrect and caused
+ test failures.
+
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit
https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/3rdparty/libpng/LICENSE b/src/3rdparty/libpng/LICENSE
index e803911d37..4cda4fa0ad 100644
--- a/src/3rdparty/libpng/LICENSE
+++ b/src/3rdparty/libpng/LICENSE
@@ -10,7 +10,7 @@ this sentence.
This code is released under the libpng license.
-libpng versions 1.0.7, July 1, 2000 through 1.6.32, August 24, 2017 are
+libpng versions 1.0.7, July 1, 2000 through 1.6.34, September 29, 2017 are
Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
derived from libpng-1.0.6, and are distributed according to the same
disclaimer and license as libpng-1.0.6 with the following individuals
@@ -130,4 +130,4 @@ any encryption software. See the EAR, paragraphs 734.3(b)(3) and
Glenn Randers-Pehrson
glennrp at users.sourceforge.net
-April 1, 2017
+September 29, 2017
diff --git a/src/3rdparty/libpng/README b/src/3rdparty/libpng/README
index 71292715eb..0da5a5ef83 100644
--- a/src/3rdparty/libpng/README
+++ b/src/3rdparty/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.32 - August 24, 2017 (shared library 16.0)
+README for libpng version 1.6.34 - September 29, 2017 (shared library 16.0)
See the note about version numbers near the top of png.h
See INSTALL for instructions on how to install libpng.
diff --git a/src/3rdparty/libpng/libpng-manual.txt b/src/3rdparty/libpng/libpng-manual.txt
index e34b1436f5..d4407ef2ea 100644
--- a/src/3rdparty/libpng/libpng-manual.txt
+++ b/src/3rdparty/libpng/libpng-manual.txt
@@ -1,6 +1,6 @@
libpng-manual.txt - A description on how to use and modify libpng
- libpng version 1.6.32 - August 24, 2017
+ libpng version 1.6.34 - September 29, 2017
Updated and distributed by Glenn Randers-Pehrson
<glennrp at users.sourceforge.net>
Copyright (c) 1998-2017 Glenn Randers-Pehrson
@@ -11,7 +11,7 @@ libpng-manual.txt - A description on how to use and modify libpng
Based on:
- libpng versions 0.97, January 1998, through 1.6.32 - August 24, 2017
+ libpng versions 0.97, January 1998, through 1.6.34 - September 29, 2017
Updated and distributed by Glenn Randers-Pehrson
Copyright (c) 1998-2017 Glenn Randers-Pehrson
@@ -986,8 +986,17 @@ premultiplication.
png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
-This is the default libpng handling of the alpha channel - it is not
-pre-multiplied into the color components. In addition the call states
+Choices for the alpha_mode are
+
+ PNG_ALPHA_PNG 0 /* according to the PNG standard */
+ PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */
+ PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */
+ PNG_ALPHA_PREMULTIPLIED 1 /* as above */
+ PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */
+ PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */
+
+PNG_ALPHA_PNG is the default libpng handling of the alpha channel. It is not
+pre-multiplied into the color components. In addition the call states
that the output is for a sRGB system and causes all PNG files without gAMA
chunks to be assumed to be encoded using sRGB.
@@ -1002,7 +1011,7 @@ early Mac systems behaved.
This is the classic Jim Blinn approach and will work in academic
environments where everything is done by the book. It has the shortcoming
of assuming that input PNG data with no gamma information is linear - this
-is unlikely to be correct unless the PNG files where generated locally.
+is unlikely to be correct unless the PNG files were generated locally.
Most of the time the output precision will be so low as to show
significant banding in dark areas of the image.
@@ -5405,7 +5414,7 @@ Since the PNG Development group is an ad-hoc body, we can't make
an official declaration.
This is your unofficial assurance that libpng from version 0.71 and
-upward through 1.6.32 are Y2K compliant. It is my belief that earlier
+upward through 1.6.34 are Y2K compliant. It is my belief that earlier
versions were also Y2K compliant.
Libpng only has two year fields. One is a 2-byte unsigned integer
diff --git a/src/3rdparty/libpng/png.c b/src/3rdparty/libpng/png.c
index 2352df13cb..ff02c56518 100644
--- a/src/3rdparty/libpng/png.c
+++ b/src/3rdparty/libpng/png.c
@@ -1,7 +1,7 @@
/* png.c - location for general purpose libpng functions
*
- * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -14,7 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_32 Your_png_h_is_not_version_1_6_32;
+typedef png_libpng_version_1_6_34 Your_png_h_is_not_version_1_6_34;
#ifdef __GNUC__
/* The version tests may need to be added to, but the problem warning has
@@ -816,14 +816,14 @@ png_get_copyright(png_const_structrp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
- "libpng version 1.6.32 - August 24, 2017" PNG_STRING_NEWLINE \
+ "libpng version 1.6.34 - September 29, 2017" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
"Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
PNG_STRING_NEWLINE;
# else
- return "libpng version 1.6.32 - August 24, 2017\
+ return "libpng version 1.6.34 - September 29, 2017\
Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
@@ -1913,12 +1913,12 @@ png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)
return png_icc_profile_error(png_ptr, colorspace, "sRGB",
- (unsigned)intent, "invalid sRGB rendering intent");
+ (png_alloc_size_t)intent, "invalid sRGB rendering intent");
if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&
colorspace->rendering_intent != intent)
return png_icc_profile_error(png_ptr, colorspace, "sRGB",
- (unsigned)intent, "inconsistent rendering intents");
+ (png_alloc_size_t)intent, "inconsistent rendering intents");
if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)
{
@@ -1979,7 +1979,6 @@ icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
if (profile_length < 132)
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
"too short");
-
return 1;
}
@@ -2224,22 +2223,23 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* being in range. All defined tag types have an 8 byte header - a 4 byte
* type signature then 0.
*/
+
+ /* This is a hard error; potentially it can cause read outside the
+ * profile.
+ */
+ if (tag_start > profile_length || tag_length > profile_length - tag_start)
+ return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
+ "ICC profile tag outside profile");
+
if ((tag_start & 3) != 0)
{
- /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is
+ /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is
* only a warning here because libpng does not care about the
* alignment.
*/
(void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"ICC profile tag start not a multiple of 4");
}
-
- /* This is a hard error; potentially it can cause read outside the
- * profile.
- */
- if (tag_start > profile_length || tag_length > profile_length - tag_start)
- return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
- "ICC profile tag outside profile");
}
return 1; /* success, maybe with warnings */
@@ -3761,7 +3761,7 @@ png_log16bit(png_uint_32 x)
* of getting this accuracy in practice.
*
* To deal with this the following exp() function works out the exponent of the
- * frational part of the logarithm by using an accurate 32-bit value from the
+ * fractional part of the logarithm by using an accurate 32-bit value from the
* top four fractional bits then multiplying in the remaining bits.
*/
static const png_uint_32
diff --git a/src/3rdparty/libpng/png.h b/src/3rdparty/libpng/png.h
index 51ac8abe74..4c873f5c22 100644
--- a/src/3rdparty/libpng/png.h
+++ b/src/3rdparty/libpng/png.h
@@ -1,7 +1,7 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.32, August 24, 2017
+ * libpng version 1.6.34, September 29, 2017
*
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
@@ -12,7 +12,7 @@
* Authors and maintainers:
* libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
- * libpng versions 0.97, January 1998, through 1.6.32, August 24, 2017:
+ * libpng versions 0.97, January 1998, through 1.6.34, September 29, 2017:
* Glenn Randers-Pehrson.
* See also "Contributing Authors", below.
*/
@@ -25,7 +25,7 @@
*
* This code is released under the libpng license.
*
- * libpng versions 1.0.7, July 1, 2000 through 1.6.32, August 24, 2017 are
+ * libpng versions 1.0.7, July 1, 2000 through 1.6.34, September 29, 2017 are
* Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
* derived from libpng-1.0.6, and are distributed according to the same
* disclaimer and license as libpng-1.0.6 with the following individuals
@@ -209,11 +209,11 @@
* ...
* 1.0.19 10 10019 10.so.0.19[.0]
* ...
- * 1.2.57 13 10257 12.so.0.57[.0]
+ * 1.2.59 13 10257 12.so.0.59[.0]
* ...
- * 1.5.28 15 10527 15.so.15.28[.0]
+ * 1.5.30 15 10527 15.so.15.30[.0]
* ...
- * 1.6.32 16 10632 16.so.16.32[.0]
+ * 1.6.34 16 10633 16.so.16.34[.0]
*
* Henceforth the source version will match the shared-library major
* and minor numbers; the shared-library major version number will be
@@ -241,13 +241,13 @@
* Y2K compliance in libpng:
* =========================
*
- * August 24, 2017
+ * September 29, 2017
*
* Since the PNG Development group is an ad-hoc body, we can't make
* an official declaration.
*
* This is your unofficial assurance that libpng from version 0.71 and
- * upward through 1.6.32 are Y2K compliant. It is my belief that
+ * upward through 1.6.34 are Y2K compliant. It is my belief that
* earlier versions were also Y2K compliant.
*
* Libpng only has two year fields. One is a 2-byte unsigned integer
@@ -309,8 +309,8 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.32"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.32 - August 24, 2017\n"
+#define PNG_LIBPNG_VER_STRING "1.6.34"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.34 - September 29, 2017\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
@@ -318,7 +318,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 32
+#define PNG_LIBPNG_VER_RELEASE 34
/* This should match the numeric part of the final component of
* PNG_LIBPNG_VER_STRING, omitting any leading zero:
@@ -349,7 +349,7 @@
* version 1.0.0 was mis-numbered 100 instead of 10000). From
* version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release
*/
-#define PNG_LIBPNG_VER 10632 /* 1.6.32 */
+#define PNG_LIBPNG_VER 10634 /* 1.6.34 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -459,7 +459,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_32;
+typedef char* png_libpng_version_1_6_34;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -2819,6 +2819,8 @@ typedef struct
# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */
#endif
+#define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U /* alpha channel is associated */
+
/* Commonly used formats have predefined macros.
*
* First the single byte (sRGB) formats:
diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h
index c0f15547be..d13b13e57a 100644
--- a/src/3rdparty/libpng/pngconf.h
+++ b/src/3rdparty/libpng/pngconf.h
@@ -1,7 +1,7 @@
/* pngconf.h - machine configurable file for libpng
*
- * libpng version 1.6.32, August 24, 2017
+ * libpng version 1.6.34, September 29, 2017
*
* Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
diff --git a/src/3rdparty/libpng/pnglibconf.h b/src/3rdparty/libpng/pnglibconf.h
index 9e45f73129..53b5e442c4 100644
--- a/src/3rdparty/libpng/pnglibconf.h
+++ b/src/3rdparty/libpng/pnglibconf.h
@@ -1,8 +1,8 @@
-/* libpng 1.6.32 STANDARD API DEFINITION */
+/* libpng 1.6.34 STANDARD API DEFINITION */
/* pnglibconf.h - library build configuration */
-/* Libpng version 1.6.32 - August 24, 2017 */
+/* Libpng version 1.6.34 - September 29, 2017 */
/* Copyright (c) 1998-2017 Glenn Randers-Pehrson */
diff --git a/src/3rdparty/libpng/pngread.c b/src/3rdparty/libpng/pngread.c
index e34ddd99a0..da32e9ad9c 100644
--- a/src/3rdparty/libpng/pngread.c
+++ b/src/3rdparty/libpng/pngread.c
@@ -1,7 +1,7 @@
/* pngread.c - read a PNG file
*
- * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -3759,7 +3759,13 @@ png_image_read_direct(png_voidp argument)
mode = PNG_ALPHA_PNG;
output_gamma = PNG_DEFAULT_sRGB;
}
-
+
+ if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0)
+ {
+ mode = PNG_ALPHA_OPTIMIZED;
+ change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
+ }
+
/* If 'do_local_background' is set check for the presence of gamma
* correction; this is part of the work-round for the libpng bug
* described above.
@@ -3985,6 +3991,10 @@ png_image_read_direct(png_voidp argument)
else if (do_local_compose != 0) /* internal error */
png_error(png_ptr, "png_image_read: alpha channel lost");
+ if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) {
+ info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
+ }
+
if (info_ptr->bit_depth == 16)
info_format |= PNG_FORMAT_FLAG_LINEAR;
diff --git a/src/3rdparty/libpng/pngrtran.c b/src/3rdparty/libpng/pngrtran.c
index 9a30ddf22b..c189650313 100644
--- a/src/3rdparty/libpng/pngrtran.c
+++ b/src/3rdparty/libpng/pngrtran.c
@@ -1,7 +1,7 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Last changed in libpng 1.6.31 [July 27, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -430,7 +430,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
int i;
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
for (i = 0; i < num_palette; i++)
png_ptr->quantize_index[i] = (png_byte)i;
}
@@ -447,7 +447,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
/* Initialize an array to sort colors */
png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
/* Initialize the quantize_sort array */
for (i = 0; i < num_palette; i++)
@@ -581,9 +581,11 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
/* Initialize palette index arrays */
png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette *
+ (sizeof (png_byte))));
png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette *
+ (sizeof (png_byte))));
/* Initialize the sort array */
for (i = 0; i < num_palette; i++)
@@ -592,7 +594,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
png_ptr->palette_to_index[i] = (png_byte)i;
}
- hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
+ hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 *
(sizeof (png_dsortp))));
num_new_palette = num_palette;
@@ -623,7 +625,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
{
t = (png_dsortp)png_malloc_warn(png_ptr,
- (png_uint_32)(sizeof (png_dsort)));
+ (png_alloc_size_t)(sizeof (png_dsort)));
if (t == NULL)
break;
@@ -748,9 +750,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
png_size_t num_entries = ((png_size_t)1 << total_bits);
png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
- (png_uint_32)(num_entries * (sizeof (png_byte))));
+ (png_alloc_size_t)(num_entries * (sizeof (png_byte))));
- distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
+ distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)(num_entries *
(sizeof (png_byte))));
memset(distance, 0xff, num_entries * (sizeof (png_byte)));
@@ -3322,7 +3324,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
== png_ptr->trans_color.gray)
{
unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
- tmp |=
+ tmp |=
(unsigned int)(png_ptr->background.gray << shift);
*sp = (png_byte)(tmp & 0xff);
}
diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c
index a4fa71457b..8692933bd8 100644
--- a/src/3rdparty/libpng/pngrutil.c
+++ b/src/3rdparty/libpng/pngrutil.c
@@ -1,7 +1,7 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -314,6 +314,7 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
if (buffer != NULL)
{
+ memset(buffer, 0, new_size); /* just in case */
png_ptr->read_buffer = buffer;
png_ptr->read_buffer_size = new_size;
}
@@ -673,6 +674,8 @@ png_decompress_chunk(png_structrp png_ptr,
if (text != NULL)
{
+ memset(text, 0, buffer_size);
+
ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,
png_ptr->read_buffer + prefix_size, &lzsize,
text + prefix_size, newlength);
@@ -736,9 +739,7 @@ png_decompress_chunk(png_structrp png_ptr,
{
/* inflateReset failed, store the error message */
png_zstream_error(png_ptr, ret);
-
- if (ret == Z_STREAM_END)
- ret = PNG_UNEXPECTED_ZLIB_RETURN;
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
}
}
@@ -1476,7 +1477,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
/* Now read the tag table; a variable size buffer is
* needed at this point, allocate one for the whole
* profile. The header check has already validated
- * that none of these stuff will overflow.
+ * that none of this stuff will overflow.
*/
const png_uint_32 tag_count = png_get_uint_32(
profile_header+128);
@@ -1583,19 +1584,11 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
return;
}
}
-
- else if (size > 0)
- errmsg = "truncated";
-
-#ifndef __COVERITY__
- else
+ if (errmsg == NULL)
errmsg = png_ptr->zstream.msg;
-#endif
}
-
/* else png_icc_check_tag_table output an error */
}
-
else /* profile truncated */
errmsg = png_ptr->zstream.msg;
}
@@ -3144,28 +3137,28 @@ png_check_chunk_length(png_const_structrp png_ptr, const png_uint_32 length)
{
png_alloc_size_t limit = PNG_UINT_31_MAX;
- if (png_ptr->chunk_name != png_IDAT)
- {
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
- if (png_ptr->user_chunk_malloc_max > 0 &&
- png_ptr->user_chunk_malloc_max < limit)
- limit = png_ptr->user_chunk_malloc_max;
+ if (png_ptr->user_chunk_malloc_max > 0 &&
+ png_ptr->user_chunk_malloc_max < limit)
+ limit = png_ptr->user_chunk_malloc_max;
# elif PNG_USER_CHUNK_MALLOC_MAX > 0
- if (PNG_USER_CHUNK_MALLOC_MAX < limit)
- limit = PNG_USER_CHUNK_MALLOC_MAX;
+ if (PNG_USER_CHUNK_MALLOC_MAX < limit)
+ limit = PNG_USER_CHUNK_MALLOC_MAX;
# endif
- }
- else
+ if (png_ptr->chunk_name == png_IDAT)
{
+ png_alloc_size_t idat_limit = PNG_UINT_31_MAX;
size_t row_factor =
(png_ptr->width * png_ptr->channels * (png_ptr->bit_depth > 8? 2: 1)
+ 1 + (png_ptr->interlaced? 6: 0));
if (png_ptr->height > PNG_UINT_32_MAX/row_factor)
- limit=PNG_UINT_31_MAX;
+ idat_limit=PNG_UINT_31_MAX;
else
- limit = png_ptr->height * row_factor;
- limit += 6 + 5*(limit/32566+1); /* zlib+deflate overhead */
- limit=limit < PNG_UINT_31_MAX? limit : PNG_UINT_31_MAX;
+ idat_limit = png_ptr->height * row_factor;
+ row_factor = row_factor > 32566? 32566 : row_factor;
+ idat_limit += 6 + 5*(idat_limit/row_factor+1); /* zlib+deflate overhead */
+ idat_limit=idat_limit < PNG_UINT_31_MAX? idat_limit : PNG_UINT_31_MAX;
+ limit = limit < idat_limit? idat_limit : limit;
}
if (length > limit)
diff --git a/src/3rdparty/libpng/pngtrans.c b/src/3rdparty/libpng/pngtrans.c
index 326ac33f0e..6882f0fd7b 100644
--- a/src/3rdparty/libpng/pngtrans.c
+++ b/src/3rdparty/libpng/pngtrans.c
@@ -1,7 +1,7 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
- * Last changed in libpng 1.6.30 [June 28, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -609,7 +609,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
return; /* The filler channel has gone already */
/* Fix the rowbytes value. */
- row_info->rowbytes = (unsigned int)(dp-row);
+ row_info->rowbytes = (png_size_t)(dp-row);
}
#endif
@@ -708,7 +708,7 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
* forms produced on either GCC or MSVC.
*/
int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width);
- png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
+ png_bytep rp = png_ptr->row_buf + row_info->rowbytes - 1;
switch (row_info->bit_depth)
{
diff --git a/src/3rdparty/libpng/pngwrite.c b/src/3rdparty/libpng/pngwrite.c
index a7662acb71..a16d77ce00 100644
--- a/src/3rdparty/libpng/pngwrite.c
+++ b/src/3rdparty/libpng/pngwrite.c
@@ -1940,7 +1940,7 @@ png_image_write_main(png_voidp argument)
int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);
int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */
int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);
- int write_16bit = linear && !colormap && (display->convert_to_8bit == 0);
+ int write_16bit = linear && (display->convert_to_8bit == 0);
# ifdef PNG_BENIGN_ERRORS_SUPPORTED
/* Make sure we error out on any bad situation */
diff --git a/src/3rdparty/libpng/qt_attribution.json b/src/3rdparty/libpng/qt_attribution.json
index 7b2d776978..23fb903bdd 100644
--- a/src/3rdparty/libpng/qt_attribution.json
+++ b/src/3rdparty/libpng/qt_attribution.json
@@ -6,7 +6,7 @@
"Description": "libpng is the official PNG reference library.",
"Homepage": "http://www.libpng.org/pub/png/libpng.html",
- "Version": "1.6.32",
+ "Version": "1.6.34",
"License": "libpng License",
"LicenseId": "Libpng",
"LicenseFile": "LICENSE",
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index e4b756f4b7..50cf0889c7 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -1376,12 +1376,12 @@
} while (false)
#if defined(__cplusplus)
-#if QT_HAS_CPP_ATTRIBUTE(fallthrough)
-# define Q_FALLTHROUGH() [[fallthrough]]
-#elif QT_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#if QT_HAS_CPP_ATTRIBUTE(clang::fallthrough)
# define Q_FALLTHROUGH() [[clang::fallthrough]]
#elif QT_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
# define Q_FALLTHROUGH() [[gnu::fallthrough]]
+#elif QT_HAS_CPP_ATTRIBUTE(fallthrough)
+# define Q_FALLTHROUGH() [[fallthrough]]
#endif
#endif
#ifndef Q_FALLTHROUGH
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
index 5855784f32..6b5c550b53 100644
--- a/src/corelib/global/qfloat16.h
+++ b/src/corelib/global/qfloat16.h
@@ -124,7 +124,7 @@ inline qfloat16::qfloat16(float f) Q_DECL_NOTHROW
__m128i packhalf = _mm_cvtps_ph(packsingle, 0);
b16 = _mm_extract_epi16(packhalf, 0);
#elif defined (__ARM_FP16_FORMAT_IEEE)
- __fp16 f16 = f;
+ __fp16 f16 = __fp16(f);
memcpy(&b16, &f16, sizeof(quint16));
#else
quint32 u;
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index 9abb9ece7f..72ac8d332b 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -43,10 +43,8 @@
#include "qrandom.h"
#include "qrandom_p.h"
#include <qobjectdefs.h>
+#include <qmutex.h>
#include <qthreadstorage.h>
-#include <private/qsimd_p.h>
-
-#include <random>
#include <errno.h>
@@ -86,6 +84,7 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
#undef Q_ASSERT_X
#undef Q_ASSERT
#define Q_ASSERT(cond) assert(cond)
+#define Q_ASSERT_X(cond, x, msg) assert(cond && msg)
#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
# define NDEBUG 1
#endif
@@ -122,14 +121,21 @@ static QT_FUNCTION_TARGET(RDRND) qssize_t qt_random_cpu(void *buffer, qssize_t c
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
+#else
+static qssize_t qt_random_cpu(void *, qssize_t)
+{
+ return 0;
+}
#endif
-namespace {
-#if QT_CONFIG(getentropy)
-class SystemRandom
+enum {
+ // may be "overridden" by a member enum
+ FillBufferNoexcept = true
+};
+
+struct QRandomGenerator::SystemGenerator
{
-public:
- enum { EfficientBufferFill = true };
+#if QT_CONFIG(getentropy)
static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
{
// getentropy can read at most 256 bytes, so break the reading
@@ -147,96 +153,93 @@ public:
Q_UNUSED(ret);
return count;
}
-};
#elif defined(Q_OS_UNIX)
-class SystemRandom
-{
- static QBasicAtomicInt s_fdp1; // "file descriptor plus 1"
- static int openDevice();
-#ifdef Q_CC_GNU
- // If it's not GCC or GCC-like, then we'll leak the file descriptor
- __attribute__((destructor))
-#endif
- static void closeDevice();
- SystemRandom() {}
-public:
- enum { EfficientBufferFill = true };
- static qssize_t fillBuffer(void *buffer, qssize_t count);
-};
-QBasicAtomicInt SystemRandom::s_fdp1 = Q_BASIC_ATOMIC_INITIALIZER(0);
+ enum { FillBufferNoexcept = false };
-void SystemRandom::closeDevice()
-{
- int fd = s_fdp1.loadAcquire() - 1;
- if (fd >= 0)
- qt_safe_close(fd);
-}
+ QBasicAtomicInt fdp1; // "file descriptor plus 1"
+ int openDevice()
+ {
+ int fd = fdp1.loadAcquire() - 1;
+ if (fd != -1)
+ return fd;
+
+ fd = qt_safe_open("/dev/urandom", O_RDONLY);
+ if (fd == -1)
+ fd = qt_safe_open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd == -1) {
+ // failed on both, set to -2 so we won't try again
+ fd = -2;
+ }
-int SystemRandom::openDevice()
-{
- int fd = s_fdp1.loadAcquire() - 1;
- if (fd != -1)
- return fd;
-
- fd = qt_safe_open("/dev/urandom", O_RDONLY);
- if (fd == -1)
- fd = qt_safe_open("/dev/random", O_RDONLY | O_NONBLOCK);
- if (fd == -1) {
- // failed on both, set to -2 so we won't try again
- fd = -2;
+ int opened_fdp1;
+ if (fdp1.testAndSetOrdered(0, fd + 1, opened_fdp1))
+ return fd;
+
+ // failed, another thread has opened the file descriptor
+ if (fd >= 0)
+ qt_safe_close(fd);
+ return opened_fdp1 - 1;
}
- int opened_fdp1;
- if (s_fdp1.testAndSetOrdered(0, fd + 1, opened_fdp1)) {
- if (fd >= 0) {
- static const SystemRandom closer;
- Q_UNUSED(closer);
- }
- return fd;
+#ifdef Q_CC_GNU
+ // If it's not GCC or GCC-like, then we'll leak the file descriptor
+ __attribute__((destructor))
+#endif
+ static void closeDevice()
+ {
+ int fd = self().fdp1.load() - 1;
+ if (fd >= 0)
+ qt_safe_close(fd);
}
- // failed, another thread has opened the file descriptor
- if (fd >= 0)
- qt_safe_close(fd);
- return opened_fdp1 - 1;
-}
+ Q_DECL_CONSTEXPR SystemGenerator() : fdp1 Q_BASIC_ATOMIC_INITIALIZER(0) {}
-qssize_t SystemRandom::fillBuffer(void *buffer, qssize_t count)
-{
- int fd = openDevice();
- if (Q_UNLIKELY(fd < 0))
- return 0;
+ qssize_t fillBuffer(void *buffer, qssize_t count)
+ {
+ int fd = openDevice();
+ if (Q_UNLIKELY(fd < 0))
+ return 0;
- qint64 n = qt_safe_read(fd, buffer, count);
- return qMax<qssize_t>(n, 0); // ignore any errors
-}
-#endif // Q_OS_UNIX
+ qint64 n = qt_safe_read(fd, buffer, count);
+ return qMax<qssize_t>(n, 0); // ignore any errors
+ }
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
-class SystemRandom
-{
-public:
- enum { EfficientBufferFill = true };
- static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
+#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
{
auto RtlGenRandom = SystemFunction036;
return RtlGenRandom(buffer, ULONG(count)) ? count: 0;
}
-};
#elif defined(Q_OS_WINRT)
-class SystemRandom
-{
-public:
- enum { EfficientBufferFill = false };
- static qssize_t fillBuffer(void *, qssize_t) Q_DECL_NOTHROW
+ qssize_t fillBuffer(void *, qssize_t) Q_DECL_NOTHROW
{
// always use the fallback
return 0;
}
-};
#endif // Q_OS_WINRT
-} // unnamed namespace
+
+ static SystemGenerator &self();
+ void generate(quint32 *begin, quint32 *end) Q_DECL_NOEXCEPT_EXPR(FillBufferNoexcept);
+
+ // For std::mersenne_twister_engine implementations that use something
+ // other than quint32 (unsigned int) to fill their buffers.
+ template <typename T> void generate(T *begin, T *end)
+ {
+ Q_STATIC_ASSERT(sizeof(T) >= sizeof(quint32));
+ if (sizeof(T) == sizeof(quint32)) {
+ // Microsoft Visual Studio uses unsigned long, but that's still 32-bit
+ generate(reinterpret_cast<quint32 *>(begin), reinterpret_cast<quint32 *>(end));
+ } else {
+ // Slow path. Fix your C++ library.
+ std::generate(begin, end, [this]() {
+ quint32 datum;
+ generate(&datum, &datum + 1);
+ return datum;
+ });
+ }
+ }
+};
#if defined(Q_OS_WIN)
static void fallback_update_seed(unsigned) {}
@@ -255,6 +258,7 @@ static void fallback_update_seed(unsigned) {}
static void fallback_fill(quint32 *, qssize_t) Q_DECL_NOTHROW
{
// no fallback necessary, getentropy cannot fail under normal circumstances
+ Q_UNREACHABLE();
}
#elif defined(Q_OS_BSD4)
static void fallback_update_seed(unsigned) {}
@@ -350,31 +354,25 @@ static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
}
#endif
-static qssize_t fill_cpu(quint32 *buffer, qssize_t count) Q_DECL_NOTHROW
+Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, quint32 *end)
+ Q_DECL_NOEXCEPT_EXPR(FillBufferNoexcept)
{
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
- if (qCpuHasFeature(RDRND) && (uint(qt_randomdevice_control) & SkipHWRNG) == 0)
- return qt_random_cpu(buffer, count);
-#else
- Q_UNUSED(buffer);
- Q_UNUSED(count);
-#endif
- return 0;
-}
+ quint32 *buffer = begin;
+ qssize_t count = end - begin;
-static void fill_internal(quint32 *buffer, qssize_t count)
- Q_DECL_NOEXCEPT_EXPR(noexcept(SystemRandom::fillBuffer(buffer, count)))
-{
if (Q_UNLIKELY(uint(qt_randomdevice_control) & SetRandomData)) {
uint value = uint(qt_randomdevice_control) & RandomDataMask;
std::fill_n(buffer, count, value);
return;
}
- qssize_t filled = fill_cpu(buffer, count);
+ qssize_t filled = 0;
+ if (qt_has_hwrng() && (uint(qt_randomdevice_control) & SkipHWRNG) == 0)
+ filled += qt_random_cpu(buffer, count);
+
if (filled != count && (uint(qt_randomdevice_control) & SkipSystemRNG) == 0) {
qssize_t bytesFilled =
- SystemRandom::fillBuffer(buffer + filled, (count - filled) * qssize_t(sizeof(*buffer)));
+ fillBuffer(buffer + filled, (count - filled) * qssize_t(sizeof(*buffer)));
filled += bytesFilled / qssize_t(sizeof(*buffer));
}
if (filled)
@@ -386,147 +384,262 @@ static void fill_internal(quint32 *buffer, qssize_t count)
}
}
-static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
- Q_DECL_NOEXCEPT_EXPR(noexcept(fill_internal(static_cast<quint32 *>(buffer), 1)))
+struct QRandomGenerator::SystemAndGlobalGenerators
{
- struct ThreadState {
- enum {
- DesiredBufferByteSize = 32,
- BufferCount = DesiredBufferByteSize / sizeof(quint32)
- };
- quint32 buffer[BufferCount];
- int idx = BufferCount;
- };
-
- // Verify that the pointers are properly aligned for 32-bit
- Q_ASSERT(quintptr(buffer) % sizeof(quint32) == 0);
- Q_ASSERT(quintptr(bufferEnd) % sizeof(quint32) == 0);
+ // Construction notes:
+ // 1) The global PRNG state is in a different cacheline compared to the
+ // mutex that protects it. This avoids any false cacheline sharing of
+ // the state in case another thread tries to lock the mutex. It's not
+ // a common scenario, but since sizeof(QRandomGenerator) >= 2560, the
+ // overhead is actually acceptable.
+ // 2) We use both Q_DECL_ALIGN and std::aligned_storage<..., 64> because
+ // some implementations of std::aligned_storage can't align to more
+ // than a primitive type's alignment.
+ // 3) We don't store the entire system QRandomGenerator, only the space
+ // used by the QRandomGenerator::type member. This is fine because we
+ // (ab)use the common initial sequence exclusion to aliasing rules.
+ QBasicMutex globalPRNGMutex;
+ struct ShortenedSystem { uint type; } system_;
+ SystemGenerator sys;
+ Q_DECL_ALIGN(64) std::aligned_storage<sizeof(QRandomGenerator64), 64>::type global_;
+
+#ifdef Q_COMPILER_CONSTEXPR
+ constexpr SystemAndGlobalGenerators()
+ : globalPRNGMutex{}, system_{0}, sys{}, global_{}
+ {}
+#endif
- quint32 *ptr = reinterpret_cast<quint32 *>(buffer);
- quint32 * const end = reinterpret_cast<quint32 *>(bufferEnd);
+ void confirmLiteral()
+ {
+#if defined(Q_COMPILER_CONSTEXPR) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY)
+ // Currently fails to compile with MSVC 2017, saying QBasicMutex is not
+ // a literal type. Disassembly with MSVC 2013 and 2015 shows it is
+ // actually a literal; MSVC 2017 has a bug relating to this, so we're
+ // withhold judgement for now. Integrity's compiler is unable to
+ // guarantee g's alignment for some reason.
+
+ constexpr SystemAndGlobalGenerators g = {};
+ Q_UNUSED(g);
+ Q_STATIC_ASSERT(std::is_literal_type<SystemAndGlobalGenerators>::value);
+#endif
+ }
-#if defined(Q_COMPILER_THREAD_LOCAL) && !defined(QT_BOOTSTRAPPED)
- if (SystemRandom::EfficientBufferFill && (end - ptr) < ThreadState::BufferCount
- && uint(qt_randomdevice_control) == 0) {
- thread_local ThreadState state;
- qssize_t itemsAvailable = ThreadState::BufferCount - state.idx;
+ static SystemAndGlobalGenerators *self()
+ {
+ static SystemAndGlobalGenerators g;
+ Q_STATIC_ASSERT(sizeof(g) > sizeof(QRandomGenerator64));
+ return &g;
+ }
- // copy as much as we already have
- qssize_t itemsToCopy = qMin(qssize_t(end - ptr), itemsAvailable);
- memcpy(ptr, state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
- ptr += itemsToCopy;
+ static QRandomGenerator64 *system()
+ {
+ // Though we never call the constructor, the system QRandomGenerator is
+ // properly initialized by the zero initialization performed in self().
+ // Though QRandomGenerator is has non-vacuous initialization, we
+ // consider it initialized because of the common initial sequence.
+ return reinterpret_cast<QRandomGenerator64 *>(&self()->system_);
+ }
- if (ptr != end) {
- // refill the buffer and try again
- fill_internal(state.buffer, ThreadState::BufferCount);
- state.idx = 0;
+ static QRandomGenerator64 *globalNoInit()
+ {
+ // This function returns the pointer to the global QRandomGenerator,
+ // but does not initialize it. Only call it directly if you meant to do
+ // a pointer comparison.
+ return reinterpret_cast<QRandomGenerator64 *>(&self()->global_);
+ }
- itemsToCopy = end - ptr;
- memcpy(ptr, state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
- ptr = end;
- }
+ static void securelySeed(QRandomGenerator *rng)
+ {
+ // force reconstruction, just to be pedantic
+ new (rng) QRandomGenerator{System{}};
- // erase what we copied and advance
-# ifdef Q_OS_WIN
- // Microsoft recommends this
- SecureZeroMemory(state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
-# else
- // We're quite confident the compiler will not optimize this out because
- // we're writing to a thread-local buffer
- memset(state.buffer + state.idx, 0, size_t(itemsToCopy) * sizeof(*ptr));
-# endif
- state.idx += itemsToCopy;
+ rng->type = MersenneTwister;
+ new (&rng->storage.engine()) RandomEngine(self()->sys);
}
-#endif // Q_COMPILER_THREAD_LOCAL && !QT_BOOTSTRAPPED
- if (ptr != end) {
- // fill directly in the user buffer
- fill_internal(ptr, end - ptr);
- }
+ struct PRNGLocker {
+ const bool locked;
+ PRNGLocker(const QRandomGenerator *that)
+ : locked(that == globalNoInit())
+ {
+ if (locked)
+ self()->globalPRNGMutex.lock();
+ }
+ ~PRNGLocker()
+ {
+ if (locked)
+ self()->globalPRNGMutex.unlock();
+ }
+ };
+};
+
+inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::self()
+{
+ return SystemAndGlobalGenerators::self()->sys;
}
/*!
\class QRandomGenerator
\inmodule QtCore
+ \reentrant
\since 5.10
\brief The QRandomGenerator class allows one to obtain random values from a
- high-quality, seed-less Random Number Generator.
+ high-quality Random Number Generator.
QRandomGenerator may be used to generate random values from a high-quality
- random number generator. Unlike qrand(), QRandomGenerator does not need to be
- seeded. That also means it is not possible to force it to produce a
- reliable sequence, which may be needed for debugging.
+ random number generator. Like the C++ random engines, QRandomGenerator can
+ be seeded with user-provided values through the constructor.
+ When seeded, the sequence of numbers generated by this
+ class is deterministic. That is to say, given the same seed data,
+ QRandomGenerator will generate the same sequence of numbers. But given
+ different seeds, the results should be considerably different.
+
+ QRandomGenerator::securelySeeded() can be used to create a QRandomGenerator
+ that is securely seeded with QRandomGenerator::system(), meaning that the
+ sequence of numbers it generates cannot be easily predicted. Additionally,
+ QRandomGenerator::global() returns a global instance of QRandomGenerator
+ that Qt will ensure to be securely seeded. This object is thread-safe, may
+ be shared for most uses, and is always seeded from
+ QRandomGenerator::system()
+
+ QRandomGenerator::system() may be used to access the system's
+ cryptographically-safe random generator. On Unix systems, it's equivalent
+ to reading from \c {/dev/urandom} or the \c {getrandom()} or \c
+ {getentropy()} system calls.
The class can generate 32-bit or 64-bit quantities, or fill an array of
those. The most common way of generating new values is to call the generate(),
generate64() or fillRange() functions. One would use it as:
\code
- quint32 value = QRandomGenerator::generate();
+ quint32 value = QRandomGenerator::global()->generate();
\endcode
- Additionally, it provides a floating-point function generateDouble() that returns
- a number in the range [0, 1) (that is, inclusive of zero and exclusive of
- 1). There's also a set of convenience functions that facilitate obtaining a
- random number in a bounded, integral range.
+ Additionally, it provides a floating-point function generateDouble() that
+ returns a number in the range [0, 1) (that is, inclusive of zero and
+ exclusive of 1). There's also a set of convenience functions that
+ facilitate obtaining a random number in a bounded, integral range.
- \warning This class is not suitable for bulk data creation. See below for the
- technical reasons.
+ \section1 Seeding and determinism
+
+ QRandomGenerator may be seeded with specific seed data. When that is done,
+ the numbers generated by the object will always be the same, as in the
+ following example:
+
+ \code
+ QRandomGenerator prng1(1234), prng2(1234);
+ Q_ASSERT(prng1.generate32() == prng2.generate32());
+ Q_ASSERT(prng1.generate64() == prng2.generate64());
+ \endcode
- \section1 Frequency and entropy exhaustion
+ The seed data takes the form of one or more 32-bit words. The ideal seed
+ size is approximately equal to the size of the QRandomGenerator class
+ itself. Due to mixing of the seed data, QRandomGenerator cannot guarantee
+ that distinct seeds will produce different sequences.
+
+ QRandomGenerator::global(), like all generators created by
+ QRandomGenerator::securelySeeded(), is always seeded from
+ QRandomGenerator::system(), so it's not possible to make it produce
+ identical sequences.
+
+ \section1 Bulk data
+
+ When operating in deterministic mode, QRandomGenerator may be used for bulk
+ data generation. In fact, applications that do not need
+ cryptographically-secure or true random data are advised to use a regular
+ QRandomGenerator instead of QRandomGenerator::system() for their random
+ data needs.
+
+ For ease of use, QRandomGenerator provides a global object that can
+ be easily used, as in the following example:
+
+ \code
+ int x = QRandomGenerator::global()->generate32();
+ int y = QRandomGenerator::global()->generate32();
+ int w = QRandomGenerator::global()->bounded(16384);
+ int h = QRandomGenerator::global()->bounded(16384);
+ \endcode
- QRandomGenerator does not need to be seeded and instead uses operating system
- or hardware facilities to generate random numbers. On some systems and with
- certain hardware, those facilities are true Random Number Generators.
- However, if they are true RNGs, those facilities have finite entropy source
- and thus may fail to produce any results if the entropy pool is exhausted.
+ \section1 System-wide random number generator
+
+ QRandomGenerator::system() may be used to access the system-wide random
+ number generator, which is cryptographically-safe on all systems that Qt
+ runs on. This function will use hardware facilities to generate random
+ numbers where available. On such systems, those facilities are true Random
+ Number Generators. However, if they are true RNGs, those facilities have
+ finite entropy sources and thus may fail to produce any results if their
+ entropy pool is exhausted.
If that happens, first the operating system then QRandomGenerator will fall
back to Pseudo Random Number Generators of decreasing qualities (Qt's
- fallback generator being the simplest). Therefore, QRandomGenerator should
- not be used for high-frequency random number generation, lest the entropy
- pool become empty. As a rule of thumb, this class should not be called upon
- to generate more than a kilobyte per second of random data (note: this may
- vary from system to system).
+ fallback generator being the simplest). Whether those generators are still
+ of cryptographic quality is implementation-defined. Therefore,
+ QRandomGenerator::system() should not be used for high-frequency random
+ number generation, lest the entropy pool become empty. As a rule of thumb,
+ this class should not be called upon to generate more than a kilobyte per
+ second of random data (note: this may vary from system to system).
If an application needs true RNG data in bulk, it should use the operating
- system facilities (such as \c{/dev/random} on Unix systems) directly and
- wait for entropy to become available. If true RNG is not required,
- applications should instead use a PRNG engines and can use QRandomGenerator to
- seed those.
+ system facilities (such as \c{/dev/random} on Linux) directly and wait for
+ entropy to become available. If the application requires PRNG engines of
+ cryptographic quality but not of true randomness,
+ QRandomGenerator::system() may still be used (see section below).
+
+ If neither a true RNG nor a cryptographically secure PRNG are required,
+ applications should instead use PRNG engines like QRandomGenerator's
+ deterministic mode and those from the C++ Standard Library.
+ QRandomGenerator::system() can be used to seed those.
+
+ \section2 Fallback quality
+
+ QRandomGenerator::system() uses the operating system facilities to obtain
+ random numbers, which attempt to collect real entropy from the surrounding
+ environment to produce true random numbers. However, it's possible that the
+ entropy pool becomes exhausted, in which case the operating system will
+ fall back to a pseudo-random engine for a time. Under no circumstances will
+ QRandomGenerator::system() block, waiting for more entropy to be collected.
+
+ The following operating systems guarantee that the results from their
+ random-generation API will be of at least cryptographically-safe quality,
+ even if the entropy pool is exhausted: Apple OSes (Darwin), BSDs, Linux,
+ Windows. Barring a system installation problem (such as \c{/dev/urandom}
+ not being readable by the current process), QRandomGenerator::system() will
+ therefore have the same guarantees.
+
+ On other operating systems, QRandomGenerator will fall back to a PRNG of
+ good numeric distribution, but it cannot guarantee proper seeding in all
+ cases. Please consult the OS documentation for more information.
+
+ Applications that require QRandomGenerator not to fall back to
+ non-cryptographic quality generators are advised to check their operating
+ system documentation or restrict their deployment to one of the above.
+
+ \section1 Reentrancy and thread-safety
+
+ QRandomGenerator is reentrant, meaning that multiple threads can operate on
+ this class at the same time, so long as they operate on different objects.
+ If multiple threads need to share one PRNG sequence, external locking by a
+ mutex is required.
+
+ The exceptions are the objects returned by QRandomGenerator::global() and
+ QRandomGenerator::system(): those objects are thread-safe and may be used
+ by any thread without external locking. Note that thread-safety does not
+ extend to copying those objects: they should always be used by reference.
\section1 Standard C++ Library compatibility
- QRandomGenerator is modeled after
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
- and may be used in almost all contexts that the Standard Library can.
- QRandomGenerator attempts to use either the same engine that backs
- \c{std::random_device} or a better one. Note that \c{std::random_device} is
- also allowed to fail if the source entropy pool becomes exhausted, in which
- case it will throw an exception. QRandomGenerator never throws, but may abort
- program execution instead.
-
- Like the Standard Library class, QRandomGenerator can be used to seed Standard
- Library deterministic random engines from \c{<random>}, such as the
- Mersenne Twister. Unlike \c{std::random_device}, QRandomGenerator also
- implements the API of
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/seed_seq}{std::seed_seq}},
- allowing it to seed the deterministic engines directly.
-
- The following code can be used to create and seed the
- implementation-defined default deterministic PRNG, then use it to fill a
- block range:
-
- \code
- QRandomGenerator rd;
- std::default_random_engine rng(rd);
- std::generate(block.begin(), block.end(), rng);
+ QRandomGenerator is modeled after the requirements for random number
+ engines in the C++ Standard Library and may be used in almost all contexts
+ that the Standard Library engines can. Exceptions to the requirements are
+ the following:
- // equivalent to:
- for (auto &v : block)
- v = rng();
- \endcode
+ \list
+ \li QRandomGenerator does not support seeding from another seed
+ sequence-like class besides std::seed_seq itself;
+ \li QRandomGenerator is not comparable (but is copyable) or
+ streamable to \c{std::ostream} or from \c{std::istream}.
+ \endlist
QRandomGenerator is also compatible with the uniform distribution classes
\c{std::uniform_int_distribution} and \c{std:uniform_real_distribution}, as
@@ -535,57 +648,129 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
[1, 2.5):
\code
- QRandomGenerator64 rd;
std::uniform_real_distribution dist(1, 2.5);
- return dist(rd);
+ return dist(*QRandomGenerator::global());
\endcode
- Note the use of the QRandomGenerator64 class instead of QRandomGenerator to
- obtain 64 bits of random data in a single call, though it is not required
- to make the algorithm work (the Standard Library functions will make as
- many calls as required to obtain enough bits of random data for the desired
- range).
-
\sa QRandomGenerator64, qrand()
*/
/*!
- \fn QRandomGenerator::QRandomGenerator()
- \internal
- Defaulted constructor, does nothing.
+ \fn QRandomGenerator::QRandomGenerator(quint32 seedValue)
+
+ Initializes this QRandomGenerator object with the value \a seedValue as
+ the seed. Two objects constructed or reseeded with the same seed value will
+ produce the same number sequence.
+
+ \sa seed(), securelySeeded()
*/
/*!
- \typedef QRandomGenerator::result_type
+ \fn QRandomGenerator::QRandomGenerator(const quint32 (&seedBuffer)[N])
+ \overload
- A typedef to the type that operator()() returns. That is, quint32.
+ Initializes this QRandomGenerator object with the values found in the
+ array \a seedBuffer as the seed. Two objects constructed or reseeded with
+ the same seed value will produce the same number sequence.
- \sa operator()()
+ \sa seed(), securelySeeded()
*/
/*!
- \fn result_type QRandomGenerator::operator()()
+ \fn QRandomGenerator::QRandomGenerator(const quint32 *seedBuffer, qssize_t len)
+ \overload
- Generates a 32-bit random quantity and returns it.
+ Initializes this QRandomGenerator object with \a len values found in
+ the array \a seedBuffer as the seed. Two objects constructed or reseeded
+ with the same seed value will produce the same number sequence.
- \sa QRandomGenerator::generate(), QRandomGenerator::generate64()
+ This constructor is equivalent to:
+ \code
+ std::seed_seq sseq(seedBuffer, seedBuffer + len);
+ QRandomGenerator generator(sseq);
+ \endcode
+
+ \sa seed(), securelySeeded()
*/
/*!
- \fn double QRandomGenerator::entropy() const
+ \fn QRandomGenerator::QRandomGenerator(const quint32 *begin, const quin32 *end)
+ \overload
+
+ Initializes this QRandomGenerator object with the values found in the range
+ from \a begin to \a end as the seed. Two objects constructed or reseeded
+ with the same seed value will produce the same number sequence.
- Returns the estimate of the entropy in the random generator source.
+ This constructor is equivalent to:
+ \code
+ std::seed_seq sseq(begin, end);
+ QRandomGenerator generator(sseq);
+ \endcode
+
+ \sa seed(), securelySeeded()
+ */
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(std::seed_seq &sseq)
+ \overload
- This function exists to comply with the Standard Library requirements for
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
- but it does not and cannot ever work. It is not possible to obtain a
- reliable entropy value in a shared entropy pool in a multi-tasking system,
- as other processes or threads may use that entropy. Any value non-zero
- value that this function could return would be obsolete by the time the
- user code reached it.
+ Initializes this QRandomGenerator object with the seed sequence \a
+ sseq as the seed. Two objects constructed or reseeded with the same seed
+ value will produce the same number sequence.
- Since QRandomGenerator attempts to use a hardware Random Number Generator,
- this function always returns 0.0.
+ \sa seed(), securelySeeded()
+ */
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(const QRandomGenerator &other)
+
+ Creates a copy of the generator state in the \a other object. If \a other is
+ QRandomGenerator::system() or a copy of that, this object will also read
+ from the operating system random-generating facilities. In that case, the
+ sequences generated by the two objects will be different.
+
+ In all other cases, the new QRandomGenerator object will start at the same
+ position in the deterministic sequence as the \a other object was. Both
+ objects will generate the same sequence from this point on.
+
+ For that reason, it is not adviseable to create a copy of
+ QRandomGenerator::global(). If one needs an exclusive deterministic
+ generator, consider instead using securelySeeded() to obtain a new object
+ that shares no relationship with the QRandomGenerator::global().
+ */
+
+/*!
+ \fn bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
+ \relates QRandomGenerator
+
+ Returns true if the two the two engines \a rng1 and \a rng2 are at the same
+ state or if they are both reading from the operating system facilities,
+ false otherwise.
+*/
+
+/*!
+ \fn bool operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
+ \relates QRandomGenerator
+
+ Returns true if the two the two engines \a rng1 and \a rng2 are at
+ different states or if one of them is reading from the operating system
+ facilities and the other is not, false otherwise.
+*/
+
+/*!
+ \typedef QRandomGenerator::result_type
+
+ A typedef to the type that operator()() returns. That is, quint32.
+
+ \sa operator()()
+ */
+
+/*!
+ \fn result_type QRandomGenerator::operator()()
+
+ Generates a 32-bit random quantity and returns it.
+
+ \sa generate(), generate64()
*/
/*!
@@ -593,7 +778,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
Returns the minimum value that QRandomGenerator may ever generate. That is, 0.
- \sa max(), QRandomGenerator64::max()
+ \sa max(), QRandomGenerator64::min()
*/
/*!
@@ -606,13 +791,38 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
+ \fn void QRandomGenerator::seed(quint32 seed)
+
+ Reseeds this object using the value \a seed as the seed.
+ */
+
+/*!
+ \fn void QRandomGenerator::seed(std::seed_seq &seed)
+ \overload
+
+ Reseeds this object using the seed sequence \a sseq as the seed.
+ */
+
+/*!
+ \fn void QRandomGenerator::discard(unsigned long long z)
+
+ Discards the next \a z entries from the sequence. This method is equivalent
+ to calling generate() \a z times and discarding the result, as in:
+
+ \code
+ while (z--)
+ generator.generate();
+ \endcode
+*/
+
+/*!
\fn void QRandomGenerator::generate(ForwardIterator begin, ForwardIterator end)
Generates 32-bit quantities and stores them in the range between \a begin
and \a end. This function is equivalent to (and is implemented as):
\code
- std::generate(begin, end, []() { return generate(); });
+ std::generate(begin, end, [this]() { return generate(); });
\endcode
This function complies with the requirements for the function
@@ -625,7 +835,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
quantities, one can write:
\code
- std::generate(begin, end, []() { return QRandomGenerator::generate64(); });
+ std::generate(begin, end, []() { return QRandomGenerator::global()->generate64(); });
\endcode
If the range refers to contiguous memory (such as an array or the data from
@@ -703,26 +913,26 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn qreal QRandomGenerator::bounded(qreal sup)
+ \fn qreal QRandomGenerator::bounded(qreal highest)
Generates one random qreal in the range between 0 (inclusive) and \a
- sup (exclusive). This function is equivalent to and is implemented as:
+ highest (exclusive). This function is equivalent to and is implemented as:
\code
- return generateDouble() * sup;
+ return generateDouble() * highest;
\endcode
\sa generateDouble(), bounded()
*/
/*!
- \fn quint32 QRandomGenerator::bounded(quint32 sup)
+ \fn quint32 QRandomGenerator::bounded(quint32 highest)
\overload
Generates one random 32-bit quantity in the range between 0 (inclusive) and
- \a sup (exclusive). The same result may also be obtained by using
+ \a highest (exclusive). The same result may also be obtained by using
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{std::uniform_int_distribution}}
- with parameters 0 and \c{sup - 1}. That class can also be used to obtain
+ with parameters 0 and \c{highest - 1}. That class can also be used to obtain
quantities larger than 32 bits.
For example, to obtain a value between 0 and 255 (inclusive), one would write:
@@ -741,11 +951,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(int sup)
+ \fn quint32 QRandomGenerator::bounded(int highest)
\overload
Generates one random 32-bit quantity in the range between 0 (inclusive) and
- \a sup (exclusive). \a sup must not be negative.
+ \a highest (exclusive). \a highest must not be negative.
Note that this function cannot be used to obtain values in the full 32-bit
range of int. Instead, use generate() and cast to int.
@@ -754,13 +964,13 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(quint32 min, quint32 sup)
+ \fn quint32 QRandomGenerator::bounded(quint32 lowest, quint32 highest)
\overload
- Generates one random 32-bit quantity in the range between \a min (inclusive)
- and \a sup (exclusive). The same result may also be obtained by using
+ Generates one random 32-bit quantity in the range between \a lowest (inclusive)
+ and \a highest (exclusive). The same result may also be obtained by using
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{std::uniform_int_distribution}}
- with parameters \a min and \c{\a sup - 1}. That class can also be used to
+ with parameters \a lowest and \c{\a highest - 1}. That class can also be used to
obtain quantities larger than 32 bits.
For example, to obtain a value between 1000 (incl.) and 2000 (excl.), one
@@ -778,11 +988,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(int min, int sup)
+ \fn quint32 QRandomGenerator::bounded(int lowest, int highest)
\overload
- Generates one random 32-bit quantity in the range between \a min
- (inclusive) and \a sup (exclusive), both of which may be negative.
+ Generates one random 32-bit quantity in the range between \a lowest
+ (inclusive) and \a highest (exclusive), both of which may be negative.
Note that this function cannot be used to obtain values in the full 32-bit
range of int. Instead, use generate() and cast to int.
@@ -791,6 +1001,72 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
+ \fn QRandomGenerator *QRandomGenerator::system()
+ \threadsafe
+
+ Returns a pointer to a shared QRandomGenerator that always uses the
+ facilities provided by the operating system to generate random numbers. The
+ system facilities are considered to be cryptographically safe on at least
+ the following operating systems: Apple OSes (Darwin), BSDs, Linux, Windows.
+ That may also be the case on other operating systems.
+
+ They are also possibly backed by a true hardware random number generator.
+ For that reason, the QRandomGenerator returned by this function should not
+ be used for bulk data generation. Instead, use it to seed QRandomGenerator
+ or a random engine from the <random> header.
+
+ The object returned by this function is thread-safe and may be used in any
+ thread without locks. It may also be copied and the resulting
+ QRandomGenerator will also access the operating system facilities, but they
+ will not generate the same sequence.
+
+ \sa securelySeeded(), global()
+*/
+
+/*!
+ \fn QRandomGenerator *QRandomGenerator::global()
+ \threadsafe
+
+ Returns a pointer to a shared QRandomGenerator that was seeded using
+ securelySeeded(). This function should be used to create random data
+ without the expensive creation of a securely-seeded QRandomGenerator
+ for a specific use or storing the rather large QRandomGenerator object.
+
+ For example, the following creates a random RGB color:
+
+ \code
+ return QColor::fromRgb(QRandomGenerator::global()->generate());
+ \endcode
+
+ Accesses to this object are thread-safe and it may therefore be used in any
+ thread without locks. The object may also be copied and the sequence
+ produced by the copy will be the same as the shared object will produce.
+ Note, however, that if there are other threads accessing the global object,
+ those threads may obtain samples at unpredictable intervals.
+
+ \sa securelySeeded(), system()
+*/
+
+/*!
+ \fn QRandomGenerator QRandomGenerator::securelySeeded()
+
+ Returns a new QRandomGenerator object that was securely seeded with
+ QRandomGenerator::system(). This function will obtain the ideal seed size
+ for the algorithm that QRandomGenerator uses and is therefore the
+ recommended way for creating a new QRandomGenerator object that will be
+ kept for some time.
+
+ Given the amount of data required to securely seed the deterministic
+ engine, this function is somewhat expensive and should not be used for
+ short-term uses of QRandomGenerator (using it to generate fewer than 2600
+ bytes of random data is effectively a waste of resources). If the use
+ doesn't require that much data, consider using QRandomGenerator::global()
+ and not storing a QRandomGenerator object instead.
+
+ \sa global(), system()
+ */
+
+/*!
\class QRandomGenerator64
\inmodule QtCore
\since 5.10
@@ -811,10 +1087,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn QRandomGenerator64::QRandomGenerator64()
- \internal
- Defaulted constructor, does nothing.
- */
+ \fn QRandomGenerator64::QRandomGenerator64(const QRandomGenerator &other)
+ \internal
+
+ Creates a copy.
+*/
/*!
\typedef QRandomGenerator64::result_type
@@ -849,80 +1126,119 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
\sa QRandomGenerator::generate(), QRandomGenerator::generate64()
*/
-/*!
- \fn double QRandomGenerator64::entropy() const
+Q_DECL_CONSTEXPR QRandomGenerator::Storage::Storage()
+ : dummy(0)
+{
+ // nothing
+}
- Returns the estimate of the entropy in the random generator source.
+inline QRandomGenerator64::QRandomGenerator64(System s)
+ : QRandomGenerator(s)
+{
+}
- This function exists to comply with the Standard Library requirements for
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
- but it does not and cannot ever work. It is not possible to obtain a
- reliable entropy value in a shared entropy pool in a multi-tasking system,
- as other processes or threads may use that entropy. Any value non-zero
- value that this function could return would be obsolete by the time the
- user code reached it.
+QRandomGenerator64 *QRandomGenerator64::system()
+{
+ auto self = SystemAndGlobalGenerators::system();
+ Q_ASSERT(self->type == SystemRNG);
+ return self;
+}
- Since QRandomGenerator64 attempts to use a hardware Random Number Generator,
- this function always returns 0.0.
- */
+QRandomGenerator64 *QRandomGenerator64::global()
+{
+ auto self = SystemAndGlobalGenerators::globalNoInit();
-/*!
- \fn result_type QRandomGenerator64::min()
+ // Yes, this is a double-checked lock.
+ // We can return even if the type is not completely initialized yet:
+ // any thread trying to actually use the contents of the random engine
+ // will necessarily wait on the lock.
+ if (Q_LIKELY(self->type != SystemRNG))
+ return self;
- Returns the minimum value that QRandomGenerator64 may ever generate. That is, 0.
+ SystemAndGlobalGenerators::PRNGLocker locker(self);
+ if (self->type == SystemRNG)
+ SystemAndGlobalGenerators::securelySeed(self);
- \sa max(), QRandomGenerator::max()
- */
+ return self;
+}
-/*!
- \fn result_type QRandomGenerator64::max()
+QRandomGenerator64 QRandomGenerator64::securelySeeded()
+{
+ QRandomGenerator64 result(System{});
+ SystemAndGlobalGenerators::securelySeed(&result);
+ return result;
+}
- Returns the maximum value that QRandomGenerator64 may ever generate. That is,
- \c {std::numeric_limits<result_type>::max()}.
+/// \internal
+inline QRandomGenerator::QRandomGenerator(System)
+ : type(SystemRNG)
+{
+ // don't touch storage
+}
- \sa min(), QRandomGenerator::max()
- */
+QRandomGenerator::QRandomGenerator(const QRandomGenerator &other)
+ : type(other.type)
+{
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
-/*!
- Generates one 32-bit random value and returns it.
+ if (type != SystemRNG) {
+ SystemAndGlobalGenerators::PRNGLocker lock(&other);
+ storage.engine() = other.storage.engine();
+ }
+}
- Note about casting to a signed integer: all bits returned by this function
- are random, so there's a 50% chance that the most significant bit will be
- set. If you wish to cast the returned value to int and keep it positive,
- you should mask the sign bit off:
+QRandomGenerator &QRandomGenerator::operator=(const QRandomGenerator &other)
+{
+ if (Q_UNLIKELY(this == system()) || Q_UNLIKELY(this == SystemAndGlobalGenerators::globalNoInit()))
+ qFatal("Attempted to overwrite a QRandomGenerator to system() or global().");
- \code
- int value = QRandomGenerator::generate() & std::numeric_limits<int>::max();
- \endcode
+ if ((type = other.type) != SystemRNG) {
+ SystemAndGlobalGenerators::PRNGLocker lock(&other);
+ storage.engine() = other.storage.engine();
+ }
+ return *this;
+}
- \sa generate64(), generateDouble()
- */
-quint32 QRandomGenerator::generate()
+QRandomGenerator::QRandomGenerator(std::seed_seq &sseq) Q_DECL_NOTHROW
+ : type(MersenneTwister)
{
- quint32 ret;
- fill(&ret, &ret + 1);
- return ret;
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
+
+ new (&storage.engine()) RandomEngine(sseq);
}
-/*!
- Generates one 64-bit random value and returns it.
+QRandomGenerator::QRandomGenerator(const quint32 *begin, const quint32 *end)
+ : type(MersenneTwister)
+{
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
- Note about casting to a signed integer: all bits returned by this function
- are random, so there's a 50% chance that the most significant bit will be
- set. If you wish to cast the returned value to qint64 and keep it positive,
- you should mask the sign bit off:
+ std::seed_seq s(begin, end);
+ new (&storage.engine()) RandomEngine(s);
+}
- \code
- qint64 value = QRandomGenerator::generate64() & std::numeric_limits<qint64>::max();
- \endcode
+void QRandomGenerator::discard(unsigned long long z)
+{
+ if (Q_UNLIKELY(type == SystemRNG))
+ return;
- \sa generate(), generateDouble(), QRandomGenerator64
- */
-quint64 QRandomGenerator::generate64()
+ SystemAndGlobalGenerators::PRNGLocker lock(this);
+ storage.engine().discard(z);
+}
+
+bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
{
- quint64 ret;
- fill(&ret, &ret + 1);
- return ret;
+ if (rng1.type != rng2.type)
+ return false;
+ if (rng1.type == SystemRNG)
+ return true;
+
+ // Lock global() if either is it (otherwise this locking is a no-op)
+ using PRNGLocker = QRandomGenerator::SystemAndGlobalGenerators::PRNGLocker;
+ PRNGLocker locker(&rng1 == QRandomGenerator::global() ? &rng1 : &rng2);
+ return rng1.storage.engine() == rng2.storage.engine();
}
/*!
@@ -931,9 +1247,19 @@ quint64 QRandomGenerator::generate64()
Fills the range pointed by \a buffer and \a bufferEnd with 32-bit random
values. The buffer must be correctly aligned.
*/
-void QRandomGenerator::fillRange_helper(void *buffer, void *bufferEnd)
+void QRandomGenerator::_fillRange(void *buffer, void *bufferEnd)
{
- fill(buffer, bufferEnd);
+ // Verify that the pointers are properly aligned for 32-bit
+ Q_ASSERT(quintptr(buffer) % sizeof(quint32) == 0);
+ Q_ASSERT(quintptr(bufferEnd) % sizeof(quint32) == 0);
+ quint32 *begin = static_cast<quint32 *>(buffer);
+ quint32 *end = static_cast<quint32 *>(bufferEnd);
+
+ if (type == SystemRNG || Q_UNLIKELY(uint(qt_randomdevice_control) & (UseSystemRNG|SetRandomData)))
+ return SystemGenerator::self().generate(begin, end);
+
+ SystemAndGlobalGenerators::PRNGLocker lock(this);
+ std::generate(begin, end, [this]() { return storage.engine()(); });
}
#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21)
diff --git a/src/corelib/global/qrandom.h b/src/corelib/global/qrandom.h
index 049495d4e8..bde64646a4 100644
--- a/src/corelib/global/qrandom.h
+++ b/src/corelib/global/qrandom.h
@@ -42,6 +42,7 @@
#include <QtCore/qglobal.h>
#include <algorithm> // for std::generate
+#include <random> // for std::mt19937
QT_BEGIN_NAMESPACE
@@ -51,19 +52,43 @@ class QRandomGenerator
template <typename UInt> using IfValidUInt =
typename std::enable_if<std::is_unsigned<UInt>::value && sizeof(UInt) >= sizeof(uint), bool>::type;
public:
- static QRandomGenerator system() { return {}; }
- static QRandomGenerator global() { return {}; }
- QRandomGenerator() = default;
-
- // ### REMOVE BEFORE 5.10
- QRandomGenerator *operator->() { return this; }
- static quint32 get32() { return generate(); }
- static quint64 get64() { return generate64(); }
- static qreal getReal() { return generateDouble(); }
-
- static Q_CORE_EXPORT quint32 generate();
- static Q_CORE_EXPORT quint64 generate64();
- static double generateDouble()
+ QRandomGenerator(quint32 seedValue = 1)
+ : QRandomGenerator(&seedValue, 1)
+ {}
+ template <qssize_t N> QRandomGenerator(const quint32 (&seedBuffer)[N])
+ : QRandomGenerator(seedBuffer, seedBuffer + N)
+ {}
+ QRandomGenerator(const quint32 *seedBuffer, qssize_t len)
+ : QRandomGenerator(seedBuffer, seedBuffer + len)
+ {}
+ Q_CORE_EXPORT QRandomGenerator(std::seed_seq &sseq) Q_DECL_NOTHROW;
+ Q_CORE_EXPORT QRandomGenerator(const quint32 *begin, const quint32 *end);
+
+ // copy constructor & assignment operator (move unnecessary)
+ Q_CORE_EXPORT QRandomGenerator(const QRandomGenerator &other);
+ Q_CORE_EXPORT QRandomGenerator &operator=(const QRandomGenerator &other);
+
+ friend Q_CORE_EXPORT bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2);
+ friend bool operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
+ {
+ return !(rng1 == rng2);
+ }
+
+ quint32 generate()
+ {
+ quint32 ret;
+ fillRange(&ret, 1);
+ return ret;
+ }
+
+ quint64 generate64()
+ {
+ quint32 buf[2];
+ fillRange(buf);
+ return buf[0] | (quint64(buf[1]) << 32);
+ }
+
+ double generateDouble()
{
// IEEE 754 double precision has:
// 1 bit sign
@@ -77,87 +102,161 @@ public:
return double(x) / double(limit);
}
- static qreal bounded(qreal sup)
+ double bounded(double highest)
{
- return generateDouble() * sup;
+ return generateDouble() * highest;
}
- static quint32 bounded(quint32 sup)
+ quint32 bounded(quint32 highest)
{
quint64 value = generate();
- value *= sup;
+ value *= highest;
value /= (max)() + quint64(1);
return quint32(value);
}
- static int bounded(int sup)
+ int bounded(int highest)
{
- return int(bounded(quint32(sup)));
+ return int(bounded(quint32(highest)));
}
- static quint32 bounded(quint32 min, quint32 sup)
+ quint32 bounded(quint32 lowest, quint32 highest)
{
- return bounded(sup - min) + min;
+ return bounded(highest - lowest) + lowest;
}
- static int bounded(int min, int sup)
+ int bounded(int lowest, int highest)
{
- return bounded(sup - min) + min;
+ return bounded(highest - lowest) + lowest;
}
template <typename UInt, IfValidUInt<UInt> = true>
- static void fillRange(UInt *buffer, qssize_t count)
+ void fillRange(UInt *buffer, qssize_t count)
{
- fillRange_helper(buffer, buffer + count);
+ _fillRange(buffer, buffer + count);
}
template <typename UInt, size_t N, IfValidUInt<UInt> = true>
- static void fillRange(UInt (&buffer)[N])
+ void fillRange(UInt (&buffer)[N])
{
- fillRange_helper(buffer, buffer + N);
+ _fillRange(buffer, buffer + N);
}
// API like std::seed_seq
template <typename ForwardIterator>
void generate(ForwardIterator begin, ForwardIterator end)
{
- auto generator = static_cast<quint32 (*)()>(&QRandomGenerator::generate);
- std::generate(begin, end, generator);
+ std::generate(begin, end, [this]() { return generate(); });
}
void generate(quint32 *begin, quint32 *end)
{
- fillRange_helper(begin, end);
+ _fillRange(begin, end);
}
- // API like std::random_device
+ // API like std:: random engines
typedef quint32 result_type;
result_type operator()() { return generate(); }
- double entropy() const Q_DECL_NOTHROW { return 0.0; }
+ void seed(quint32 s = 1) { *this = { s }; }
+ void seed(std::seed_seq &sseq) Q_DECL_NOTHROW { *this = { sseq }; }
+ Q_CORE_EXPORT void discard(unsigned long long z);
static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); }
static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); }
+ static inline Q_DECL_CONST_FUNCTION QRandomGenerator *system();
+ static inline Q_DECL_CONST_FUNCTION QRandomGenerator *global();
+ static inline QRandomGenerator securelySeeded();
+
+protected:
+ enum System {};
+ QRandomGenerator(System);
+
private:
- static Q_CORE_EXPORT void fillRange_helper(void *buffer, void *bufferEnd);
+ Q_CORE_EXPORT void _fillRange(void *buffer, void *bufferEnd);
+
+ friend class QRandomGenerator64;
+ struct SystemGenerator;
+ struct SystemAndGlobalGenerators;
+ typedef std::mt19937 RandomEngine;
+
+ union Storage {
+ uint dummy;
+#ifdef Q_COMPILER_UNRESTRICTED_UNIONS
+ RandomEngine twister;
+ RandomEngine &engine() { return twister; }
+ const RandomEngine &engine() const { return twister; }
+#else
+ std::aligned_storage<sizeof(RandomEngine), Q_ALIGNOF(RandomEngine)>::type buffer;
+ RandomEngine &engine() { return reinterpret_cast<RandomEngine &>(buffer); }
+ const RandomEngine &engine() const { return reinterpret_cast<const RandomEngine &>(buffer); }
+#endif
+
+ Q_STATIC_ASSERT_X(std::is_trivially_destructible<RandomEngine>::value,
+ "std::mersenne_twister not trivially destructible as expected");
+ Q_DECL_CONSTEXPR Storage();
+ };
+ uint type;
+ Storage storage;
};
-class QRandomGenerator64
+class QRandomGenerator64 : public QRandomGenerator
{
+ QRandomGenerator64(System);
public:
- static QRandomGenerator64 system() { return {}; }
- static QRandomGenerator64 global() { return {}; }
- QRandomGenerator64() = default;
+ // unshadow generate() overloads, since we'll override.
+ using QRandomGenerator::generate;
+ quint64 generate() { return generate64(); }
- static quint64 generate() { return QRandomGenerator::generate64(); }
-
- // API like std::random_device
typedef quint64 result_type;
- result_type operator()() { return QRandomGenerator::generate64(); }
- double entropy() const Q_DECL_NOTHROW { return 0.0; }
+ result_type operator()() { return generate64(); }
+
+#ifndef Q_QDOC
+ QRandomGenerator64(quint32 seedValue = 1)
+ : QRandomGenerator(seedValue)
+ {}
+ template <qssize_t N> QRandomGenerator64(const quint32 (&seedBuffer)[N])
+ : QRandomGenerator(seedBuffer)
+ {}
+ QRandomGenerator64(const quint32 *seedBuffer, qssize_t len)
+ : QRandomGenerator(seedBuffer, len)
+ {}
+ QRandomGenerator64(std::seed_seq &sseq) Q_DECL_NOTHROW
+ : QRandomGenerator(sseq)
+ {}
+ QRandomGenerator64(const quint32 *begin, const quint32 *end)
+ : QRandomGenerator(begin, end)
+ {}
+ QRandomGenerator64(const QRandomGenerator &other) : QRandomGenerator(other) {}
+
+ void discard(unsigned long long z)
+ {
+ Q_ASSERT_X(z * 2 > z, "QRandomGenerator64::discard",
+ "Overflow. Are you sure you want to skip over 9 quintillion samples?");
+ QRandomGenerator::discard(z * 2);
+ }
+
static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); }
static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); }
+ static Q_DECL_CONST_FUNCTION Q_CORE_EXPORT QRandomGenerator64 *system();
+ static Q_DECL_CONST_FUNCTION Q_CORE_EXPORT QRandomGenerator64 *global();
+ static Q_CORE_EXPORT QRandomGenerator64 securelySeeded();
+#endif // Q_QDOC
};
+inline QRandomGenerator *QRandomGenerator::system()
+{
+ return QRandomGenerator64::system();
+}
+
+inline QRandomGenerator *QRandomGenerator::global()
+{
+ return QRandomGenerator64::global();
+}
+
+QRandomGenerator QRandomGenerator::securelySeeded()
+{
+ return QRandomGenerator64::securelySeeded();
+}
QT_END_NAMESPACE
diff --git a/src/corelib/global/qrandom_p.h b/src/corelib/global/qrandom_p.h
index 6ac2904e1b..917a91098e 100644
--- a/src/corelib/global/qrandom_p.h
+++ b/src/corelib/global/qrandom_p.h
@@ -52,11 +52,12 @@
//
#include "qglobal_p.h"
+#include <private/qsimd_p.h>
QT_BEGIN_NAMESPACE
enum QRandomGeneratorControl {
- SkipMemfill = 1,
+ UseSystemRNG = 1,
SkipSystemRNG = 2,
SkipHWRNG = 4,
SetRandomData = 8,
@@ -65,6 +66,11 @@ enum QRandomGeneratorControl {
RandomDataMask = 0xfffffff0
};
+enum RNGType {
+ SystemRNG = 0,
+ MersenneTwister = 1
+};
+
#if defined(QT_BUILD_INTERNAL) && defined(QT_BUILD_CORE_LIB)
Q_CORE_EXPORT QBasicAtomicInteger<uint> qt_randomdevice_control = Q_BASIC_ATOMIC_INITIALIZER(0U);
#elif defined(QT_BUILD_INTERNAL)
@@ -73,6 +79,16 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<uint> qt_randomdevice_control;
enum { qt_randomdevice_control = 0 };
#endif
+inline bool qt_has_hwrng()
+{
+#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
+ return qCpuHasFeature(RDRND);
+#else
+ return false;
+#endif
+}
+
+
QT_END_NAMESPACE
#endif // QRANDOM_P_H
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index 9db67f2f9b..0ba8b124f7 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -146,7 +146,7 @@ QFileSelectorPrivate::QFileSelectorPrivate()
Selectors normally available are
\list
\li platform, any of the following strings which match the platform the application is running
- on (list not exhaustive): android, ios, osx, darwin, mac, linux, wince, unix, windows.
+ on (list not exhaustive): android, ios, osx, darwin, mac, macos, linux, qnx, unix, windows.
On Linux, if it can be determined, the name of the distribution too, like debian,
fedora or opensuse.
\li locale, same as QLocale().name().
@@ -373,8 +373,8 @@ QStringList QFileSelectorPrivate::platformSelectors()
# endif
#elif defined(Q_OS_UNIX)
ret << QStringLiteral("unix");
-# if !defined(Q_OS_ANDROID)
- // we don't want "linux" for Android
+# if !defined(Q_OS_ANDROID) && !defined(Q_OS_QNX)
+ // we don't want "linux" for Android or two instances of "qnx" for QNX
ret << QSysInfo::kernelType();
# ifdef Q_OS_MAC
ret << QStringLiteral("mac"); // compatibility, since kernelType() is "darwin"
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index cdb79e7c97..9e43d11e71 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -308,7 +308,7 @@ void QWindowsRemovableDriveListener::addPath(const QString &p)
notify.dbch_size = sizeof(notify);
notify.dbch_devicetype = DBT_DEVTYP_HANDLE;
notify.dbch_handle = volumeHandle;
- QEventDispatcherWin32 *winEventDispatcher = static_cast<QEventDispatcherWin32 *>(QCoreApplication::eventDispatcher());
+ QEventDispatcherWin32 *winEventDispatcher = static_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
re.devNotify = RegisterDeviceNotification(winEventDispatcher->internalHwnd(),
&notify, DEVICE_NOTIFY_WINDOW_HANDLE);
// Empirically found: The notifications also work when the handle is immediately
@@ -336,7 +336,7 @@ QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent
: QFileSystemWatcherEngine(parent)
{
#ifndef Q_OS_WINRT
- if (QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher()) {
+ if (QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance()) {
m_driveListener = new QWindowsRemovableDriveListener(this);
eventDispatcher->installNativeEventFilter(m_driveListener);
parent->setProperty("_q_driveListener",
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 82fc34c537..0a3e83206b 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -775,6 +775,7 @@ bool QIODevice::open(OpenMode mode)
d->writeBuffers.clear();
d->setReadChannelCount(isReadable() ? 1 : 0);
d->setWriteChannelCount(isWritable() ? 1 : 0);
+ d->errorString.clear();
#if defined QIODEVICE_DEBUG
printf("%p QIODevice::open(0x%x)\n", this, quint32(mode));
#endif
@@ -801,7 +802,6 @@ void QIODevice::close()
emit aboutToClose();
#endif
d->openMode = NotOpen;
- d->errorString.clear();
d->pos = 0;
d->transactionStarted = false;
d->transactionPos = 0;
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index fbbfac26f6..6ab806d9fe 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -48,6 +48,7 @@
#include <qdir.h>
#include <qelapsedtimer.h>
#include <qfileinfo.h>
+#include <qrandom.h>
#include <qregexp.h>
#include <qwineventnotifier.h>
#include <private/qsystemlibrary_p.h>
@@ -99,10 +100,8 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
wchar_t pipeName[256];
unsigned int attempts = 1000;
forever {
- // ### The user must make sure to call qsrand() to make the pipe names less predictable.
- // ### Replace the call to qrand() with a secure version, once we have it in Qt.
_snwprintf(pipeName, sizeof(pipeName) / sizeof(pipeName[0]),
- L"\\\\.\\pipe\\qt-%X", qrand());
+ L"\\\\.\\pipe\\qt-%X", QRandomGenerator::global()->generate());
DWORD dwOpenMode = FILE_FLAG_OVERLAPPED;
DWORD dwOutputBufferSize = 0;
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 0911083bac..cdaa6329f9 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -544,6 +544,38 @@ void QStorageInfoPrivate::initRootPath()
}
}
+#ifdef Q_OS_LINUX
+// udev encodes the labels with ID_LABEL_FS_ENC which is done with
+// blkid_encode_string(). Within this function some 1-byte utf-8
+// characters not considered safe (e.g. '\' or ' ') are encoded as hex
+static QString decodeFsEncString(const QString &str)
+{
+ QString decoded;
+ decoded.reserve(str.size());
+
+ int i = 0;
+ while (i < str.size()) {
+ if (i <= str.size() - 4) { // we need at least four characters \xAB
+ if (str.at(i) == QLatin1Char('\\') &&
+ str.at(i+1) == QLatin1Char('x')) {
+ bool bOk;
+ const int code = str.midRef(i+2, 2).toInt(&bOk, 16);
+ // only decode characters between 0x20 and 0x7f but not
+ // the backslash to prevent collisions
+ if (bOk && code >= 0x20 && code < 0x80 && code != '\\') {
+ decoded += QChar(code);
+ i += 4;
+ continue;
+ }
+ }
+ }
+ decoded += str.at(i);
+ ++i;
+ }
+ return decoded;
+}
+#endif
+
static inline QString retrieveLabel(const QByteArray &device)
{
#ifdef Q_OS_LINUX
@@ -557,7 +589,7 @@ static inline QString retrieveLabel(const QByteArray &device)
it.next();
QFileInfo fileInfo(it.fileInfo());
if (fileInfo.isSymLink() && fileInfo.symLinkTarget() == devicePath)
- return fileInfo.fileName();
+ return decodeFsEncString(fileInfo.fileName());
}
#elif defined Q_OS_HAIKU
fs_info fsInfo;
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 5865d9e19a..b8d3e859cf 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -165,7 +165,7 @@ QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
Char *rIter = placeholderEnd;
while (rIter != placeholderStart) {
- quint32 rnd = QRandomGenerator::generate();
+ quint32 rnd = QRandomGenerator::global()->generate();
auto applyOne = [&]() {
quint32 v = rnd & ((1 << BitsPerCharacter) - 1);
rnd >>= BitsPerCharacter;
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index a499dc2d30..cf7ed130ba 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -1037,6 +1037,7 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU
{
sectionIsPresent &= ~Authority;
sectionIsPresent |= Host;
+ port = -1;
// we never actually _loop_
while (from != end) {
@@ -1061,10 +1062,8 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU
}
}
- if (colonIndex == end - 1) {
- // found a colon but no digits after it
- port = -1;
- } else if (uint(colonIndex) < uint(end)) {
+ if (uint(colonIndex) < uint(end) - 1) {
+ // found a colon with digits after it
unsigned long x = 0;
for (int i = colonIndex + 1; i < end; ++i) {
ushort c = auth.at(i).unicode();
@@ -1083,8 +1082,6 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU
if (mode == QUrl::StrictMode)
break;
}
- } else {
- port = -1;
}
setHost(auth, from, qMin<uint>(end, colonIndex), mode);
@@ -1644,8 +1641,7 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p
if (path.isEmpty())
return NoError;
if (path.at(0) == QLatin1Char('/')) {
- if (sectionIsPresent & QUrlPrivate::Authority || port != -1 ||
- path.length() == 1 || path.at(1) != QLatin1Char('/'))
+ if (hasAuthority() || path.length() == 1 || path.at(1) != QLatin1Char('/'))
return NoError;
if (source) {
*source = path;
@@ -2474,6 +2470,8 @@ void QUrl::setPort(int port)
}
d->port = port;
+ if (port != -1)
+ d->sectionIsPresent |= QUrlPrivate::Host;
}
/*!
diff --git a/src/corelib/kernel/qfunctions_winrt.h b/src/corelib/kernel/qfunctions_winrt.h
index 9b33f8b120..d0c44be683 100644
--- a/src/corelib/kernel/qfunctions_winrt.h
+++ b/src/corelib/kernel/qfunctions_winrt.h
@@ -44,6 +44,7 @@
#ifdef Q_OS_WIN
+#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include <QtCore/QAbstractEventDispatcher>
#include <QtCore/QElapsedTimer>
diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp
index 362111a2c8..24de491326 100644
--- a/src/corelib/kernel/qwineventnotifier.cpp
+++ b/src/corelib/kernel/qwineventnotifier.cpp
@@ -199,8 +199,11 @@ void QWinEventNotifier::setEnabled(bool enable)
d->enabled = enable;
QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher.load();
- if (!eventDispatcher) // perhaps application is shutting down
+ if (!eventDispatcher) { // perhaps application is shutting down
+ if (!enable && d->waitHandle != nullptr)
+ d->unregisterWaitObject();
return;
+ }
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread");
return;
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index eb425bcd4f..e58ddaff44 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -411,7 +411,7 @@ QStateMachinePrivate::~QStateMachinePrivate()
qDeleteAll(internalEventQueue);
qDeleteAll(externalEventQueue);
- for (QHash<int, DelayedEvent>::const_iterator it = delayedEvents.begin(), eit = delayedEvents.end(); it != eit; ++it) {
+ for (QHash<int, DelayedEvent>::const_iterator it = delayedEvents.cbegin(), eit = delayedEvents.cend(); it != eit; ++it) {
delete it.value().event;
}
}
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
index 541f6af546..3dff363541 100644
--- a/src/corelib/thread/qmutex.h
+++ b/src/corelib/thread/qmutex.h
@@ -67,6 +67,12 @@ class QMutexData;
class Q_CORE_EXPORT QBasicMutex
{
public:
+#ifdef Q_COMPILER_CONSTEXPR
+ constexpr QBasicMutex()
+ : d_ptr(nullptr)
+ {}
+#endif
+
// BasicLockable concept
inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
if (!fastTryLock())
diff --git a/src/corelib/thread/qsemaphore.h b/src/corelib/thread/qsemaphore.h
index c41f258577..2639085e99 100644
--- a/src/corelib/thread/qsemaphore.h
+++ b/src/corelib/thread/qsemaphore.h
@@ -74,8 +74,6 @@ private:
class QSemaphoreReleaser
{
- QSemaphore *m_sem = nullptr;
- int m_n;
public:
QSemaphoreReleaser() = default;
explicit QSemaphoreReleaser(QSemaphore &sem, int n = 1) Q_DECL_NOTHROW
@@ -109,6 +107,10 @@ public:
m_sem = nullptr;
return old;
}
+
+private:
+ QSemaphore *m_sem = nullptr;
+ int m_n;
};
#endif // QT_NO_THREAD
diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp
index 978b663444..dd277f7753 100644
--- a/src/corelib/tools/qdatetimeparser.cpp
+++ b/src/corelib/tools/qdatetimeparser.cpp
@@ -1090,7 +1090,6 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
int dayofweek = defaultDate.dayOfWeek();
Qt::TimeSpec tspec = defaultValue.timeSpec();
int zoneOffset = 0; // In seconds; local - UTC
- QString zoneName;
QTimeZone timeZone;
switch (tspec) {
case Qt::OffsetFromUTC: // timeZone is ignored
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index ded9ad354e..501f0d345f 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -339,6 +339,7 @@ static void qt_initialize_qhash_seed()
*/
int qGlobalQHashSeed()
{
+ qt_initialize_qhash_seed();
return qt_qhash_seed.load();
}
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 0f237bce87..b96e48252e 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -388,7 +388,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
/*!
\fn QString QVersionNumber::toString() const
- Returns a string with all of the segments delimited by a '.'.
+ Returns a string with all of the segments delimited by a period (\c{.}).
\sa majorVersion(), minorVersion(), microVersion(), segments()
*/
@@ -409,7 +409,7 @@ QString QVersionNumber::toString() const
#if QT_STRINGVIEW_LEVEL < 2
/*!
Constructs a QVersionNumber from a specially formatted \a string of
- non-negative decimal numbers delimited by '.'.
+ non-negative decimal numbers delimited by a period (\c{.}).
Once the numerical segments have been parsed, the remainder of the string
is considered to be the suffix string. The start index of that string will be
diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp
index 0927f326f2..0ef5061b5f 100644
--- a/src/dbus/qdbusinternalfilters.cpp
+++ b/src/dbus/qdbusinternalfilters.cpp
@@ -407,7 +407,7 @@ QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
- if (it != connector->adaptors.end() && interface_name == QLatin1String(it->interface)) {
+ if (it != connector->adaptors.cend() && interface_name == QLatin1String(it->interface)) {
return propertyWriteReply(msg, interface_name, property_name,
writeProperty(it->adaptor, property_name, value));
}
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 7a5a630495..7086e102ea 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -72,6 +72,11 @@
that occurred, or errorString() to get a human readable
description of what went wrong.
+ \note QImageReader assumes exclusive control over the file or
+ device that is assigned. Any attempts to modify the assigned file
+ or device during the lifetime of the QImageReader object will
+ yield undefined results.
+
\section1 Formats
Call supportedImageFormats() for a list of formats that
@@ -1220,10 +1225,13 @@ float QImageReader::gamma() const
see if the image data is valid. read() may still return false
after canRead() returns \c true, if the image data is corrupt.
+ \note A QMimeDatabase lookup is normally a better approach than this
+ function for identifying potentially non-image files or data.
+
For images that support animation, canRead() returns \c false when
all frames have been read.
- \sa read(), supportedImageFormats()
+ \sa read(), supportedImageFormats(), QMimeDatabase
*/
bool QImageReader::canRead() const
{
diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp
index de32327071..d694352fc1 100644
--- a/src/gui/image/qpixmap_blitter.cpp
+++ b/src/gui/image/qpixmap_blitter.cpp
@@ -41,6 +41,7 @@
#include <qpainter.h>
#include <qimage.h>
+#include <qrandom.h>
#include <qscreen.h>
#include <private/qguiapplication_p.h>
@@ -252,7 +253,7 @@ QImage *QBlittablePlatformPixmap::overlay()
m_rasterOverlay->size() != QSize(w,h)){
m_rasterOverlay = new QImage(w,h,QImage::Format_ARGB32_Premultiplied);
m_rasterOverlay->fill(0x00000000);
- uint color = (qrand() % 11)+7;
+ uint color = QRandomGenerator::global()->bounded(11)+7;
m_overlayColor = QColor(Qt::GlobalColor(color));
m_overlayColor.setAlpha(0x88);
diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h
index 0a060a2d2c..83fc9452c5 100644
--- a/src/gui/kernel/qhighdpiscaling_p.h
+++ b/src/gui/kernel/qhighdpiscaling_p.h
@@ -402,7 +402,8 @@ inline QRegion fromNativeLocalExposedRegion(const QRegion &pixelRegion, const QW
const QPointF topLeftP = rect.topLeft() / scaleFactor;
const QSizeF sizeP = rect.size() / scaleFactor;
pointRegion += QRect(QPoint(qFloor(topLeftP.x()), qFloor(topLeftP.y())),
- QSize(qCeil(sizeP.width()), qCeil(sizeP.height())));
+ QPoint(qCeil(topLeftP.x() + sizeP.width() - 1.0),
+ qCeil(topLeftP.y() + sizeP.height() - 1.0)));
}
return pointRegion;
}
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 406fcdd226..6298dd5f45 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -1008,6 +1008,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
|| qstrncmp(rendererString, "Adreno 4xx", 8) == 0 // Same as above but without the '(TM)'
|| qstrcmp(rendererString, "GC800 core") == 0
|| qstrcmp(rendererString, "GC1000 core") == 0
+ || strstr(rendererString, "GC2000") != 0
|| qstrcmp(rendererString, "Immersion.16") == 0;
}
needsWorkaroundSet = true;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 9969124339..fea55e459d 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -55,6 +55,7 @@
# include "qaccessible.h"
#endif
#include "qhighdpiscaling_p.h"
+#include "qshapedpixmapdndwindow_p.h"
#include <private/qevent_p.h>
@@ -379,7 +380,9 @@ void QWindowPrivate::setVisible(bool visible)
QGuiApplicationPrivate::showModalWindow(q);
else
QGuiApplicationPrivate::hideModalWindow(q);
- } else if (visible && QGuiApplication::modalWindow()) {
+ // QShapedPixmapWindow is used on some platforms for showing a drag pixmap, so don't block
+ // input to this window as it is performing a drag - QTBUG-63846
+ } else if (visible && QGuiApplication::modalWindow() && !qobject_cast<QShapedPixmapWindow *>(q)) {
QGuiApplicationPrivate::updateBlockedStatus(q);
}
@@ -2575,7 +2578,7 @@ QPoint QWindowPrivate::globalPosition() const
QPoint offset = q->position();
for (const QWindow *p = q->parent(); p; p = p->parent()) {
QPlatformWindow *pw = p->handle();
- if (pw && pw->isForeignWindow()) {
+ if (pw && (pw->isForeignWindow() || pw->isEmbedded())) {
// Use mapToGlobal() for foreign windows
offset += p->mapToGlobal(QPoint(0, 0));
break;
diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp
index 58dcbed50a..3aa4c0d2e6 100644
--- a/src/gui/opengl/qopenglgradientcache.cpp
+++ b/src/gui/opengl/qopenglgradientcache.cpp
@@ -42,6 +42,7 @@
#include <private/qopenglcontext_p.h>
#include <private/qrgba64_p.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qrandom.h>
#include "qopenglfunctions.h"
#include "qopenglextensions_p.h"
@@ -137,7 +138,7 @@ GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient
{
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (cache.size() == maxCacheSize()) {
- int elem_to_remove = qrand() % maxCacheSize();
+ int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
quint64 key = cache.keys()[elem_to_remove];
// need to call glDeleteTextures on each removed cache entry:
diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm
index a234a12bf0..e1601d87dc 100644
--- a/src/gui/painting/qcoregraphics.mm
+++ b/src/gui/painting/qcoregraphics.mm
@@ -110,6 +110,7 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm)
QImage image = pm.toImage();
CGImageRef cgImage = qt_mac_toCGImage(image);
NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage);
+ nsImage.size = (pm.size() / pm.devicePixelRatioF()).toCGSize();
CGImageRelease(cgImage);
return nsImage;
}
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 68554c6579..d0d948bbb7 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -50,6 +50,7 @@
#include <qdebug.h>
#include <qbitmap.h>
#include <qmath.h>
+#include <qrandom.h>
// #include <private/qdatabuffer_p.h>
// #include <private/qpainter_p.h>
@@ -4229,7 +4230,7 @@ protected:
QSharedPointer<const CacheInfo> addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
if (cache.size() == maxCacheSize()) {
// may remove more than 1, but OK
- cache.erase(cache.begin() + (qrand() % maxCacheSize()));
+ cache.erase(cache.begin() + QRandomGenerator::global()->bounded(maxCacheSize()));
}
auto cache_entry = QSharedPointer<CacheInfo>::create(gradient.stops(), opacity, gradient.interpolationMode());
generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 86a53c21a3..2a7e0eaa0c 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -318,11 +318,12 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
return;
}
#endif
+ Q_ASSERT(mask.width() <= c.w && mask.height() <= c.h);
if (m_format == QFontEngine::Format_A32
|| m_format == QFontEngine::Format_ARGB) {
QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
- qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(),
+ qMin(mask.width(), c.w), qMin(mask.height(), c.h), m_image.bytesPerLine(),
m_image.format());
QPainter p(&ref);
p.setCompositionMode(QPainter::CompositionMode_Source);
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 0c72ac3019..220e89a0c4 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -727,11 +727,9 @@ void QFont::setFamily(const QString &family)
/*!
\since 4.8
- Returns the requested font style name, it will be used to match the
+ Returns the requested font style name. This can be used to match the
font with irregular styles (that can't be normalized in other style
- properties). It depends on system font support, thus only works for
- \macos and X11 so far. On Windows irregular styles will be added
- as separate font families so there is no need for this.
+ properties).
\sa setFamily(), setStyle()
*/
@@ -744,7 +742,12 @@ QString QFont::styleName() const
\since 4.8
Sets the style name of the font to \a styleName. When set, other style properties
- like \l style() and \l weight() will be ignored for font matching.
+ like \l style() and \l weight() will be ignored for font matching, though they may be
+ simulated afterwards if supported by the platform's font engine.
+
+ Due to the lower quality of artificially simulated styles, and the lack of full cross
+ platform support, it is not recommended to use matching by style name together with
+ matching by style properties
\sa styleName()
*/
@@ -985,6 +988,10 @@ int QFont::pixelSize() const
Sets the style() of the font to QFont::StyleItalic if \a enable is true;
otherwise the style is set to QFont::StyleNormal.
+ \note If styleName() is set, this value may be ignored, or if supported
+ on the platform, the font may be rendered tilted instead of picking a
+ designed italic font-variant.
+
\sa italic(), QFontInfo
*/
@@ -1050,6 +1057,8 @@ int QFont::weight() const
Sets the weight of the font to \a weight, using the scale defined by
\l QFont::Weight enumeration.
+ \note If styleName() is set, this value may be ignored for font selection.
+
\sa weight(), QFontInfo
*/
void QFont::setWeight(int weight)
@@ -1083,6 +1092,9 @@ void QFont::setWeight(int weight)
For finer boldness control use setWeight().
+ \note If styleName() is set, this value may be ignored, or if supported
+ on the platform, the font artificially embolded.
+
\sa bold(), setWeight()
*/
diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp
index e4a3c2b915..9639c18d2b 100644
--- a/src/gui/text/qtexttable.cpp
+++ b/src/gui/text/qtexttable.cpp
@@ -1048,7 +1048,7 @@ void QTextTable::mergeCells(int row, int column, int numRows, int numCols)
QFragmentFindHelper helper(origCellPosition, p->fragmentMap());
const auto begin = d->cells.cbegin();
const auto it = std::lower_bound(begin, d->cells.cend(), helper);
- Q_ASSERT(it != d->cells.end());
+ Q_ASSERT(it != d->cells.cend());
Q_ASSERT(!(helper < *it));
Q_ASSERT(*it == cellFragment);
const int insertCellIndex = it - begin;
@@ -1082,7 +1082,7 @@ void QTextTable::mergeCells(int row, int column, int numRows, int numCols)
QFragmentFindHelper helper(pos, p->fragmentMap());
const auto begin = d->cells.cbegin();
const auto it = std::lower_bound(begin, d->cells.cend(), helper);
- Q_ASSERT(it != d->cells.end());
+ Q_ASSERT(it != d->cells.cend());
Q_ASSERT(!(helper < *it));
Q_ASSERT(*it == fragment);
firstCellIndex = cellIndex = it - begin;
diff --git a/src/gui/vulkan/qvulkaninstance.h b/src/gui/vulkan/qvulkaninstance.h
index ada297be43..57459e458c 100644
--- a/src/gui/vulkan/qvulkaninstance.h
+++ b/src/gui/vulkan/qvulkaninstance.h
@@ -42,6 +42,10 @@
#include <QtGui/qtguiglobal.h>
+#if 0
+#pragma qt_no_master_include
+#endif
+
#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
#ifndef VK_NO_PROTOTYPES
diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp
index bc82f5df08..7dea743ea8 100644
--- a/src/gui/vulkan/qvulkanwindow.cpp
+++ b/src/gui/vulkan/qvulkanwindow.cpp
@@ -47,7 +47,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
+Q_LOGGING_CATEGORY(lcGuiVk, "qt.vulkan")
/*!
\class QVulkanWindow
@@ -357,7 +357,7 @@ QVector<VkPhysicalDeviceProperties> QVulkanWindow::availablePhysicalDevices()
return d->physDevProps;
}
- qCDebug(lcVk, "%d physical devices", count);
+ qCDebug(lcGuiVk, "%d physical devices", count);
if (!count)
return d->physDevProps;
@@ -373,7 +373,7 @@ QVector<VkPhysicalDeviceProperties> QVulkanWindow::availablePhysicalDevices()
for (uint32_t i = 0; i < count; ++i) {
VkPhysicalDeviceProperties *p = &d->physDevProps[i];
f->vkGetPhysicalDeviceProperties(d->physDevs.at(i), p);
- qCDebug(lcVk, "Physical device [%d]: name '%s' version %d.%d.%d", i, p->deviceName,
+ qCDebug(lcGuiVk, "Physical device [%d]: name '%s' version %d.%d.%d", i, p->deviceName,
VK_VERSION_MAJOR(p->driverVersion), VK_VERSION_MINOR(p->driverVersion),
VK_VERSION_PATCH(p->driverVersion));
}
@@ -442,7 +442,7 @@ QVulkanInfoVector<QVulkanExtension> QVulkanWindow::supportedDeviceExtensions()
exts.append(ext);
}
d->supportedDevExtensions.insert(physDev, exts);
- qDebug(lcVk) << "Supported device extensions:" << exts;
+ qDebug(lcGuiVk) << "Supported device extensions:" << exts;
return exts;
}
}
@@ -615,7 +615,7 @@ void QVulkanWindowPrivate::init()
Q_Q(QVulkanWindow);
Q_ASSERT(status == StatusUninitialized);
- qCDebug(lcVk, "QVulkanWindow init");
+ qCDebug(lcGuiVk, "QVulkanWindow init");
inst = q->vulkanInstance();
if (!inst) {
@@ -648,7 +648,7 @@ void QVulkanWindowPrivate::init()
qWarning("QVulkanWindow: Invalid physical device index; defaulting to 0");
physDevIndex = 0;
}
- qCDebug(lcVk, "Using physical device [%d]", physDevIndex);
+ qCDebug(lcGuiVk, "Using physical device [%d]", physDevIndex);
// Give a last chance to do decisions based on the physical device and the surface.
if (renderer)
@@ -665,7 +665,7 @@ void QVulkanWindowPrivate::init()
presQueueFamilyIdx = uint32_t(-1);
for (int i = 0; i < queueFamilyProps.count(); ++i) {
const bool supportsPresent = inst->supportsPresent(physDev, i, q);
- qCDebug(lcVk, "queue family %d: flags=0x%x count=%d supportsPresent=%d", i,
+ qCDebug(lcGuiVk, "queue family %d: flags=0x%x count=%d supportsPresent=%d", i,
queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount, supportsPresent);
if (gfxQueueFamilyIdx == uint32_t(-1)
&& (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
@@ -675,7 +675,7 @@ void QVulkanWindowPrivate::init()
if (gfxQueueFamilyIdx != uint32_t(-1)) {
presQueueFamilyIdx = gfxQueueFamilyIdx;
} else {
- qCDebug(lcVk, "No queue with graphics+present; trying separate queues");
+ qCDebug(lcGuiVk, "No queue with graphics+present; trying separate queues");
for (int i = 0; i < queueFamilyProps.count(); ++i) {
if (gfxQueueFamilyIdx == uint32_t(-1) && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
gfxQueueFamilyIdx = i;
@@ -698,7 +698,7 @@ void QVulkanWindowPrivate::init()
if (qEnvironmentVariableIsSet("QT_VK_PRESENT_QUEUE_INDEX"))
presQueueFamilyIdx = qEnvironmentVariableIntValue("QT_VK_PRESENT_QUEUE_INDEX");
#endif
- qCDebug(lcVk, "Using queue families: graphics = %u present = %u", gfxQueueFamilyIdx, presQueueFamilyIdx);
+ qCDebug(lcGuiVk, "Using queue families: graphics = %u present = %u", gfxQueueFamilyIdx, presQueueFamilyIdx);
VkDeviceQueueCreateInfo queueInfo[2];
const float prio[] = { 0 };
@@ -724,7 +724,7 @@ void QVulkanWindowPrivate::init()
if (supportedExtensions.contains(ext))
devExts.append(ext.constData());
}
- qCDebug(lcVk) << "Enabling device extensions:" << devExts;
+ qCDebug(lcGuiVk) << "Enabling device extensions:" << devExts;
VkDeviceCreateInfo devInfo;
memset(&devInfo, 0, sizeof(devInfo));
@@ -774,7 +774,7 @@ void QVulkanWindowPrivate::init()
physDevs.clear();
physDevProps.clear();
status = StatusUninitialized;
- qCDebug(lcVk, "Attempting to restart in 2 seconds");
+ qCDebug(lcGuiVk, "Attempting to restart in 2 seconds");
QTimer::singleShot(2000, q, [this]() { ensureStarted(); });
return;
}
@@ -819,7 +819,7 @@ void QVulkanWindowPrivate::init()
f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
const VkMemoryType *memType = physDevMemProps.memoryTypes;
- qCDebug(lcVk, "memtype %d: flags=0x%x", i, memType[i].propertyFlags);
+ qCDebug(lcGuiVk, "memtype %d: flags=0x%x", i, memType[i].propertyFlags);
// Find a host visible, host coherent memtype. If there is one that is
// cached as well (in addition to being coherent), prefer that.
const int hostVisibleAndCoherent = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
@@ -831,7 +831,7 @@ void QVulkanWindowPrivate::init()
}
}
}
- qCDebug(lcVk, "Picked memtype %d for host visible memory", hostVisibleMemIndex);
+ qCDebug(lcGuiVk, "Picked memtype %d for host visible memory", hostVisibleMemIndex);
deviceLocalMemIndex = 0;
for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
const VkMemoryType *memType = physDevMemProps.memoryTypes;
@@ -841,7 +841,7 @@ void QVulkanWindowPrivate::init()
break;
}
}
- qCDebug(lcVk, "Picked memtype %d for device local memory", deviceLocalMemIndex);
+ qCDebug(lcGuiVk, "Picked memtype %d for device local memory", deviceLocalMemIndex);
if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR) {
vkGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
@@ -906,7 +906,7 @@ void QVulkanWindowPrivate::init()
if (dsFormatIdx == dsFormatCandidateCount)
qWarning("QVulkanWindow: Failed to find an optimal depth-stencil format");
- qCDebug(lcVk, "Color format: %d Depth-stencil format: %d", colorFormat, dsFormat);
+ qCDebug(lcGuiVk, "Color format: %d Depth-stencil format: %d", colorFormat, dsFormat);
if (!createDefaultRenderPass())
return;
@@ -922,7 +922,7 @@ void QVulkanWindowPrivate::reset()
if (!dev) // do not rely on 'status', a half done init must be cleaned properly too
return;
- qCDebug(lcVk, "QVulkanWindow reset");
+ qCDebug(lcGuiVk, "QVulkanWindow reset");
devFuncs->vkDeviceWaitIdle(dev);
@@ -1118,7 +1118,7 @@ void QVulkanWindowPrivate::recreateSwapChain()
swapChainInfo.clipped = true;
swapChainInfo.oldSwapchain = oldSwapChain;
- qCDebug(lcVk, "Creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height);
+ qCDebug(lcGuiVk, "Creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height);
VkSwapchainKHR newSwapChain;
VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo, nullptr, &newSwapChain);
@@ -1139,7 +1139,7 @@ void QVulkanWindowPrivate::recreateSwapChain()
return;
}
- qCDebug(lcVk, "Actual swap chain buffer count: %d (supportsReadback=%d)",
+ qCDebug(lcGuiVk, "Actual swap chain buffer count: %d (supportsReadback=%d)",
actualSwapChainBufferCount, swapChainSupportsReadBack);
if (actualSwapChainBufferCount > MAX_SWAPCHAIN_BUFFER_COUNT) {
qWarning("QVulkanWindow: Too many swapchain buffers (%d)", actualSwapChainBufferCount);
@@ -1389,7 +1389,7 @@ bool QVulkanWindowPrivate::createTransientImage(VkFormat format,
return false;
}
startIndex = memInfo.memoryTypeIndex + 1;
- qCDebug(lcVk, "Allocating %u bytes for transient image (memtype %u)",
+ qCDebug(lcGuiVk, "Allocating %u bytes for transient image (memtype %u)",
uint32_t(memInfo.allocationSize), memInfo.memoryTypeIndex);
err = devFuncs->vkAllocateMemory(dev, &memInfo, nullptr, mem);
if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
@@ -1435,7 +1435,7 @@ void QVulkanWindowPrivate::releaseSwapChain()
if (!dev || !swapChain) // do not rely on 'status', a half done init must be cleaned properly too
return;
- qCDebug(lcVk, "Releasing swapchain");
+ qCDebug(lcGuiVk, "Releasing swapchain");
devFuncs->vkDeviceWaitIdle(dev);
@@ -2059,10 +2059,10 @@ bool QVulkanWindowPrivate::checkDeviceLost(VkResult err)
qWarning("QVulkanWindow: Device lost");
if (renderer)
renderer->logicalDeviceLost();
- qCDebug(lcVk, "Releasing all resources due to device lost");
+ qCDebug(lcGuiVk, "Releasing all resources due to device lost");
releaseSwapChain();
reset();
- qCDebug(lcVk, "Restarting");
+ qCDebug(lcGuiVk, "Restarting");
ensureStarted();
return true;
}
diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h
index 65249ecbfc..927c81042f 100644
--- a/src/gui/vulkan/qvulkanwindow.h
+++ b/src/gui/vulkan/qvulkanwindow.h
@@ -42,6 +42,10 @@
#include <QtGui/qtguiglobal.h>
+#if 0
+#pragma qt_no_master_include
+#endif
+
#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
#include <QtGui/qvulkaninstance.h>
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index dbcbcff8d1..0cdcee6b59 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -1102,7 +1102,7 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader
QByteArray binder(", ");
if (name == "set-cookie")
binder = "\n";
- httpReply->setHeaderField(name, value.replace('\0', binder));
+ httpReplyPrivate->fields.append(qMakePair(name, value.replace('\0', binder)));
}
}
diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h
index b338934691..9165808302 100644
--- a/src/network/access/qhttp2protocolhandler_p.h
+++ b/src/network/access/qhttp2protocolhandler_p.h
@@ -55,11 +55,11 @@
#include <private/qabstractprotocolhandler_p.h>
#include <private/qhttpnetworkrequest_p.h>
-#include "http2/http2protocol_p.h"
-#include "http2/http2streams_p.h"
-#include "http2/http2frames_p.h"
-#include "http2/hpacktable_p.h"
-#include "http2/hpack_p.h"
+#include <private/http2protocol_p.h>
+#include <private/http2streams_p.h>
+#include <private/http2frames_p.h>
+#include <private/hpacktable_p.h>
+#include <private/hpack_p.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qbytearray.h>
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 18d85a27a1..96016453c2 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -180,6 +180,7 @@ QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manage
: QNetworkReply(*new QNetworkReplyHttpImplPrivate, manager)
{
Q_D(QNetworkReplyHttpImpl);
+ Q_ASSERT(manager);
d->manager = manager;
d->managerPrivate = manager->d_func();
d->request = request;
@@ -393,9 +394,9 @@ bool QNetworkReplyHttpImpl::canReadLine () const
void QNetworkReplyHttpImpl::ignoreSslErrors()
{
Q_D(QNetworkReplyHttpImpl);
+ Q_ASSERT(d->managerPrivate);
- if (d->managerPrivate && d->managerPrivate->stsEnabled
- && d->managerPrivate->stsCache.isKnownHost(url())) {
+ if (d->managerPrivate->stsEnabled && d->managerPrivate->stsCache.isKnownHost(url())) {
// We cannot ignore any Security Transport-related errors for this host.
return;
}
@@ -406,9 +407,9 @@ void QNetworkReplyHttpImpl::ignoreSslErrors()
void QNetworkReplyHttpImpl::ignoreSslErrorsImplementation(const QList<QSslError> &errors)
{
Q_D(QNetworkReplyHttpImpl);
+ Q_ASSERT(d->managerPrivate);
- if (d->managerPrivate && d->managerPrivate->stsEnabled
- && d->managerPrivate->stsCache.isKnownHost(url())) {
+ if (d->managerPrivate->stsEnabled && d->managerPrivate->stsCache.isKnownHost(url())) {
// We cannot ignore any Security Transport-related errors for this host.
return;
}
@@ -1122,16 +1123,14 @@ QNetworkAccessManager::Operation QNetworkReplyHttpImplPrivate::getRedirectOperat
// HTTP status code can be used to decide if we can redirect with a GET
// operation or not. See http://www.ietf.org/rfc/rfc2616.txt [Sec 10.3] for
// more details
- Q_UNUSED(httpStatus);
+
+ // We MUST keep using the verb that was used originally when being redirected with 307 or 308.
+ if (httpStatus == 307 || httpStatus == 308)
+ return currentOp;
switch (currentOp) {
case QNetworkAccessManager::HeadOperation:
return QNetworkAccessManager::HeadOperation;
- case QNetworkAccessManager::PostOperation:
- // We MUST keep using POST when being redirected with 307 or 308.
- if (statusCode == 307 || statusCode == 308)
- return QNetworkAccessManager::PostOperation;
- break;
default:
break;
}
@@ -1158,6 +1157,8 @@ QNetworkRequest QNetworkReplyHttpImplPrivate::createRedirectRequest(const QNetwo
void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int httpStatus, int maxRedirectsRemaining)
{
Q_Q(QNetworkReplyHttpImpl);
+ Q_ASSERT(manager);
+ Q_ASSERT(managerPrivate);
if (isFinished)
return;
@@ -1192,7 +1193,7 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining);
operation = getRedirectOperation(operation, httpStatus);
- if (const QNetworkCookieJar *const cookieJar = (manager ? manager->cookieJar() : nullptr)) {
+ if (const QNetworkCookieJar *const cookieJar = manager->cookieJar()) {
auto cookies = cookieJar->cookiesForUrl(url);
if (!cookies.empty()) {
redirectRequest.setHeader(QNetworkRequest::KnownHeaders::CookieHeader,
@@ -1209,6 +1210,7 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
void QNetworkReplyHttpImplPrivate::followRedirect()
{
Q_Q(QNetworkReplyHttpImpl);
+ Q_ASSERT(managerPrivate);
rawHeaders.clear();
cookedHeaders.clear();
@@ -1220,7 +1222,7 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
// If the original request didn't need a session (i.e. it was to localhost)
// then we might not have a session open, to which to redirect, if the
// new URL is remote. When this happens, we need to open the session now:
- if (managerPrivate && isSessionNeeded(url)) {
+ if (isSessionNeeded(url)) {
if (auto session = managerPrivate->getNetworkSession()) {
if (session->state() != QNetworkSession::State::Connected || !session->isOpen()) {
startWaitForSession(session);
@@ -2058,9 +2060,7 @@ void QNetworkReplyHttpImplPrivate::_q_bufferOutgoingData()
void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected()
{
Q_Q(QNetworkReplyHttpImpl);
-
- if (!manager)
- return;
+ Q_ASSERT(managerPrivate);
QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession();
if (!session)
@@ -2190,28 +2190,27 @@ void QNetworkReplyHttpImplPrivate::finished()
if (preMigrationDownloaded != Q_INT64_C(-1))
totalSize = totalSize.toLongLong() + preMigrationDownloaded;
- if (manager) {
#ifndef QT_NO_BEARERMANAGEMENT
- QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession();
- if (session && session->state() == QNetworkSession::Roaming &&
- state == Working && errorCode != QNetworkReply::OperationCanceledError) {
- // only content with a known size will fail with a temporary network failure error
- if (!totalSize.isNull()) {
- if (bytesDownloaded != totalSize) {
- if (migrateBackend()) {
- // either we are migrating or the request is finished/aborted
- if (state == Reconnecting || state == WaitingForSession) {
- return; // exit early if we are migrating.
- }
- } else {
- error(QNetworkReply::TemporaryNetworkFailureError,
- QNetworkReply::tr("Temporary network failure."));
+ Q_ASSERT(managerPrivate);
+ QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession();
+ if (session && session->state() == QNetworkSession::Roaming &&
+ state == Working && errorCode != QNetworkReply::OperationCanceledError) {
+ // only content with a known size will fail with a temporary network failure error
+ if (!totalSize.isNull()) {
+ if (bytesDownloaded != totalSize) {
+ if (migrateBackend()) {
+ // either we are migrating or the request is finished/aborted
+ if (state == Reconnecting || state == WaitingForSession) {
+ return; // exit early if we are migrating.
}
+ } else {
+ error(QNetworkReply::TemporaryNetworkFailureError,
+ QNetworkReply::tr("Temporary network failure."));
}
}
}
-#endif
}
+#endif
// if we don't know the total size of or we received everything save the cache
if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
@@ -2269,17 +2268,16 @@ void QNetworkReplyHttpImplPrivate::_q_metaDataChanged()
Q_Q(QNetworkReplyHttpImpl);
// 1. do we have cookies?
// 2. are we allowed to set them?
- if (manager) {
- const auto it = cookedHeaders.constFind(QNetworkRequest::SetCookieHeader);
- if (it != cookedHeaders.cend()
- && request.attribute(QNetworkRequest::CookieSaveControlAttribute,
- QNetworkRequest::Automatic).toInt() == QNetworkRequest::Automatic) {
- QNetworkCookieJar *jar = manager->cookieJar();
- if (jar) {
- QList<QNetworkCookie> cookies =
- qvariant_cast<QList<QNetworkCookie> >(it.value());
- jar->setCookiesFromUrl(cookies, url);
- }
+ Q_ASSERT(manager);
+ const auto it = cookedHeaders.constFind(QNetworkRequest::SetCookieHeader);
+ if (it != cookedHeaders.cend()
+ && request.attribute(QNetworkRequest::CookieSaveControlAttribute,
+ QNetworkRequest::Automatic).toInt() == QNetworkRequest::Automatic) {
+ QNetworkCookieJar *jar = manager->cookieJar();
+ if (jar) {
+ QList<QNetworkCookie> cookies =
+ qvariant_cast<QList<QNetworkCookie> >(it.value());
+ jar->setCookiesFromUrl(cookies, url);
}
}
emit q->metaDataChanged();
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index f2fe3fe134..11b80d59d5 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -6,7 +6,7 @@ INCLUDEPATH += $$PWD
HEADERS += kernel/qtnetworkglobal.h \
kernel/qtnetworkglobal_p.h \
kernel/qauthenticator.h \
- kernel/qauthenticator_p.h \
+ kernel/qauthenticator_p.h \
kernel/qhostaddress.h \
kernel/qhostaddress_p.h \
kernel/qhostinfo.h \
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index 6203ba37b3..10ff35b72c 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -42,7 +42,7 @@
#include <qcoreapplication.h>
#include <qdatetime.h>
-#include <qthreadstorage.h>
+#include <qrandom.h>
#include <qurl.h>
#include <algorithm>
@@ -50,7 +50,6 @@
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
-Q_GLOBAL_STATIC(QThreadStorage<bool *>, theDnsLookupSeedStorage);
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
{
@@ -85,7 +84,7 @@ static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &record
// Randomize the slice of records.
while (!slice.isEmpty()) {
- const unsigned int pos = qrand() % slice.size();
+ const unsigned int pos = QRandomGenerator::global()->bounded(slice.size());
records[i++] = slice.takeAt(pos);
}
}
@@ -134,7 +133,7 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
// Order the slice of records.
while (!slice.isEmpty()) {
- const unsigned int weightThreshold = qrand() % (sliceWeight + 1);
+ const unsigned int weightThreshold = QRandomGenerator::global()->bounded(sliceWeight + 1);
unsigned int summedWeight = 0;
for (int j = 0; j < slice.size(); ++j) {
summedWeight += slice.at(j).weight();
@@ -1011,10 +1010,6 @@ void QDnsLookupRunnable::run()
query(requestType, requestName, nameserver, &reply);
// Sort results.
- if (!theDnsLookupSeedStorage()->hasLocalData()) {
- qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(this));
- theDnsLookupSeedStorage()->setLocalData(new bool(true));
- }
qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
qt_qdnsservicerecord_sort(reply.serviceRecords);
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index fb31607e2c..afdc4cf319 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -411,13 +411,13 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
// get the pointer to sendmsg and recvmsg
DWORD bytesReturned;
GUID recvmsgguid = WSAID_WSARECVMSG;
- if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&recvmsgguid, sizeof(recvmsgguid),
&recvmsg, sizeof(recvmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
recvmsg = 0;
GUID sendmsgguid = WSAID_WSASENDMSG;
- if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&sendmsgguid, sizeof(sendmsgguid),
&sendmsg, sizeof(sendmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
sendmsg = 0;
@@ -1257,26 +1257,28 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress);
}
- if (ret != -1 && recvmsg) {
+ if (ret != -1 && recvmsg && options != QAbstractSocketEngine::WantNone) {
// get the ancillary data
+ header->destinationPort = localPort;
WSACMSGHDR *cmsgptr;
for (cmsgptr = WSA_CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
cmsgptr = WSA_CMSG_NXTHDR(&msg, cmsgptr)) {
if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
&& cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in6_pktinfo))) {
in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
- QHostAddress target(reinterpret_cast<quint8 *>(&info->ipi6_addr));
- if (info->ipi6_ifindex)
- target.setScopeId(QString::number(info->ipi6_ifindex));
+
+ header->destinationAddress.setAddress(reinterpret_cast<quint8 *>(&info->ipi6_addr));
+ header->ifindex = info->ipi6_ifindex;
+ if (header->ifindex)
+ header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex));
}
if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO
&& cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in_pktinfo))) {
in_pktinfo *info = reinterpret_cast<in_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
u_long addr;
WSANtohl(socketDescriptor, info->ipi_addr.s_addr, &addr);
- QHostAddress target(addr);
- if (info->ipi_ifindex)
- target.setScopeId(QString::number(info->ipi_ifindex));
+ header->destinationAddress.setAddress(addr);
+ header->ifindex = info->ipi_ifindex;
}
if (cmsgptr->cmsg_len == WSA_CMSG_LEN(sizeof(int))
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
index 6716c0158b..817317f303 100644
--- a/src/network/ssl/qsslkey_qt.cpp
+++ b/src/network/ssl/qsslkey_qt.cpp
@@ -287,7 +287,7 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
// ### use a cryptographically secure random number generator
- quint64 random = QRandomGenerator::generate64();
+ quint64 random = QRandomGenerator::system()->generate64();
QByteArray iv = QByteArray::fromRawData(reinterpret_cast<const char *>(&random), sizeof(random));
Cipher cipher = DesEde3Cbc;
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 84c814cca4..145ae1a3c8 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1686,7 +1686,8 @@ bool QSslSocket::waitForDisconnected(int msecs)
if (!d->plainSocket)
return false;
- if (d->mode == UnencryptedMode)
+ // Forward to the plain socket unless the connection is secure.
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake)
return d->plainSocket->waitForDisconnected(msecs);
QElapsedTimer stopWatch;
@@ -1697,6 +1698,17 @@ bool QSslSocket::waitForDisconnected(int msecs)
if (!waitForEncrypted(msecs))
return false;
}
+ // We are delaying the disconnect, if the write buffer is not empty.
+ // So, start the transmission.
+ if (!d->writeBuffer.isEmpty())
+ d->transmit();
+
+ // At this point, the socket might be disconnected, if disconnectFromHost()
+ // was called just after the connectToHostEncrypted() call. Also, we can
+ // lose the connection as a result of the transmit() call.
+ if (state() == UnconnectedState)
+ return true;
+
bool retVal = d->plainSocket->waitForDisconnected(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
if (!retVal) {
setSocketState(d->plainSocket->state());
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index b4ca49514f..fc5e236ca6 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -41,6 +41,7 @@
#include <private/qdrawhelper_p.h>
#include <private/qgl_p.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qrandom.h>
QT_BEGIN_NAMESPACE
@@ -130,7 +131,7 @@ GLuint QGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gra
{
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (cache.size() == maxCacheSize()) {
- int elem_to_remove = qrand() % maxCacheSize();
+ int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
quint64 key = cache.keys()[elem_to_remove];
// need to call glDeleteTextures on each removed cache entry:
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index 1fb73e873a..898cabd786 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -1771,15 +1771,25 @@ QFixed QFontEngineFT::scaledBitmapMetrics(QFixed m) const
return m * scalableBitmapScaleFactor;
}
-glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m) const
+glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &t) const
{
+ QTransform trans(t);
+ const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
+ trans.scale(scaleFactor, scaleFactor);
+
+ QRectF rect(m.x.toReal(), m.y.toReal(), m.width.toReal(), m.height.toReal());
+ QPointF offset(m.xoff.toReal(), m.yoff.toReal());
+
+ rect = trans.mapRect(rect);
+ offset = trans.map(offset);
+
glyph_metrics_t metrics;
- metrics.x = scaledBitmapMetrics(m.x);
- metrics.y = scaledBitmapMetrics(m.y);
- metrics.width = scaledBitmapMetrics(m.width);
- metrics.height = scaledBitmapMetrics(m.height);
- metrics.xoff = scaledBitmapMetrics(m.xoff);
- metrics.yoff = scaledBitmapMetrics(m.yoff);
+ metrics.x = QFixed::fromReal(rect.x());
+ metrics.y = QFixed::fromReal(rect.y());
+ metrics.width = QFixed::fromReal(rect.width());
+ metrics.height = QFixed::fromReal(rect.height());
+ metrics.xoff = QFixed::fromReal(offset.x());
+ metrics.yoff = QFixed::fromReal(offset.y());
return metrics;
}
@@ -1873,7 +1883,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
unlockFace();
if (isScalableBitmap())
- overall = scaledBitmapMetrics(overall);
+ overall = scaledBitmapMetrics(overall, QTransform());
return overall;
}
@@ -1912,7 +1922,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
unlockFace();
if (isScalableBitmap())
- overall = scaledBitmapMetrics(overall);
+ overall = scaledBitmapMetrics(overall, QTransform());
return overall;
}
@@ -1950,7 +1960,7 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe
}
if (isScalableBitmap())
- overall = scaledBitmapMetrics(overall);
+ overall = scaledBitmapMetrics(overall, matrix);
return overall;
}
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
index 7efd175402..f5585da7de 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
@@ -321,7 +321,7 @@ private:
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
bool shouldUseDesignMetrics(ShaperFlags flags) const;
QFixed scaledBitmapMetrics(QFixed m) const;
- glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m) const;
+ glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &matrix) const;
GlyphFormat defaultFormat;
FT_Matrix matrix;
diff --git a/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp
index 1a2a07260a..382d142334 100644
--- a/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp
+++ b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp
@@ -45,7 +45,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
+Q_LOGGING_CATEGORY(lcPlatVk, "qt.vulkan")
/*!
\class QBasicPlatformVulkanInstance
@@ -87,7 +87,7 @@ void QBasicPlatformVulkanInstance::init(QLibrary *lib)
if (m_vkGetInstanceProcAddr)
return;
- qCDebug(lcVk, "Vulkan init (%s)", qPrintable(lib->fileName()));
+ qCDebug(lcPlatVk, "Vulkan init (%s)", qPrintable(lib->fileName()));
// While not strictly required with every implementation, try to follow the spec
// and do not rely on core functions being exported.
@@ -137,7 +137,7 @@ void QBasicPlatformVulkanInstance::init(QLibrary *lib)
m_supportedLayers.append(layer);
}
}
- qCDebug(lcVk) << "Supported Vulkan instance layers:" << m_supportedLayers;
+ qCDebug(lcPlatVk) << "Supported Vulkan instance layers:" << m_supportedLayers;
uint32_t extCount = 0;
m_vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr);
@@ -152,7 +152,7 @@ void QBasicPlatformVulkanInstance::init(QLibrary *lib)
m_supportedExtensions.append(ext);
}
}
- qDebug(lcVk) << "Supported Vulkan instance extensions:" << m_supportedExtensions;
+ qDebug(lcPlatVk) << "Supported Vulkan instance extensions:" << m_supportedExtensions;
}
QVulkanInfoVector<QVulkanLayer> QBasicPlatformVulkanInstance::supportedLayers() const
@@ -206,13 +206,13 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const
if (!m_supportedLayers.contains(layerName))
m_enabledLayers.removeAt(i--);
}
- qDebug(lcVk) << "Enabling Vulkan instance layers:" << m_enabledLayers;
+ qDebug(lcPlatVk) << "Enabling Vulkan instance layers:" << m_enabledLayers;
for (int i = 0; i < m_enabledExtensions.count(); ++i) {
const QByteArray &extName(m_enabledExtensions[i]);
if (!m_supportedExtensions.contains(extName))
m_enabledExtensions.removeAt(i--);
}
- qDebug(lcVk) << "Enabling Vulkan instance extensions:" << m_enabledExtensions;
+ qDebug(lcPlatVk) << "Enabling Vulkan instance extensions:" << m_enabledExtensions;
VkInstanceCreateInfo instInfo;
memset(&instInfo, 0, sizeof(instInfo));
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
index 6016d460fc..48693ccdb0 100644
--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
@@ -222,7 +222,7 @@ bool QComposeInputContext::checkComposeTable()
int next = 1;
do {
// if we are at the end of the table, then we have nothing to do here
- if (it + next != m_composeTable.end()) {
+ if (it + next != m_composeTable.constEnd()) {
QComposeTableElement nextElem = *(it + next);
if (isDuplicate(elem, nextElem)) {
elem = nextElem;
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index e4d670239f..a3bc58bb89 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -105,15 +105,15 @@ namespace QtAndroidAccessibility
{
QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->isValid()) {
- jintArray jArray = env->NewIntArray(jsize(iface->childCount()));
- for (int i = 0; i < iface->childCount(); ++i) {
+ const int childCount = iface->childCount();
+ QVarLengthArray<jint, 8> ifaceIdArray(childCount);
+ for (int i = 0; i < childCount; ++i) {
QAccessibleInterface *child = iface->child(i);
- if (child && child->isValid()) {
- QAccessible::Id ifaceId = QAccessible::uniqueId(child);
- jint jid = ifaceId;
- env->SetIntArrayRegion(jArray, i, 1, &jid);
- }
+ if (child && child->isValid())
+ ifaceIdArray.append(QAccessible::uniqueId(child));
}
+ jintArray jArray = env->NewIntArray(jsize(ifaceIdArray.count()));
+ env->SetIntArrayRegion(jArray, 0, ifaceIdArray.count(), ifaceIdArray.data());
return jArray;
}
diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp
index 85b814ce1c..8eea1e654e 100644
--- a/src/plugins/platforms/cocoa/messages.cpp
+++ b/src/plugins/platforms/cocoa/messages.cpp
@@ -75,7 +75,7 @@ QString qt_mac_applicationmenu_string(int type)
QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption)
{
QString captionNoAmpersand(caption);
- captionNoAmpersand.remove(QChar('&'));
+ captionNoAmpersand.remove(QLatin1Char('&'));
const QString aboutString = QCoreApplication::translate("QCocoaMenuItem", "About");
if (captionNoAmpersand.startsWith(aboutString, Qt::CaseInsensitive) || caption.endsWith(aboutString, Qt::CaseInsensitive))
return QPlatformMenuItem::AboutRole;
diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h
index a9c9cc42e5..e41898fe59 100644
--- a/src/plugins/platforms/cocoa/messages.h
+++ b/src/plugins/platforms/cocoa/messages.h
@@ -45,6 +45,17 @@
QT_BEGIN_NAMESPACE
+enum {
+ ServicesAppMenuItem = 0,
+ HideAppMenuItem,
+ HideOthersAppMenuItem,
+ ShowAllAppMenuItem,
+ PreferencesAppMenuItem,
+ QuitAppMenuItem,
+ AboutAppMenuItem
+};
+
+
QString msgAboutQt();
QString qt_mac_applicationmenu_string(int type);
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 9fa7487623..301771fd53 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -60,8 +60,9 @@ QT_BEGIN_NAMESPACE
class QCocoaScreen;
-class QCocoaIntegration : public QPlatformIntegration
+class QCocoaIntegration : public QObject, public QPlatformIntegration
{
+ Q_OBJECT
public:
enum Option {
UseFreeTypeFontEngine = 0x1
@@ -120,6 +121,9 @@ public:
void beep() const override;
+private Q_SLOTS:
+ void focusWindowChanged(QWindow *);
+
private:
static QCocoaIntegration *mInstance;
Options mOptions;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index dd17848109..55b3805df3 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -179,6 +179,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
QMacInternalPasteboardMime::initializeMimeTypes();
QCocoaMimeTypes::initializeMimeTypes();
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+
+ connect(qGuiApp, &QGuiApplication::focusWindowChanged,
+ this, &QCocoaIntegration::focusWindowChanged);
}
QCocoaIntegration::~QCocoaIntegration()
@@ -222,6 +225,8 @@ QCocoaIntegration::Options QCocoaIntegration::options() const
return mOptions;
}
+Q_LOGGING_CATEGORY(lcCocoaScreen, "qt.qpa.cocoa.screens");
+
/*!
\brief Synchronizes the screen list, adds new screens, removes deleted ones
*/
@@ -261,9 +266,11 @@ void QCocoaIntegration::updateScreens()
if (screen) {
remainingScreens.remove(screen);
screen->updateGeometry();
+ qCDebug(lcCocoaScreen) << "Updated properties of" << screen;
} else {
screen = new QCocoaScreen(i);
mScreens.append(screen);
+ qCDebug(lcCocoaScreen) << "Adding" << screen;
screenAdded(screen);
}
siblings << screen;
@@ -280,6 +287,7 @@ void QCocoaIntegration::updateScreens()
mScreens.removeOne(screen);
// Prevent stale references to NSScreen during destroy
screen->m_screenIndex = -1;
+ qCDebug(lcCocoaScreen) << "Removing" << screen;
destroyScreen(screen);
}
}
@@ -505,4 +513,33 @@ void QCocoaIntegration::beep() const
NSBeep();
}
+void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
+{
+ // Don't revert icon just because we lost focus
+ if (!focusWindow)
+ return;
+
+ static bool hasDefaultApplicationIcon = [](){
+ NSImage *genericApplicationIcon = [[NSWorkspace sharedWorkspace]
+ iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
+ NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon];
+
+ NSRect rect = NSMakeRect(0, 0, 32, 32);
+ return [applicationIcon CGImageForProposedRect:&rect context:nil hints:nil]
+ == [genericApplicationIcon CGImageForProposedRect:&rect context:nil hints:nil];
+ }();
+
+ // Don't let the window icon override an explicit application icon set in the Info.plist
+ if (!hasDefaultApplicationIcon)
+ return;
+
+ // Or an explicit application icon set on QGuiApplication
+ if (!qGuiApp->windowIcon().isNull())
+ return;
+
+ setApplicationIcon(focusWindow->icon());
+}
+
+#include "moc_qcocoaintegration.cpp"
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 4392de2f9b..f5fa93cbb5 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -93,6 +93,8 @@ public:
void timerEvent(QTimerEvent *e) override;
+ void syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate);
+
private:
QCocoaMenuItem *itemOrNull(int index) const;
void insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem);
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index eeb4c01791..a54284dbae 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -434,6 +434,11 @@ void QCocoaMenu::timerEvent(QTimerEvent *e)
void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem)
{
+ syncMenuItem_helper(menuItem, false /*menubarUpdate*/);
+}
+
+void QCocoaMenu::syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate)
+{
QMacAutoReleasePool pool;
QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem);
if (!m_menuItems.contains(cocoaItem)) {
@@ -443,8 +448,9 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem)
const bool wasMerged = cocoaItem->isMerged();
NSMenuItem *oldItem = cocoaItem->nsItem();
+ NSMenuItem *syncedItem = cocoaItem->sync();
- if (cocoaItem->sync() != oldItem) {
+ if (syncedItem != oldItem) {
// native item was changed for some reason
if (oldItem) {
if (wasMerged) {
@@ -462,6 +468,14 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem)
// when an item's enabled state changes after menuWillOpen:
scheduleUpdate();
}
+
+ // This may be a good moment to attach this item's eventual submenu to the
+ // synced item, but only on the condition we're all currently hooked to the
+ // menunbar. A good indicator of this being the right moment is knowing that
+ // we got called from QCocoaMenuBar::updateMenuBarImmediately().
+ if (menubarUpdate)
+ if (QCocoaMenu *submenu = cocoaItem->menu())
+ submenu->setAttachedItem(syncedItem);
}
void QCocoaMenu::syncSeparatorsCollapsible(bool enable)
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index 0a46e80695..32a8fd89b4 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -72,6 +72,8 @@ public:
QList<QCocoaMenuItem*> merged() const;
NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r);
+ void syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate);
+
private:
static QCocoaWindow *findWindowForMenubar();
static QCocoaMenuBar *findGlobalMenubar();
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 36655dffab..fd28a4d7da 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -155,7 +155,7 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor
}
}
- syncMenu(menu);
+ syncMenu_helper(menu, false /*internaCall*/);
if (needsImmediateUpdate())
updateMenuBarImmediately();
@@ -183,11 +183,16 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu)
void QCocoaMenuBar::syncMenu(QPlatformMenu *menu)
{
+ syncMenu_helper(menu, false /*internaCall*/);
+}
+
+void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
+{
QMacAutoReleasePool pool;
QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(menu);
Q_FOREACH (QCocoaMenuItem *item, cocoaMenu->items())
- cocoaMenu->syncMenuItem(item);
+ cocoaMenu->syncMenuItem_helper(item, menubarUpdate);
BOOL shouldHide = YES;
if (cocoaMenu->isVisible()) {
@@ -357,7 +362,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
menu->setAttachedItem(item);
menu->setMenuParent(mb);
// force a sync?
- mb->syncMenu(menu);
+ mb->syncMenu_helper(menu, true /*menubarUpdate*/);
menu->propagateEnabledState(!disableForModal);
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index d135b244e0..eaf310ec51 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -149,10 +149,6 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
QMacAutoReleasePool pool;
m_menu = static_cast<QCocoaMenu *>(menu);
if (m_menu) {
- if (m_native) {
- // Skip automatic menu item validation
- m_native.action = nil;
- }
m_menu->setMenuParent(this);
m_menu->propagateEnabledState(isEnabled());
} else {
@@ -369,24 +365,20 @@ NSMenuItem *QCocoaMenuItem::sync()
return m_native;
}
-QT_BEGIN_NAMESPACE
-extern QString qt_mac_applicationmenu_string(int type);
-QT_END_NAMESPACE
-
QString QCocoaMenuItem::mergeText()
{
QCocoaMenuLoader *loader = [QCocoaMenuLoader sharedMenuLoader];
if (m_native == [loader aboutMenuItem]) {
- return qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName());
+ return qt_mac_applicationmenu_string(AboutAppMenuItem).arg(qt_mac_applicationName());
} else if (m_native== [loader aboutQtMenuItem]) {
if (m_text == QString("About Qt"))
return msgAboutQt();
else
return m_text;
} else if (m_native == [loader preferencesMenuItem]) {
- return qt_mac_applicationmenu_string(4);
+ return qt_mac_applicationmenu_string(PreferencesAppMenuItem);
} else if (m_native == [loader quitMenuItem]) {
- return qt_mac_applicationmenu_string(5).arg(qt_mac_applicationName());
+ return qt_mac_applicationmenu_string(QuitAppMenuItem).arg(qt_mac_applicationName());
} else if (m_text.contains('\t')) {
return m_text.left(m_text.indexOf('\t'));
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index 01a3c04afb..0d9bb5009d 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -47,14 +47,8 @@
#include <QtCore/private/qcore_mac_p.h>
#include <QtCore/private/qthread_p.h>
#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qdebug.h>
#include <QtGui/private/qguiapplication_p.h>
-QT_FORWARD_DECLARE_CLASS(QCFString)
-QT_FORWARD_DECLARE_CLASS(QString)
-
@implementation QCocoaMenuLoader
+ (instancetype)sharedMenuLoader
@@ -314,13 +308,13 @@ QT_FORWARD_DECLARE_CLASS(QString)
{
#ifndef QT_NO_TRANSLATION
- [servicesItem setTitle:qt_mac_applicationmenu_string(0).toNSString()];
- [hideItem setTitle:qt_mac_applicationmenu_string(1).arg(qt_mac_applicationName()).toNSString()];
- [hideAllOthersItem setTitle:qt_mac_applicationmenu_string(2).toNSString()];
- [showAllItem setTitle:qt_mac_applicationmenu_string(3).toNSString()];
- [preferencesItem setTitle:qt_mac_applicationmenu_string(4).toNSString()];
- [quitItem setTitle:qt_mac_applicationmenu_string(5).arg(qt_mac_applicationName()).toNSString()];
- [aboutItem setTitle:qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName()).toNSString()];
+ [servicesItem setTitle:qt_mac_applicationmenu_string(ServicesAppMenuItem).toNSString()];
+ [hideItem setTitle:qt_mac_applicationmenu_string(HideAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
+ [hideAllOthersItem setTitle:qt_mac_applicationmenu_string(HideOthersAppMenuItem).toNSString()];
+ [showAllItem setTitle:qt_mac_applicationmenu_string(ShowAllAppMenuItem).toNSString()];
+ [preferencesItem setTitle:qt_mac_applicationmenu_string(PreferencesAppMenuItem).toNSString()];
+ [quitItem setTitle:qt_mac_applicationmenu_string(QuitAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
+ [aboutItem setTitle:qt_mac_applicationmenu_string(AboutAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
#endif
}
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
index b44f8873e4..3d59c3de79 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.h
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -98,6 +98,10 @@ public:
QList<QPlatformScreen *> m_siblings;
};
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QCocoaScreen *screen);
+#endif
+
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index 2c0d04dc3e..ed1b19cd53 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -288,4 +288,22 @@ QRectF QCocoaScreen::mapFromNative(CGRect rect, QCocoaScreen *screen)
return qt_mac_flip(QRectF::fromCGRect(rect), screen->geometry());
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QCocoaScreen *screen)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QCocoaScreen(" << (const void *)screen;
+ if (screen) {
+ debug << ", index=" << screen->m_screenIndex;
+ debug << ", native=" << screen->nativeScreen();
+ debug << ", geometry=" << screen->geometry();
+ debug << ", dpr=" << screen->devicePixelRatio();
+ debug << ", name=" << screen->name();
+ }
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 8ac3ec228f..c3160e32c2 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -79,6 +79,8 @@ static void qt_closePopups()
}
}
+Q_LOGGING_CATEGORY(lcCocoaNotifications, "qt.qpa.cocoa.notifications");
+
static void qRegisterNotificationCallbacks()
{
static const QLatin1String notificationHandlerPrefix(Q_NOTIFICATION_PREFIX);
@@ -110,11 +112,24 @@ static void qRegisterNotificationCallbacks()
if (QNSView *qnsView = qnsview_cast(notification.object))
cocoaWindows += qnsView.platformWindow;
} else {
- qCWarning(lcQpaCocoaWindow) << "Unhandled notifcation"
+ qCWarning(lcCocoaNotifications) << "Unhandled notifcation"
<< notification.name << "for" << notification.object;
return;
}
+ if (lcCocoaNotifications().isDebugEnabled()) {
+ if (cocoaWindows.isEmpty()) {
+ qCDebug(lcCocoaNotifications) << "Could not find forwarding target for" <<
+ qPrintable(notificationName) << "from" << notification.object;
+ } else {
+ QVector<QCocoaWindow *> debugWindows;
+ for (QCocoaWindow *cocoaWindow : cocoaWindows)
+ debugWindows += cocoaWindow;
+ qCDebug(lcCocoaNotifications) << "Forwarding" << qPrintable(notificationName) <<
+ "to" << debugWindows;
+ }
+ }
+
// FIXME: Could be a foreign window, look up by iterating top level QWindows
for (QCocoaWindow *cocoaWindow : cocoaWindows) {
@@ -1427,6 +1442,21 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
applyContentBorderThickness(nsWindow);
+ // Prevent CoreGraphics RGB32 -> RGB64 backing store conversions on deep color
+ // displays by forcing 8-bit components, unless a deep color format has been
+ // requested. This conversion uses significant CPU time.
+ QSurface::SurfaceType surfaceType = QPlatformWindow::window()->surfaceType();
+ bool usesCoreGraphics = surfaceType == QSurface::RasterSurface || surfaceType == QSurface::RasterGLSurface;
+ QSurfaceFormat surfaceFormat = QPlatformWindow::window()->format();
+ bool usesDeepColor = surfaceFormat.redBufferSize() > 8 ||
+ surfaceFormat.greenBufferSize() > 8 ||
+ surfaceFormat.blueBufferSize() > 8;
+ bool usesLayer = view().layer;
+ if (usesCoreGraphics && !usesDeepColor && !usesLayer) {
+ [nsWindow setDynamicDepthLimit:NO];
+ [nsWindow setDepthLimit:NSWindowDepthTwentyfourBitRGB];
+ }
+
return nsWindow;
}
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index a0ffc11967..90a6f936e2 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -1878,6 +1878,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
}
else {
NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
+ nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
[nsimage release];
}
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index 799704a407..e846fa043c 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -46,6 +46,8 @@
#include <qpa/qwindowsysteminterface.h>
#include <qoperatingsystemversion.h>
+Q_LOGGING_CATEGORY(lcCocoaEvents, "qt.qpa.cocoa.events");
+
static bool isMouseEvent(NSEvent *ev)
{
switch ([ev type]) {
@@ -116,6 +118,22 @@ static bool isMouseEvent(NSEvent *ev)
return qnsview_cast(self.contentView).platformWindow;
}
+- (NSString *)description
+{
+ NSMutableString *description = [NSMutableString stringWithString:qt_objcDynamicSuper()];
+
+#ifndef QT_NO_DEBUG_STREAM
+ QString contentViewDescription;
+ QDebug debug(&contentViewDescription);
+ debug.nospace() << "; contentView=" << qnsview_cast(self.contentView) << ">";
+
+ NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
+ [description replaceCharactersInRange:lastCharacter withString:contentViewDescription.toNSString()];
+#endif
+
+ return description;
+}
+
- (BOOL)canBecomeKeyWindow
{
QCocoaWindow *pw = self.platformWindow;
@@ -177,6 +195,8 @@ static bool isMouseEvent(NSEvent *ev)
- (void)sendEvent:(NSEvent*)theEvent
{
+ qCDebug(lcCocoaEvents) << "Sending" << theEvent << "to" << self;
+
// We might get events for a NSWindow after the corresponding platform
// window has been deleted, as the NSWindow can outlive the QCocoaWindow
// e.g. if being retained by other parts of AppKit, or in an auto-release
@@ -185,6 +205,10 @@ static bool isMouseEvent(NSEvent *ev)
if (!self.platformWindow)
return;
+ // Prevent deallocation of this NSWindow during event delivery, as we
+ // have logic further below that depends on the window being alive.
+ [[self retain] autorelease];
+
const char *eventType = object_getClassName(theEvent);
if (QWindowSystemInterface::handleNativeEvent(self.platformWindow->window(),
QByteArray::fromRawData(eventType, qstrlen(eventType)), theEvent, nullptr)) {
@@ -221,6 +245,7 @@ static bool isMouseEvent(NSEvent *ev)
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (void)dealloc
{
+ qCDebug(lcQpaCocoaWindow) << "dealloc" << self;
qt_objcDynamicSuper();
}
#pragma clang diagnostic pop
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index 3eb8675d77..75bb786b28 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -61,6 +61,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatforminputcontext.h>
+#include <qpa/qplatformtheme.h>
#include <qpa/qplatformservices.h>
@@ -167,6 +168,37 @@ QAbstractEventDispatcher *QOffscreenIntegration::createEventDispatcher() const
#endif
}
+static QString themeName() { return QStringLiteral("offscreen"); }
+
+QStringList QOffscreenIntegration::themeNames() const
+{
+ return QStringList(themeName());
+}
+
+// Restrict the styles to "fusion" to prevent native styles requiring native
+// window handles (eg Windows Vista style) from being used.
+class OffscreenTheme : public QPlatformTheme
+{
+public:
+ OffscreenTheme() {}
+
+ QVariant themeHint(ThemeHint h) const override
+ {
+ switch (h) {
+ case StyleNames:
+ return QVariant(QStringList(QStringLiteral("fusion")));
+ default:
+ break;
+ }
+ return QPlatformTheme::themeHint(h);
+ }
+};
+
+QPlatformTheme *QOffscreenIntegration::createPlatformTheme(const QString &name) const
+{
+ return name == themeName() ? new OffscreenTheme() : nullptr;
+}
+
QPlatformFontDatabase *QOffscreenIntegration::fontDatabase() const
{
return m_fontDatabase.data();
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h
index 4c7df207eb..c84c1f7c50 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.h
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h
@@ -69,6 +69,9 @@ public:
QPlatformFontDatabase *fontDatabase() const override;
QAbstractEventDispatcher *createEventDispatcher() const override;
+ QStringList themeNames() const;
+ QPlatformTheme *createPlatformTheme(const QString &name) const;
+
static QOffscreenIntegration *createOffscreenIntegration();
private:
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index cf83525c6c..1efb01d52e 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -992,7 +992,9 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode,
break;
case QFileDialogOptions::Directory:
case QFileDialogOptions::DirectoryOnly:
- flags |= FOS_PICKFOLDERS | FOS_FILEMUSTEXIST;
+ // QTBUG-63645: Restrict to file system items, as Qt cannot deal with
+ // places like 'Network', etc.
+ flags |= FOS_PICKFOLDERS | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM;
break;
case QFileDialogOptions::ExistingFiles:
flags |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT;
@@ -1201,6 +1203,8 @@ void QWindowsNativeFileDialogBase::onSelectionChange()
{
const QList<QUrl> current = selectedFiles();
m_data.setSelectedFiles(current);
+ qDebug() << __FUNCTION__ << current << current.size();
+
if (current.size() == 1)
emit currentChanged(current.front());
}
@@ -1397,7 +1401,7 @@ QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const
for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) {
QWindowsShellItem qItem(item);
const QString path = qItem.path();
- if (path.isEmpty()) {
+ if (path.isEmpty() && !qItem.isDir()) {
const QString temporaryCopy = createTemporaryItemCopy(qItem);
if (temporaryCopy.isEmpty())
qWarning() << "Unable to create a local copy of" << qItem;
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
index 3ee591de8c..901d132ea5 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -354,7 +354,7 @@ HICON QWindowsSystemTrayIcon::createIcon(const QIcon &icon)
m_hIcon = nullptr;
if (icon.isNull())
return oldIcon;
- const QSize requestedSize(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
+ const QSize requestedSize = QSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
const QSize size = icon.actualSize(requestedSize);
const QPixmap pm = icon.pixmap(size);
if (!pm.isNull())
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 8702ce7bab..854c19ccf8 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -74,6 +74,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/QDebug>
+#include <QtCore/QLibraryInfo>
#include <dwmapi.h>
@@ -1579,7 +1580,7 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
setFlag(WithinSetGeometry);
setGeometry_sys(rect);
clearFlag(WithinSetGeometry);
- if (m_data.geometry != rect) {
+ if (m_data.geometry != rect && (isVisible() || QLibraryInfo::isDebugBuild())) {
qWarning("%s: Unable to set geometry %dx%d+%d+%d on %s/'%s'."
" Resulting geometry: %dx%d+%d+%d "
"(frame: %d, %d, %d, %d, custom margin: %d, %d, %d, %d"
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index d97c532b67..e60b5213ff 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -249,7 +249,7 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
isTablet = true;
tabletData.pointerType = QTabletEvent::Eraser;
dbgType = QLatin1String("eraser");
- } else if (name.contains("cursor")) {
+ } else if (name.contains("cursor") && !(name.contains("cursor controls") && name.contains("trackball"))) {
isTablet = true;
tabletData.pointerType = QTabletEvent::Cursor;
dbgType = QLatin1String("cursor");
diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp
index 5800b84fc6..2d16c3d60c 100644
--- a/src/plugins/sqldrivers/oci/qsql_oci.cpp
+++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp
@@ -2640,7 +2640,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
QString stmt(QLatin1String("select b.column_name, b.index_name, a.table_name, a.owner "
"from all_constraints a, all_ind_columns b "
"where a.constraint_type='P' "
- "and b.index_name = a.constraint_name "
+ "and b.index_name = a.index_name "
"and b.index_owner = a.owner"));
bool buildIndex = false;
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp
index 7699bede27..1dce2f28c1 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql.cpp
+++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp
@@ -181,13 +181,14 @@ public:
QPSQLDriver::Protocol getPSQLVersion();
bool setEncodingUtf8();
void setDatestyle();
+ void setByteaOutput();
void detectBackslashEscape();
};
void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type)
{
QString query;
- if (pro >= QPSQLDriver::Version73) {
+ if (pro >= QPSQLDriver::Version7_3) {
query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class "
"left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) "
"where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') "
@@ -525,7 +526,7 @@ int QPSQLResult::numRowsAffected()
QVariant QPSQLResult::lastInsertId() const
{
Q_D(const QPSQLResult);
- if (d->drv_d_func()->pro >= QPSQLDriver::Version81) {
+ if (d->drv_d_func()->pro >= QPSQLDriver::Version8_1) {
QSqlQuery qry(driver()->createResult());
// Most recent sequence value obtained from nextval
if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next())
@@ -698,11 +699,25 @@ void QPSQLDriverPrivate::setDatestyle()
PQclear(result);
}
+void QPSQLDriverPrivate::setByteaOutput()
+{
+ if (pro >= QPSQLDriver::Version9) {
+ // Server version before QPSQLDriver::Version9 only supports escape mode for bytea type,
+ // but bytea format is set to hex by default in PSQL 9 and above. So need to force the
+ // server to use the old escape mode when connects to the new server.
+ PGresult *result = exec("SET bytea_output TO escape");
+ int status = PQresultStatus(result);
+ if (status != PGRES_COMMAND_OK)
+ qWarning("%s", PQerrorMessage(connection));
+ PQclear(result);
+ }
+}
+
void QPSQLDriverPrivate::detectBackslashEscape()
{
// standard_conforming_strings option introduced in 8.2
// http://www.postgresql.org/docs/8.2/static/runtime-config-compatible.html
- if (pro < QPSQLDriver::Version82) {
+ if (pro < QPSQLDriver::Version8_2) {
hasBackslashEscape = true;
} else {
hasBackslashEscape = false;
@@ -724,11 +739,11 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin)
{
switch (vMin) {
case 1:
- return QPSQLDriver::Version71;
+ return QPSQLDriver::Version7_1;
case 3:
- return QPSQLDriver::Version73;
+ return QPSQLDriver::Version7_3;
case 4:
- return QPSQLDriver::Version74;
+ return QPSQLDriver::Version7_4;
default:
return QPSQLDriver::Version7;
}
@@ -738,76 +753,102 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin)
{
switch (vMin) {
case 1:
- return QPSQLDriver::Version81;
+ return QPSQLDriver::Version8_1;
case 2:
- return QPSQLDriver::Version82;
+ return QPSQLDriver::Version8_2;
case 3:
- return QPSQLDriver::Version83;
+ return QPSQLDriver::Version8_3;
case 4:
- return QPSQLDriver::Version84;
+ return QPSQLDriver::Version8_4;
default:
return QPSQLDriver::Version8;
}
break;
}
case 9:
- return QPSQLDriver::Version9;
+ {
+ switch (vMin) {
+ case 1:
+ return QPSQLDriver::Version9_1;
+ case 2:
+ return QPSQLDriver::Version9_2;
+ case 3:
+ return QPSQLDriver::Version9_3;
+ case 4:
+ return QPSQLDriver::Version9_4;
+ case 5:
+ return QPSQLDriver::Version9_5;
+ case 6:
+ return QPSQLDriver::Version9_6;
+ default:
+ return QPSQLDriver::Version9;
+ }
break;
+ }
+ case 10:
+ return QPSQLDriver::Version10;
default:
+ if (vMaj > 10)
+ return QPSQLDriver::UnknownLaterVersion;
break;
}
return QPSQLDriver::VersionUnknown;
}
+static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString)
+{
+ const QRegExp rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?"));
+ if (rx.indexIn(versionString) != -1) {
+ // Beginning with PostgreSQL version 10, a major release is indicated by
+ // increasing the first part of the version, e.g. 10 to 11.
+ // Before version 10, a major release was indicated by increasing either
+ // the first or second part of the version number, e.g. 9.5 to 9.6.
+ int vMaj = rx.cap(1).toInt();
+ int vMin;
+ if (vMaj >= 10) {
+ vMin = 0;
+ } else {
+ if (rx.cap(2).isEmpty())
+ return QPSQLDriver::VersionUnknown;
+ vMin = rx.cap(2).toInt();
+ }
+ return qMakePSQLVersion(vMaj, vMin);
+ }
+
+ return QPSQLDriver::VersionUnknown;
+}
+
QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
{
QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6;
PGresult* result = exec("select version()");
int status = PQresultStatus(result);
if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) {
- QString val = QString::fromLatin1(PQgetvalue(result, 0, 0));
-
- QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)"));
- rx.setMinimal(true); // enforce non-greedy RegExp
+ serverVersion = qFindPSQLVersion(
+ QString::fromLatin1(PQgetvalue(result, 0, 0)));
+ }
+ PQclear(result);
- if (rx.indexIn(val) != -1) {
- int vMaj = rx.cap(1).toInt();
- int vMin = rx.cap(2).toInt();
- serverVersion = qMakePSQLVersion(vMaj, vMin);
+ QPSQLDriver::Protocol clientVersion =
#if defined(PG_MAJORVERSION)
- if (rx.indexIn(QLatin1String(PG_MAJORVERSION)) != -1)
+ qFindPSQLVersion(QLatin1String(PG_MAJORVERSION));
#elif defined(PG_VERSION)
- if (rx.indexIn(QLatin1String(PG_VERSION)) != -1)
+ qFindPSQLVersion(QLatin1String(PG_VERSION));
#else
- if (0)
+ QPSQLDriver::VersionUnknown;
#endif
- {
- vMaj = rx.cap(1).toInt();
- vMin = rx.cap(2).toInt();
- QPSQLDriver::Protocol clientVersion = qMakePSQLVersion(vMaj, vMin);
-
- if (serverVersion >= QPSQLDriver::Version9 && clientVersion < QPSQLDriver::Version9) {
- //Client version before QPSQLDriver::Version9 only supports escape mode for bytea type,
- //but bytea format is set to hex by default in PSQL 9 and above. So need to force the
- //server use the old escape mode when connects to the new server with old client library.
- PQclear(result);
- result = exec("SET bytea_output=escape; ");
- status = PQresultStatus(result);
- } else if (serverVersion == QPSQLDriver::VersionUnknown) {
- serverVersion = clientVersion;
- if (serverVersion != QPSQLDriver::VersionUnknown)
- qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
- }
- }
- }
+
+ if (serverVersion == QPSQLDriver::VersionUnknown) {
+ serverVersion = clientVersion;
+ if (serverVersion != QPSQLDriver::VersionUnknown)
+ qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
}
- PQclear(result);
- //keep the old behavior unchanged
+ // Keep the old behavior unchanged
if (serverVersion == QPSQLDriver::VersionUnknown)
serverVersion = QPSQLDriver::Version6;
- if (serverVersion < QPSQLDriver::Version71) {
+ if (serverVersion < QPSQLDriver::Version7_3) {
qWarning("This version of PostgreSQL is not supported and may not work.");
}
@@ -857,7 +898,7 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
return true;
case PreparedQueries:
case PositionalPlaceholders:
- return d->pro >= QPSQLDriver::Version82;
+ return d->pro >= QPSQLDriver::Version8_2;
case BatchOperations:
case NamedPlaceholders:
case SimpleLocking:
@@ -866,7 +907,7 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
case CancelQuery:
return false;
case BLOB:
- return d->pro >= QPSQLDriver::Version71;
+ return d->pro >= QPSQLDriver::Version7_1;
case Unicode:
return d->isUtf8;
}
@@ -929,6 +970,7 @@ bool QPSQLDriver::open(const QString & db,
d->detectBackslashEscape();
d->isUtf8 = d->setEncodingUtf8();
d->setDatestyle();
+ d->setByteaOutput();
setOpen(true);
setOpenError(false);
@@ -993,12 +1035,7 @@ bool QPSQLDriver::commitTransaction()
// This hack is used to tell if the transaction has succeeded for the protocol versions of
// PostgreSQL below. For 7.x and other protocol versions we are left in the dark.
// This hack can dissapear once there is an API to query this sort of information.
- if (d->pro == QPSQLDriver::Version8 ||
- d->pro == QPSQLDriver::Version81 ||
- d->pro == QPSQLDriver::Version82 ||
- d->pro == QPSQLDriver::Version83 ||
- d->pro == QPSQLDriver::Version84 ||
- d->pro == QPSQLDriver::Version9) {
+ if (d->pro >= QPSQLDriver::Version8) {
transaction_failed = qstrcmp(PQcmdStatus(res), "ROLLBACK") == 0;
}
@@ -1085,8 +1122,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
else
schema = std::move(schema).toLower();
- switch(d->pro) {
- case QPSQLDriver::Version6:
+ if (d->pro == QPSQLDriver::Version6) {
stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname "
"from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
"where pg_cl.relname = '%1_pkey' "
@@ -1095,9 +1131,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
"and pg_att1.attrelid = pg_ind.indrelid "
"and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
"order by pg_att2.attnum");
- break;
- case QPSQLDriver::Version7:
- case QPSQLDriver::Version71:
+ } else if (d->pro == QPSQLDriver::Version7 || d->pro == QPSQLDriver::Version7_1) {
stmt = QLatin1String("select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname "
"from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
"where pg_cl.relname = '%1_pkey' "
@@ -1106,15 +1140,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
"and pg_att1.attrelid = pg_ind.indrelid "
"and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
"order by pg_att2.attnum");
- break;
- case QPSQLDriver::Version73:
- case QPSQLDriver::Version74:
- case QPSQLDriver::Version8:
- case QPSQLDriver::Version81:
- case QPSQLDriver::Version82:
- case QPSQLDriver::Version83:
- case QPSQLDriver::Version84:
- case QPSQLDriver::Version9:
+ } else if (d->pro >= QPSQLDriver::Version7_3) {
stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_class.relname "
"FROM pg_attribute, pg_class "
@@ -1129,10 +1155,8 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
else
stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
"pg_namespace where pg_namespace.nspname = '%1') AND ").arg(schema));
- break;
- case QPSQLDriver::VersionUnknown:
- qFatal("PSQL version is unknown");
- break;
+ } else {
+ qFatal("QPSQLDriver::primaryIndex(tablename): unknown PSQL version, query statement not set");
}
i.exec(stmt.arg(tbl));
@@ -1166,8 +1190,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
schema = std::move(schema).toLower();
QString stmt;
- switch(d->pro) {
- case QPSQLDriver::Version6:
+ if (d->pro == QPSQLDriver::Version6) {
stmt = QLatin1String("select pg_attribute.attname, int(pg_attribute.atttypid), "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"int(pg_attribute.attrelid), pg_attribute.attnum "
@@ -1175,8 +1198,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"where pg_class.relname = '%1' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid ");
- break;
- case QPSQLDriver::Version7:
+ } else if (d->pro == QPSQLDriver::Version7) {
stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attribute.attrelid::int, pg_attribute.attnum "
@@ -1184,8 +1206,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"where pg_class.relname = '%1' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid ");
- break;
- case QPSQLDriver::Version71:
+ } else if (d->pro == QPSQLDriver::Version7_1) {
stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attrdef.adsrc "
@@ -1196,15 +1217,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid "
"order by pg_attribute.attnum ");
- break;
- case QPSQLDriver::Version73:
- case QPSQLDriver::Version74:
- case QPSQLDriver::Version8:
- case QPSQLDriver::Version81:
- case QPSQLDriver::Version82:
- case QPSQLDriver::Version83:
- case QPSQLDriver::Version84:
- case QPSQLDriver::Version9:
+ } else if (d->pro >= QPSQLDriver::Version7_3) {
stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attrdef.adsrc "
@@ -1222,15 +1235,13 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
else
stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
"pg_namespace where pg_namespace.nspname = '%1')").arg(schema));
- break;
- case QPSQLDriver::VersionUnknown:
- qFatal("PSQL version is unknown");
- break;
+ } else {
+ qFatal("QPSQLDriver::record(tablename): unknown PSQL version, query statement not set");
}
QSqlQuery query(createResult());
query.exec(stmt.arg(tbl));
- if (d->pro >= QPSQLDriver::Version71) {
+ if (d->pro >= QPSQLDriver::Version7_1) {
while (query.next()) {
int len = query.value(3).toInt();
int precision = query.value(4).toInt();
diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h
index 3ff38f3c48..2873a9f851 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql_p.h
+++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h
@@ -76,15 +76,23 @@ public:
VersionUnknown = -1,
Version6 = 6,
Version7 = 7,
- Version71 = 8,
- Version73 = 9,
- Version74 = 10,
+ Version7_1 = 8,
+ Version7_3 = 9,
+ Version7_4 = 10,
Version8 = 11,
- Version81 = 12,
- Version82 = 13,
- Version83 = 14,
- Version84 = 15,
- Version9 = 16
+ Version8_1 = 12,
+ Version8_2 = 13,
+ Version8_3 = 14,
+ Version8_4 = 15,
+ Version9 = 16,
+ Version9_1 = 17,
+ Version9_2 = 18,
+ Version9_3 = 19,
+ Version9_4 = 20,
+ Version9_5 = 21,
+ Version9_6 = 22,
+ Version10 = 23,
+ UnknownLaterVersion = 100000
};
explicit QPSQLDriver(QObject *parent=0);
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index b24ecee102..c6ae7c1b79 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -311,6 +311,9 @@ static const QColor tabBarCloseButtonCrossSelected(115, 115, 115);
static const int closeButtonSize = 14;
static const qreal closeButtonCornerRadius = 2.0;
+static const int headerSectionArrowHeight = 6;
+static const int headerSectionSeparatorInset = 2;
+
#if QT_CONFIG(tabbar)
static bool isVerticalTabs(const QTabBar::Shape shape) {
return (shape == QTabBar::RoundedEast
@@ -569,7 +572,6 @@ static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
case QTabBar::TriangularSouth:
ttd = kThemeTabSouth;
break;
- default: // Added to remove the warning, since all values are taken care of, really!
case QTabBar::RoundedNorth:
case QTabBar::TriangularNorth:
ttd = kThemeTabNorth;
@@ -622,47 +624,6 @@ static QString qt_mac_removeMnemonics(const QString &original)
return returnText;
}
-OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inRect, void *inRefcon)
-{
- QRegion *region = static_cast<QRegion *>(inRefcon);
- if (!region)
- return paramErr;
-
- switch (inMessage) {
- case kHIShapeEnumerateRect:
- *region += QRect(inRect->origin.x, inRect->origin.y,
- inRect->size.width, inRect->size.height);
- break;
- case kHIShapeEnumerateInit:
- // Assume the region is already setup correctly
- case kHIShapeEnumerateTerminate:
- default:
- break;
- }
- return noErr;
-}
-
-/*!
- \internal
- Create's a mutable shape, it's the caller's responsibility to release.
- WARNING: this function clamps the coordinates to SHRT_MIN/MAX on 10.4 and below.
-*/
-HIMutableShapeRef qt_mac_toHIMutableShape(const QRegion &region)
-{
- HIMutableShapeRef shape = HIShapeCreateMutable();
- if (region.rectCount() < 2 ) {
- QRect qtRect = region.boundingRect();
- CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
- HIShapeUnionWithRect(shape, &cgRect);
- } else {
- for (const QRect &qtRect : region) {
- CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
- HIShapeUnionWithRect(shape, &cgRect);
- }
- }
- return shape;
-}
-
bool qt_macWindowIsTextured(const QWidget *window)
{
if (QWindow *w = window->windowHandle())
@@ -1518,18 +1479,6 @@ void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
}
}
-#if QT_CONFIG(pushbutton)
-bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option)
-{
- QMacStyle *macStyle = qobject_cast<QMacStyle *>(pushButton->style());
- if (!macStyle)
- return false;
- HIThemeButtonDrawInfo bdi;
- macStyle->d_func()->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi);
- return bdi.kind == kThemeBevelButton;
-}
-#endif
-
/**
Creates a HIThemeButtonDrawInfo structure that specifies the correct button
kind and other details to use for drawing the given combobox. Which button
@@ -1537,6 +1486,7 @@ bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOpti
explicit user style settings, etc.
*/
void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
+ CocoaControl *cw,
const QWidget *widget, const ThemeDrawState &tds) const
{
bdi->version = qt_mac_hitheme_version;
@@ -1550,6 +1500,8 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
bdi->state = tds;
QStyleHelper::WidgetSizePolicy aSize = aquaSizeConstrain(combo, widget);
+ cw->first = combo->editable ? ComboBox : Button_PopupButton;
+ cw->second = aSize;
switch (aSize) {
case QStyleHelper::SizeMini:
bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
@@ -1579,21 +1531,29 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
// them forever). So anyway, the height threshold should be smaller
// in this case, or the style gets confused when it needs to render
// or return any subcontrol size of the poor thing.
- if (h < 9)
+ if (h < 9) {
bdi->kind = kThemeComboBoxMini;
- else if (h < 22)
+ cw->second = QStyleHelper::SizeMini;
+ } else if (h < 22) {
bdi->kind = kThemeComboBoxSmall;
- else
+ cw->second = QStyleHelper::SizeSmall;
+ } else {
bdi->kind = kThemeComboBox;
+ cw->second = QStyleHelper::SizeLarge;
+ }
} else
#endif
{
- if (h < 21)
+ if (h < 21) {
bdi->kind = kThemeComboBoxMini;
- else if (h < 26)
+ cw->second = QStyleHelper::SizeMini;
+ } else if (h < 26) {
bdi->kind = kThemeComboBoxSmall;
- else
+ cw->second = QStyleHelper::SizeSmall;
+ } else {
bdi->kind = kThemeComboBox;
+ cw->second = QStyleHelper::SizeLarge;
+ }
}
} else {
// Even if we specify that we want the kThemePopupButton, Carbon
@@ -1601,12 +1561,16 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
// do the same size check explicit to have the size of the inner
// text field be correct. Therefore, do this even if the user specifies
// the use of LargeButtons explicit.
- if (h < 21)
+ if (h < 21) {
bdi->kind = kThemePopupButtonMini;
- else if (h < 26)
+ cw->second = QStyleHelper::SizeMini;
+ } else if (h < 26) {
bdi->kind = kThemePopupButtonSmall;
- else
+ cw->second = QStyleHelper::SizeSmall;
+ } else {
bdi->kind = kThemePopupButton;
+ cw->second = QStyleHelper::SizeLarge;
+ }
}
break;
}
@@ -1616,51 +1580,54 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
*/
-CGRect QMacStylePrivate::comboboxInnerBounds(const CGRect &outerBounds, int buttonKind)
+CGRect QMacStylePrivate::comboboxInnerBounds(const CGRect &outerBounds, const CocoaControl &cocoaWidget)
{
CGRect innerBounds = outerBounds;
// Carbon draw parts of the view outside the rect.
// So make the rect a bit smaller to compensate
// (I wish HIThemeGetButtonBackgroundBounds worked)
- switch (buttonKind){
- case kThemePopupButton:
- innerBounds.origin.x += 2;
- innerBounds.origin.y += 2;
- innerBounds.size.width -= 5;
- innerBounds.size.height -= 6;
- break;
- case kThemePopupButtonSmall:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 3;
- innerBounds.size.width -= 6;
- innerBounds.size.height -= 7;
- break;
- case kThemePopupButtonMini:
- innerBounds.origin.x += 2;
- innerBounds.origin.y += 2;
- innerBounds.size.width -= 5;
- innerBounds.size.height -= 6;
- break;
- case kThemeComboBox:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 2;
- innerBounds.size.width -= 6;
- innerBounds.size.height -= 8;
- break;
- case kThemeComboBoxSmall:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 3;
- innerBounds.size.width -= 7;
- innerBounds.size.height -= 8;
- break;
- case kThemeComboBoxMini:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 3;
- innerBounds.size.width -= 4;
- innerBounds.size.height -= 8;
- break;
- default:
- break;
+ if (cocoaWidget.first == Button_PopupButton) {
+ switch (cocoaWidget.second) {
+ case QStyleHelper::SizeSmall:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 6;
+ innerBounds.size.height -= 7;
+ break;
+ case QStyleHelper::SizeMini:
+ innerBounds.origin.x += 2;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 5;
+ innerBounds.size.height -= 6;
+ break;
+ case QStyleHelper::SizeLarge:
+ case QStyleHelper::SizeDefault:
+ innerBounds.origin.x += 2;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 5;
+ innerBounds.size.height -= 6;
+ }
+ } else if (cocoaWidget.first == ComboBox) {
+ switch (cocoaWidget.second) {
+ case QStyleHelper::SizeSmall:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 7;
+ innerBounds.size.height -= 8;
+ break;
+ case QStyleHelper::SizeMini:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 4;
+ innerBounds.size.height -= 8;
+ break;
+ case QStyleHelper::SizeLarge:
+ case QStyleHelper::SizeDefault:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 6;
+ innerBounds.size.height -= 8;
+ }
}
return innerBounds;
@@ -1704,11 +1671,11 @@ QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThe
create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
*/
-void QMacStylePrivate::drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
+void QMacStylePrivate::drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, const CocoaControl &cw, QPainter *p)
{
if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
// We have an unscaled combobox, or popup-button; use Carbon directly.
- const CGRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
+ const CGRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, cw);
HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
} else {
QPixmap buffer;
@@ -1751,69 +1718,6 @@ void QMacStylePrivate::drawCombobox(const CGRect &outerBounds, const HIThemeButt
}
}
-/**
- Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
- onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
-*/
-void QMacStylePrivate::drawTableHeader(const CGRect &outerBounds,
- bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
-{
- static int headerHeight = qt_mac_aqua_get_metric(ListHeaderHeight);
-
- QPixmap buffer;
- QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
- if (!QPixmapCache::find(key, buffer)) {
- CGRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
- buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
- buffer.fill(Qt::transparent);
- QPainter buffPainter(&buffer);
- HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
- buffPainter.end();
- QPixmapCache::insert(key, buffer);
- }
- const int buttonw = qRound(outerBounds.size.width);
- const int buttonh = qRound(outerBounds.size.height);
- const int framew = 1;
- const int frameh_n = 4;
- const int frameh_s = 3;
- const int transh = buffer.height() - frameh_n - frameh_s;
- int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
-
- int skipTopBorder = 0;
- if (!drawTopBorder)
- skipTopBorder = 1;
-
- p->translate(outerBounds.origin.x, outerBounds.origin.y);
-
- p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
- p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
- // Draw upper and lower center blocks
- p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
- p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
- // Draw right center block borders
- p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
- p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
- // Draw right corners
- p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
- p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
- // Draw center transition block
- p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), buttonw - framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(framew, frameh_n + 1, 1, transh));
- // Draw right center transition block border
- p->drawPixmap(QRect(buttonw - framew, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(buffer.width() - framew, frameh_n + 1, framew, transh));
- if (drawLeftBorder){
- // Draw left center block borders
- p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
- p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
- // Draw left corners
- p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
- p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
- // Draw left center transition block border
- p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
- }
-
- p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
-}
-
QMacStylePrivate::QMacStylePrivate()
: backingStoreNSView(nil)
{
@@ -1849,36 +1753,36 @@ ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
return tds;
}
-static QCocoaWidget cocoaWidgetFromHIThemeButtonKind(ThemeButtonKind kind)
+ QMacStylePrivate::CocoaControl QMacStylePrivate::cocoaControlFromHIThemeButtonKind(ThemeButtonKind kind)
{
- QCocoaWidget w;
+ CocoaControl w;
switch (kind) {
case kThemePopupButton:
case kThemePopupButtonSmall:
case kThemePopupButtonMini:
- w.first = QCocoaPopupButton;
+ w.first = Button_PopupButton;
break;
case kThemeComboBox:
- w.first = QCocoaComboBox;
+ w.first = ComboBox;
break;
case kThemeArrowButton:
- w.first = QCocoaDisclosureButton;
+ w.first = Button_Disclosure;
break;
case kThemeCheckBox:
case kThemeCheckBoxSmall:
case kThemeCheckBoxMini:
- w.first = QCocoaCheckBox;
+ w.first = Button_CheckBox;
break;
case kThemeRadioButton:
case kThemeRadioButtonSmall:
case kThemeRadioButtonMini:
- w.first = QCocoaRadioButton;
+ w.first = Button_RadioButton;
break;
case kThemePushButton:
case kThemePushButtonSmall:
case kThemePushButtonMini:
- w.first = QCocoaPushButton;
+ w.first = Button_PushButton;
break;
default:
break;
@@ -1914,13 +1818,13 @@ static NSButton *makeButton(NSButtonType type, NSBezelStyle style)
return b;
}
-NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
+NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
{
NSView *bv = cocoaControls.value(widget, nil);
if (!bv) {
switch (widget.first) {
- case QCocoaBox: {
+ case Box: {
NSBox *bc = [[NSBox alloc] init];
bc.title = @"";
bc.titlePosition = NSNoTitle;
@@ -1929,48 +1833,48 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
bv = bc;
break;
}
- case QCocoaCheckBox:
+ case Button_CheckBox:
bv = makeButton(NSSwitchButton, NSRegularSquareBezelStyle);
break;
- case QCocoaDisclosureButton:
+ case Button_Disclosure:
bv = makeButton(NSOnOffButton, NSDisclosureBezelStyle);
break;
- case QCocoaPopupButton:
- case QCocoaPullDownButton: {
+ case Button_PopupButton:
+ case Button_PullDown: {
NSPopUpButton *bc = [[NSPopUpButton alloc] init];
bc.title = @"";
- if (widget.first == QCocoaPullDownButton)
+ if (widget.first == Button_PullDown)
bc.pullsDown = YES;
bv = bc;
break;
}
- case QCocoaPushButton:
+ case Button_PushButton:
bv = makeButton(NSMomentaryLightButton, NSRoundedBezelStyle);
break;
- case QCocoaRadioButton:
+ case Button_RadioButton:
bv = makeButton(NSRadioButton, NSRegularSquareBezelStyle);
break;
- case QCocoaComboBox:
+ case ComboBox:
bv = [[NSComboBox alloc] init];
break;
- case QCocoaProgressIndicator:
+ case ProgressIndicator_Determinate:
bv = [[NSProgressIndicator alloc] init];
break;
- case QCocoaIndeterminateProgressIndicator:
+ case ProgressIndicator_Indeterminate:
bv = [[QIndeterminateProgressIndicator alloc] init];
break;
- case QCocoaHorizontalScroller:
+ case Scroller_Horizontal:
bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
break;
- case QCocoaVerticalScroller:
+ case Scroller_Vertical:
// Cocoa sets the orientation from the view's frame
// at construction time, and it cannot be changed later.
bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
break;
- case QCocoaHorizontalSlider:
+ case Slider_Horizontal:
bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
break;
- case QCocoaVerticalSlider:
+ case Slider_Vertical:
// Cocoa sets the orientation from the view's frame
// at construction time, and it cannot be changed later.
bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
@@ -1991,10 +1895,10 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
default:
break;
}
- } else if (widget.first == QCocoaProgressIndicator ||
- widget.first == QCocoaIndeterminateProgressIndicator) {
+ } else if (widget.first == ProgressIndicator_Determinate ||
+ widget.first == ProgressIndicator_Indeterminate) {
auto *pi = static_cast<NSProgressIndicator *>(bv);
- pi.indeterminate = (widget.first == QCocoaIndeterminateProgressIndicator);
+ pi.indeterminate = (widget.first == ProgressIndicator_Indeterminate);
switch (widget.second) {
case QStyleHelper::SizeSmall:
pi.controlSize = NSSmallControlSize;
@@ -2013,15 +1917,15 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
return bv;
}
-NSCell *QMacStylePrivate::cocoaCell(QCocoaWidget widget) const
+NSCell *QMacStylePrivate::cocoaCell(CocoaControl widget) const
{
NSCell *cell = cocoaCells[widget];
if (!cell) {
switch (widget.first) {
- case QCocoaStepper:
+ case Stepper:
cell = [[NSStepperCell alloc] init];
break;
- case QCocoaDisclosureButton: {
+ case Button_Disclosure: {
NSButtonCell *bc = [[NSButtonCell alloc] init];
bc.buttonType = NSOnOffButton;
bc.bezelStyle = NSDisclosureBezelStyle;
@@ -2049,31 +1953,31 @@ NSCell *QMacStylePrivate::cocoaCell(QCocoaWidget widget) const
return cell;
}
-void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, QCocoaDrawRectBlock drawRectBlock) const
+void QMacStylePrivate::drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, DrawRectBlock drawRectBlock) const
{
QPoint offset;
- if (widget == QCocoaWidget(QCocoaRadioButton, QStyleHelper::SizeLarge))
+ if (widget == CocoaControl(Button_RadioButton, QStyleHelper::SizeLarge))
offset.setY(2);
- else if (widget == QCocoaWidget(QCocoaRadioButton, QStyleHelper::SizeSmall))
+ else if (widget == CocoaControl(Button_RadioButton, QStyleHelper::SizeSmall))
offset = QPoint(-1, 2);
- else if (widget == QCocoaWidget(QCocoaRadioButton, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_RadioButton, QStyleHelper::SizeMini))
offset.setY(2);
- else if (widget == QCocoaWidget(QCocoaPopupButton, QStyleHelper::SizeSmall)
- || widget == QCocoaWidget(QCocoaCheckBox, QStyleHelper::SizeLarge))
+ else if (widget == CocoaControl(Button_PopupButton, QStyleHelper::SizeSmall)
+ || widget == CocoaControl(Button_CheckBox, QStyleHelper::SizeLarge))
offset.setY(1);
- else if (widget == QCocoaWidget(QCocoaCheckBox, QStyleHelper::SizeSmall))
+ else if (widget == CocoaControl(Button_CheckBox, QStyleHelper::SizeSmall))
offset.setX(-1);
- else if (widget == QCocoaWidget(QCocoaCheckBox, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_CheckBox, QStyleHelper::SizeMini))
offset = QPoint(7, 5);
- else if (widget == QCocoaWidget(QCocoaPopupButton, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_PopupButton, QStyleHelper::SizeMini))
offset = QPoint(2, -1);
- else if (widget == QCocoaWidget(QCocoaPullDownButton, QStyleHelper::SizeLarge))
+ else if (widget == CocoaControl(Button_PullDown, QStyleHelper::SizeLarge))
offset = isQWidget ? QPoint(3, -1) : QPoint(-1, -3);
- else if (widget == QCocoaWidget(QCocoaPullDownButton, QStyleHelper::SizeSmall))
+ else if (widget == CocoaControl(Button_PullDown, QStyleHelper::SizeSmall))
offset = QPoint(2, 1);
- else if (widget == QCocoaWidget(QCocoaPullDownButton, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_PullDown, QStyleHelper::SizeMini))
offset = QPoint(5, 0);
- else if (widget == QCocoaWidget(QCocoaComboBox, QStyleHelper::SizeLarge))
+ else if (widget == CocoaControl(ComboBox, QStyleHelper::SizeLarge))
offset = QPoint(3, 0);
QMacCGContext ctx(p);
@@ -2094,12 +1998,12 @@ void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const
restoreNSGraphicsContext(ctx);
}
-void QMacStylePrivate::resolveCurrentNSView(QWindow *window)
+void QMacStylePrivate::resolveCurrentNSView(QWindow *window) const
{
backingStoreNSView = window ? (NSView *)window->winId() : nil;
}
-void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonDrawInfo *bdi,
+void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonDrawInfo *bdi, const CocoaControl &cw,
QPainter *p, const QStyleOption *opt) const
{
int xoff = 0,
@@ -2147,7 +2051,7 @@ void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonD
// Carbon combos don't scale. Therefore we draw it
// ourselves, if a scaled version is needed.
QPainter tmpPainter(&activePixmap);
- QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
+ QMacStylePrivate::drawCombobox(macRect, *bdi, cw, &tmpPainter);
} else {
QMacCGContext cg(&activePixmap);
CGRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
@@ -2162,7 +2066,7 @@ void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonD
if (!combo && !button && bdi->value == kThemeButtonOff) {
pm = activePixmap;
} else if ((combo && !editableCombo) || button) {
- QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi->kind);
+ CocoaControl cw = cocoaControlFromHIThemeButtonKind(bdi->kind);
NSButton *bc = (NSButton *)cocoaControl(cw);
[bc highlight:pressed];
bc.enabled = bdi->state != kThemeStateUnavailable && bdi->state != kThemeStateUnavailableInactive;
@@ -3131,7 +3035,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
- const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ d->resolveCurrentNSView(window);
switch (pe) {
case PE_IndicatorArrowUp:
case PE_IndicatorArrowDown:
@@ -3139,7 +3043,17 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
case PE_IndicatorArrowLeft: {
p->save();
p->setRenderHint(QPainter::Antialiasing);
- int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1;
+ const int xOffset = 1; // FIXME: opt->direction == Qt::LeftToRight ? 2 : -1;
+ qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
+ const qreal penWidth = qMax(halfSize / 3.0, 1.25);
+#if QT_CONFIG(toolbutton)
+ if (const QToolButton *tb = qobject_cast<const QToolButton *>(w)) {
+ // When stroking the arrow, make sure it fits in the tool button
+ if (tb->arrowType() != Qt::NoArrow)
+ halfSize -= penWidth;
+ }
+#endif
+
QMatrix matrix;
matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
QPainterPath path;
@@ -3157,13 +3071,15 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
matrix.rotate(-90);
break;
}
- path.moveTo(0, 5);
- path.lineTo(-4, -3);
- path.lineTo(4, -3);
p->setMatrix(matrix);
- p->setPen(Qt::NoPen);
- p->setBrush(QColor(0, 0, 0, 135));
- p->drawPath(path);
+
+ path.moveTo(-halfSize, -halfSize * 0.5);
+ path.lineTo(0.0, halfSize * 0.5);
+ path.lineTo(halfSize, -halfSize * 0.5);
+
+ const QPen arrowPen(opt->palette.text(), penWidth,
+ Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+ p->strokePath(path, arrowPen);
p->restore();
break; }
#if QT_CONFIG(tabbar)
@@ -3211,7 +3127,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
if (groupBox->features & QStyleOptionFrame::Flat) {
QCommonStyle::drawPrimitive(pe, groupBox, p, w);
} else {
- const auto cw = QCocoaWidget(QCocoaBox, QStyleHelper::SizeDefault);
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeDefault);
auto *box = static_cast<NSBox *>(d->cocoaControl(cw));
d->drawNSViewInRect(cw, box, groupBox->rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) {
CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
@@ -3386,10 +3302,11 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
else
bdi.value = kThemeButtonOff;
CGRect macRect = opt->rect.toCGRect();
+ const QMacStylePrivate::CocoaControl cw = QMacStylePrivate::cocoaControlFromHIThemeButtonKind(bdi.kind);
if (!drawColorless)
HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0);
else
- d->drawColorlessButton(macRect, &bdi, p, opt);
+ d->drawColorlessButton(macRect, &bdi, cw, p, opt);
break; }
case PE_FrameFocusRect:
// Use the our own focus widget stuff.
@@ -3397,7 +3314,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
case PE_IndicatorBranch: {
if (!(opt->state & State_Children))
break;
- NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(QCocoaWidget(QCocoaDisclosureButton, QStyleHelper::SizeLarge)));
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
+ NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(cw));
[triangleCell setState:(opt->state & State_Open) ? NSOnState : NSOffState];
bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
[triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleDark : NSBackgroundStyleLight];
@@ -3627,70 +3545,15 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
- const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ d->resolveCurrentNSView(window);
switch (ce) {
case CE_HeaderSection:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
- HIThemeButtonDrawInfo bdi;
- bdi.version = qt_mac_hitheme_version;
State flags = header->state;
QRect ir = header->rect;
- bdi.kind = kThemeListHeaderButton;
- bdi.adornment = kThemeAdornmentNone;
- bdi.state = kThemeStateActive;
- if (flags & State_On)
- bdi.value = kThemeButtonOn;
- else
- bdi.value = kThemeButtonOff;
-
- if (header->orientation == Qt::Horizontal){
- switch (header->position) {
- case QStyleOptionHeader::Beginning:
- ir.adjust(-1, -1, 0, 0);
- break;
- case QStyleOptionHeader::Middle:
- ir.adjust(-1, -1, 0, 0);
- break;
- case QStyleOptionHeader::OnlyOneSection:
- case QStyleOptionHeader::End:
- ir.adjust(-1, -1, 1, 0);
- break;
- default:
- break;
- }
-
- if (header->position != QStyleOptionHeader::Beginning
- && header->position != QStyleOptionHeader::OnlyOneSection) {
- bdi.adornment = header->direction == Qt::LeftToRight
- ? kThemeAdornmentHeaderButtonLeftNeighborSelected
- : kThemeAdornmentHeaderButtonRightNeighborSelected;
- }
- }
-
- if (flags & State_Active) {
- if (!(flags & State_Enabled))
- bdi.state = kThemeStateUnavailable;
- else if (flags & State_Sunken)
- bdi.state = kThemeStatePressed;
- } else {
- if (flags & State_Enabled)
- bdi.state = kThemeStateInactive;
- else
- bdi.state = kThemeStateUnavailableInactive;
- }
-
- if (header->sortIndicator != QStyleOptionHeader::None) {
- bdi.value = kThemeButtonOn;
- if (header->sortIndicator == QStyleOptionHeader::SortDown)
- bdi.adornment = kThemeAdornmentHeaderButtonSortUp;
- }
- if (flags & State_HasFocus)
- bdi.adornment = kThemeAdornmentFocus;
-
- ir = visualRect(header->direction, header->rect, ir);
- CGRect bounds = ir.toCGRect();
+#if 0 // FIXME: What's this solving exactly?
bool noVerticalHeader = true;
#if QT_CONFIG(tableview)
if (w)
@@ -3698,12 +3561,22 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
noVerticalHeader = !table->verticalHeader()->isVisible();
#endif
- bool drawTopBorder = header->orientation == Qt::Horizontal;
- bool drawLeftBorder = header->orientation == Qt::Vertical
- || header->position == QStyleOptionHeader::OnlyOneSection
- || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
- d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p);
+ const bool drawLeftBorder = header->orientation == Qt::Vertical
+ || header->position == QStyleOptionHeader::OnlyOneSection
+ || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
+#endif
+
+ const bool pressed = (flags & State_Sunken) && !(flags & State_On);
+ p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
+ p->setPen(QPen(header->palette.dark(), 1.0));
+ if (header->orientation == Qt::Horizontal)
+ p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
+ ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
+ else
+ p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
+ ir.right() - headerSectionSeparatorInset, ir.bottom()));
}
+
break;
case CE_HeaderLabel:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
@@ -3820,12 +3693,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
} else {
QCommonStyle::drawControl(ce, &myTb, p, w);
}
- } else {
+ } else
+#endif // QT_NO_ACCESSIBILITY
+ {
QCommonStyle::drawControl(ce, &myTb, p, w);
}
-#else
- Q_UNUSED(tb)
-#endif
}
break;
case CE_ToolBoxTabShape:
@@ -3883,9 +3755,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
newRect.size.width -= QMacStylePrivate::PushButtonRightOffset - 4;
}
+ QMacStylePrivate::CocoaControl cw = QMacStylePrivate::cocoaControlFromHIThemeButtonKind(bdi.kind);
+ if (hasMenu)
+ cw.first = QMacStylePrivate::Button_PullDown;
if (hasMenu && bdi.kind != kThemeBevelButton) {
- QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind);
- cw.first = QCocoaPullDownButton;
NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(cw);
[pdb highlight:(bdi.state == kThemeStatePressed)];
pdb.enabled = bdi.state != kThemeStateUnavailable && bdi.state != kThemeStateUnavailableInactive;
@@ -3893,7 +3766,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
rect.adjust(0, 0, cw.second == QStyleHelper::SizeSmall ? -4 : cw.second == QStyleHelper::SizeMini ? -9 : -6, 0);
d->drawNSViewInRect(cw, pdb, rect, p, w != 0);
} else if (hasMenu && bdi.state == kThemeStatePressed)
- d->drawColorlessButton(newRect, &bdi, p, opt);
+ d->drawColorlessButton(newRect, &bdi, cw, p, opt);
else
HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
@@ -4451,7 +4324,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
QIndeterminateProgressIndicator *ipi = nil;
if (isIndeterminate || animation)
- ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QCocoaIndeterminateProgressIndicator, aquaSize }));
+ ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
if (isIndeterminate) {
// QIndeterminateProgressIndicator derives from NSProgressIndicator. We use a single
// instance that we start animating as soon as one of the progress bars is indeterminate.
@@ -4478,7 +4351,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
[ipi stopAnimation];
}
- const QCocoaWidget cw = { QCocoaProgressIndicator, aquaSize };
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
d->drawNSViewInRect(cw, pi, rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) {
d->setupVerticalInvertedXform(ctx, reverse, vertical, rect);
@@ -4691,14 +4564,31 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
// Subtract width needed for arrow, if there is one
if (header->sortIndicator != QStyleOptionHeader::None) {
if (opt->state & State_Horizontal)
- rect.setWidth(rect.width() - (opt->rect.height() / 2) - (margin * 2));
+ rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
else
- rect.setHeight(rect.height() - (opt->rect.width() / 2) - (margin * 2));
+ rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
}
}
rect = visualRect(opt->direction, opt->rect, rect);
break;
}
+ case SE_HeaderArrow: {
+ int h = opt->rect.height();
+ int w = opt->rect.width();
+ int x = opt->rect.x();
+ int y = opt->rect.y();
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
+
+ if (opt->state & State_Horizontal) {
+ rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
+ headerSectionArrowHeight, h - margin * 2 - 5);
+ } else {
+ rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
+ w - margin * 2 - 5, headerSectionArrowHeight);
+ }
+ rect = visualRect(opt->direction, opt->rect, rect);
+ break;
+ }
case SE_ProgressBarGroove:
// Wrong in the secondary dimension, but accurate enough in the main dimension.
rect = opt->rect;
@@ -5159,7 +5049,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
QMacCGContext cg(p);
QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
- const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ d->resolveCurrentNSView(window);
switch (cc) {
case CC_ScrollBar:
if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
@@ -5265,7 +5155,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
d->setupNSGraphicsContext(cg, NO /* flipped */);
- const QCocoaWidget cw(isHorizontal ? QCocoaHorizontalScroller : QCocoaVerticalScroller, cocoaSize);
+ const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
NSScroller *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
if (isTransient) {
@@ -5347,8 +5238,9 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
case CC_Slider:
if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider, cs);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
if (!setupSlider(slider, sl))
break;
@@ -5483,7 +5375,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
d->setupNSGraphicsContext(cg, NO);
const auto aquaSize = d->effectiveAquaSizeConstrain(opt, widget);
- NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(QCocoaWidget(QCocoaStepper, aquaSize)));
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
+ NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
cell.enabled = (sb->state & State_Enabled);
const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
@@ -5511,19 +5404,20 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
case CC_ComboBox:
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
HIThemeButtonDrawInfo bdi;
- d->initComboboxBdi(combo, &bdi, widget, tds);
+ QMacStylePrivate::CocoaControl cw;
+ d->initComboboxBdi(combo, &bdi, &cw, widget, tds);
CGRect rect = combo->rect.toCGRect();
if (combo->editable)
rect.origin.y += tds == kThemeStateInactive ? 1 : 2;
if (tds != kThemeStateInactive)
- QMacStylePrivate::drawCombobox(rect, bdi, p);
+ QMacStylePrivate::drawCombobox(rect, bdi, cw, p);
else if (!widget && combo->editable) {
- QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind);
+ const auto cw = QMacStylePrivate::cocoaControlFromHIThemeButtonKind(bdi.kind);
NSView *cb = d->cocoaControl(cw);
QRect r = combo->rect.adjusted(3, 0, 0, 0);
d->drawNSViewInRect(cw, cb, r, p, widget != 0);
} else
- d->drawColorlessButton(rect, &bdi, p, opt);
+ d->drawColorlessButton(rect, &bdi, cw, p, opt);
}
break;
case CC_TitleBar:
@@ -5703,7 +5597,9 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
p->fillPath(path, brush);
}
proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
- } else {
+ } else
+#endif // QT_NO_ACCESSIBILITY
+ {
ThemeButtonKind bkind = kThemeBevelButton;
switch (d->aquaSizeConstrain(opt, widget)) {
case QStyleHelper::SizeDefault:
@@ -5786,7 +5682,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
}
-#endif
}
break;
#if QT_CONFIG(dial)
@@ -5822,8 +5717,9 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider, cs);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
if (!setupSlider(slider, sl))
break;
@@ -5848,9 +5744,10 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
break;
}
- const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
const bool isHorizontal = sb->orientation == Qt::Horizontal;
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalScroller : QCocoaVerticalScroller, controlSize);
+ const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
if (!setupScroller(scroller, sb)) {
sc = SC_None;
@@ -5956,8 +5853,9 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
// And nothing else since 10.7
if (part != NSScrollerNoPart) {
- const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalScroller : QCocoaVerticalScroller, controlSize);
+ const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
if (setupScroller(scroller, sb))
ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
@@ -5968,8 +5866,9 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider, cs);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
if (!setupSlider(slider, sl))
break;
@@ -6063,7 +5962,8 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
case CC_ComboBox:
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
HIThemeButtonDrawInfo bdi;
- d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
+ QMacStylePrivate::CocoaControl cw;
+ d->initComboboxBdi(combo, &bdi, &cw, widget, d->getDrawState(opt->state));
switch (sc) {
case SC_ComboBoxEditField:{
@@ -6078,7 +5978,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
break; }
case SC_ComboBoxListBoxPopup:{
if (combo->editable) {
- const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), bdi.kind);
+ const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
const int comboTop = combo->rect.top();
ret = QRect(qRound(inner.origin.x),
@@ -6230,7 +6130,8 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
Q_UNREACHABLE();
}
- NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(QCocoaWidget(QCocoaStepper, aquaSize)));
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
+ NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
ret = QRectF::fromCGRect(outRect).toRect();
@@ -6554,20 +6455,10 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
// We compensate for this by adding some extra space here to make room for the frame when drawing:
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
const auto widgetSize = d->aquaSizeConstrain(opt, widget);
- int bkind = 0;
- switch (widgetSize) {
- default:
- case QStyleHelper::SizeLarge:
- bkind = combo->editable ? kThemeComboBox : kThemePopupButton;
- break;
- case QStyleHelper::SizeSmall:
- bkind = combo->editable ? int(kThemeComboBoxSmall) : int(kThemePopupButtonSmall);
- break;
- case QStyleHelper::SizeMini:
- bkind = combo->editable ? kThemeComboBoxMini : kThemePopupButtonMini;
- break;
- }
- const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, bkind);
+ QMacStylePrivate::CocoaControl cw;
+ cw.first = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
+ cw.second = widgetSize;
+ const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
sz.rwidth() -= qRound(diffRect.size.width);
sz.rheight() -= qRound(diffRect.size.height);
} else if (ct == CT_PushButton || ct == CT_ToolButton){
@@ -6808,16 +6699,4 @@ int QMacStyle::layoutSpacing(QSizePolicy::ControlType control1,
return_SIZE(10, 8, 6); // guess
}
-/*
-FontHash::FontHash()
-{
- QHash<QByteArray, QFont>::operator=(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFonts());
-}
-
-Q_GLOBAL_STATIC(FontHash, app_fonts)
-FontHash *qt_app_fonts_hash()
-{
- return app_fonts();
-}
-*/
QT_END_NAMESPACE
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p.h b/src/plugins/styles/mac/qmacstyle_mac_p.h
index 6011baeea2..d6874001d3 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p.h
@@ -117,10 +117,6 @@ public:
private:
Q_DISABLE_COPY(QMacStyle)
Q_DECLARE_PRIVATE(QMacStyle)
-
-#if QT_CONFIG(pushbutton)
- friend bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option);
-#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
index 528edfcda1..078509d551 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
@@ -167,28 +167,6 @@ QT_BEGIN_NAMESPACE
#define CT1(c) CT2(c, c)
#define CT2(c1, c2) ((uint(c1) << 16) | uint(c2))
-enum QCocoaWidgetKind {
- QCocoaBox, // QGroupBox
- QCocoaCheckBox,
- QCocoaComboBox, // Editable QComboBox
- QCocoaDisclosureButton, // Disclosure triangle, like in QTreeView
- QCocoaPopupButton, // Non-editable QComboBox
- QCocoaProgressIndicator,
- QCocoaIndeterminateProgressIndicator,
- QCocoaPullDownButton, // QPushButton with menu
- QCocoaPushButton,
- QCocoaRadioButton,
- QCocoaHorizontalScroller,
- QCocoaVerticalScroller,
- QCocoaHorizontalSlider,
- QCocoaVerticalSlider,
- QCocoaStepper // QSpinBox buttons
-};
-
-typedef QPair<QCocoaWidgetKind, QStyleHelper::WidgetSizePolicy> QCocoaWidget;
-
-typedef void (^QCocoaDrawRectBlock)(CGContextRef, const CGRect &);
-
#define SIZE(large, small, mini) \
(controlSize == QStyleHelper::SizeLarge ? (large) : controlSize == QStyleHelper::SizeSmall ? (small) : (mini))
@@ -199,14 +177,32 @@ typedef void (^QCocoaDrawRectBlock)(CGContextRef, const CGRect &);
return sizes[controlSize]; \
} while (false)
-#if QT_CONFIG(pushbutton)
-bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option);
-#endif
-
class QMacStylePrivate : public QCommonStylePrivate
{
Q_DECLARE_PUBLIC(QMacStyle)
public:
+ enum CocoaControlType {
+ Box, // QGroupBox
+ Button_CheckBox,
+ Button_Disclosure, // Disclosure triangle, like in QTreeView
+ Button_PopupButton, // Non-editable QComboBox
+ Button_PullDown, // QPushButton with menu
+ Button_PushButton,
+ Button_RadioButton,
+ ComboBox, // Editable QComboBox
+ ProgressIndicator_Determinate,
+ ProgressIndicator_Indeterminate,
+ Scroller_Horizontal,
+ Scroller_Vertical,
+ Slider_Horizontal,
+ Slider_Vertical,
+ Stepper // QSpinBox buttons
+ };
+
+ typedef QPair<CocoaControlType, QStyleHelper::WidgetSizePolicy> CocoaControl;
+
+ typedef void (^DrawRectBlock)(CGContextRef, const CGRect &);
+
QMacStylePrivate();
~QMacStylePrivate();
@@ -235,6 +231,7 @@ public:
// Utility functions
void drawColorlessButton(const CGRect &macRect, HIThemeButtonDrawInfo *bdi,
+ const CocoaControl &cw,
QPainter *p, const QStyleOption *opt) const;
QSize pushButtonSizeFromContents(const QStyleOptionButton *btn) const;
@@ -243,15 +240,14 @@ public:
const HIThemeButtonDrawInfo *bdi) const;
void initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
+ CocoaControl *cw,
const QWidget *widget, const ThemeDrawState &tds) const;
- static CGRect comboboxInnerBounds(const CGRect &outerBounds, int buttonKind);
+ static CGRect comboboxInnerBounds(const CGRect &outerBounds, const CocoaControl &cocoaWidget);
static QRect comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi);
- static void drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p);
- static void drawTableHeader(const CGRect &outerBounds, bool drawTopBorder, bool drawLeftBorder,
- const HIThemeButtonDrawInfo &bdi, QPainter *p);
+ static void drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, const CocoaControl &cw, QPainter *p);
bool contentFitsInPushButton(const QStyleOptionButton *btn, HIThemeButtonDrawInfo *bdi,
ThemeButtonKind buttonKindToCheck) const;
void initHIThemePushButton(const QStyleOptionButton *btn, const QWidget *widget,
@@ -260,16 +256,18 @@ public:
void setAutoDefaultButton(QObject *button) const;
- NSView *cocoaControl(QCocoaWidget widget) const;
- NSCell *cocoaCell(QCocoaWidget widget) const;
+ NSView *cocoaControl(CocoaControl widget) const;
+ NSCell *cocoaCell(CocoaControl widget) const;
+
+ static CocoaControl cocoaControlFromHIThemeButtonKind(ThemeButtonKind kind);
void setupNSGraphicsContext(CGContextRef cg, bool flipped) const;
void restoreNSGraphicsContext(CGContextRef cg) const;
void setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const;
- void drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, QCocoaDrawRectBlock drawRectBlock = nil) const;
- void resolveCurrentNSView(QWindow *window);
+ void drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, DrawRectBlock drawRectBlock = nil) const;
+ void resolveCurrentNSView(QWindow *window) const;
void drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, qreal radius = 0) const;
@@ -283,9 +281,9 @@ public:
mutable QPointer<QFocusFrame> focusWidget;
QT_MANGLE_NAMESPACE(NotificationReceiver) *receiver;
- NSView *backingStoreNSView;
- mutable QHash<QCocoaWidget, NSView *> cocoaControls;
- mutable QHash<QCocoaWidget, NSCell *> cocoaCells;
+ mutable NSView *backingStoreNSView;
+ mutable QHash<CocoaControl, NSView *> cocoaControls;
+ mutable QHash<CocoaControl, NSCell *> cocoaCells;
QFont smallSystemFont;
QFont miniSystemFont;
diff --git a/src/testlib/qtest_gui.h b/src/testlib/qtest_gui.h
index f56aa60949..fc3e5d3fe2 100644
--- a/src/testlib/qtest_gui.h
+++ b/src/testlib/qtest_gui.h
@@ -83,7 +83,7 @@ namespace QTest
*/
template<> inline char *toString(const QColor &color)
{
- return qstrdup(color.name().toLocal8Bit().constData());
+ return qstrdup(color.name(QColor::HexArgb).toLocal8Bit().constData());
}
template<> inline char *toString(const QRegion &region)
diff --git a/src/testlib/qtesthelpers_p.h b/src/testlib/qtesthelpers_p.h
new file mode 100644
index 0000000000..0e39f7aea2
--- /dev/null
+++ b/src/testlib/qtesthelpers_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTHELPERS_P_H
+#define QTESTHELPERS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QFile>
+#include <QtCore/QString>
+#include <QtCore/QChar>
+#include <QtCore/QPoint>
+
+#ifdef QT_GUI_LIB
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+#endif
+
+#ifdef QT_WIDGETS_LIB
+#include <QtWidgets/QWidget>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QTestPrivate {
+
+static inline bool canHandleUnicodeFileNames()
+{
+#if defined(Q_OS_WIN)
+ return true;
+#else
+ // Check for UTF-8 by converting the Euro symbol (see tst_utf8)
+ return QFile::encodeName(QString(QChar(0x20AC))) == QByteArrayLiteral("\342\202\254");
+#endif
+}
+
+#ifdef QT_WIDGETS_LIB
+static inline void centerOnScreen(QWidget *w, const QSize &size)
+{
+ const QPoint offset = QPoint(size.width() / 2, size.height() / 2);
+ w->move(QGuiApplication::primaryScreen()->availableGeometry().center() - offset);
+}
+
+static inline void centerOnScreen(QWidget *w)
+{
+ centerOnScreen(w, w->geometry().size());
+}
+
+/*! \internal
+
+ Make a widget frameless to prevent size constraints of title bars from interfering (Windows).
+*/
+static inline void setFrameless(QWidget *w)
+{
+ Qt::WindowFlags flags = w->windowFlags();
+ flags |= Qt::FramelessWindowHint;
+ flags &= ~(Qt::WindowTitleHint | Qt::WindowSystemMenuHint
+ | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
+ w->setWindowFlags(flags);
+}
+#endif // QT_WIDGETS_LIB
+
+} // namespace QTestPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTESTHELPERS_P_H
diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro
index e11e25e1da..f99f28ca84 100644
--- a/src/testlib/testlib.pro
+++ b/src/testlib/testlib.pro
@@ -37,7 +37,8 @@ HEADERS = qbenchmark.h \
qtestspontaneevent.h \
qtestsystem.h \
qtesttouch.h \
- qtestblacklist_p.h
+ qtestblacklist_p.h \
+ qtesthelpers_p.h
SOURCES = qtestcase.cpp \
qtestlog.cpp \
diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp
index 18945f1ce5..075285e4ea 100644
--- a/src/tools/moc/main.cpp
+++ b/src/tools/moc/main.cpp
@@ -267,6 +267,7 @@ int runMoc(int argc, char **argv)
QCommandLineOption prependIncludeOption(QStringLiteral("b"));
prependIncludeOption.setDescription(QStringLiteral("Prepend #include <file> (preserve default include)."));
prependIncludeOption.setValueName(QStringLiteral("file"));
+ prependIncludeOption.setFlags(QCommandLineOption::ShortOptionStyle);
parser.addOption(prependIncludeOption);
QCommandLineOption includeOption(QStringLiteral("include"));
diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp
index 9a06fb38d0..a6725af924 100644
--- a/src/tools/moc/preprocessor.cpp
+++ b/src/tools/moc/preprocessor.cpp
@@ -992,7 +992,7 @@ static void mergeStringLiterals(Symbols *_symbols)
mergeSymbolLexem.reserve(literalsLength);
mergeSymbolLexem.append('"');
mergeSymbolLexem.append(mergeSymbolOriginalLexem);
- for (Symbols::const_iterator j = mergeSymbol + 1; j != i; ++j)
+ for (Symbols::iterator j = mergeSymbol + 1; j != i; ++j)
mergeSymbolLexem.append(j->lex.constData() + j->from + 1, j->len - 2); // append j->unquotedLexem()
mergeSymbolLexem.append('"');
mergeSymbol->len = mergeSymbol->lex.length();
diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp
index 2fd664e13a..f821c2f001 100644
--- a/src/widgets/accessible/simplewidgets.cpp
+++ b/src/widgets/accessible/simplewidgets.cpp
@@ -953,7 +953,7 @@ QAccessibleWindowContainer::QAccessibleWindowContainer(QWidget *w)
int QAccessibleWindowContainer::childCount() const
{
- if (container()->containedWindow())
+ if (container()->containedWindow() && QAccessible::queryAccessibleInterface(container()->containedWindow()))
return 1;
return 0;
}
diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp
index 900a4c1899..3876cf16c6 100644
--- a/src/widgets/dialogs/qwizard.cpp
+++ b/src/widgets/dialogs/qwizard.cpp
@@ -1462,8 +1462,8 @@ void QWizardPrivate::updateButtonTexts()
// even in RTL mode, so do the same, even if it might be counter-intuitive.
// The shortcut for 'back' is set in class QVistaBackButton.
#if QT_CONFIG(shortcut)
- if (btns[QWizard::NextButton])
- btns[QWizard::NextButton]->setShortcut(isVistaThemeEnabled() ? QKeySequence(Qt::ALT | Qt::Key_Right) : QKeySequence());
+ if (btns[QWizard::NextButton] && isVistaThemeEnabled())
+ btns[QWizard::NextButton]->setShortcut(QKeySequence(Qt::ALT | Qt::Key_Right));
#endif
}
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index d6db7deee7..463ed7e58c 100644
--- a/src/widgets/itemviews/qheaderview.cpp
+++ b/src/widgets/itemviews/qheaderview.cpp
@@ -3376,7 +3376,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool
// because it isn't stretch, determine its width and remove that from lengthToStretch
int sectionSize = 0;
if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
- sectionSize = headerSectionSize(i);
+ sectionSize = qBound(q->minimumSectionSize(), headerSectionSize(i), q->maximumSectionSize());
} else { // resizeMode == QHeaderView::ResizeToContents
int logicalIndex = q->logicalIndex(i);
sectionSize = qMax(viewSectionSizeHint(logicalIndex),
@@ -3551,6 +3551,8 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
// cascade the section size change
for (int i = visual + 1; i < sectionCount(); ++i) {
+ if (isVisualIndexHidden(i))
+ continue;
if (!sectionIsCascadable(i))
continue;
int currentSectionSize = headerSectionSize(i);
@@ -3593,6 +3595,8 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
// cascade the section size change
if (delta < 0 && newSize < minimumSize) {
for (int i = visual - 1; i >= 0; --i) {
+ if (isVisualIndexHidden(i))
+ continue;
if (!sectionIsCascadable(i))
continue;
int sectionSize = headerSectionSize(i);
@@ -3607,6 +3611,8 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
// let the next section get the space from the resized section
if (!sectionResized) {
for (int i = visual + 1; i < sectionCount(); ++i) {
+ if (isVisualIndexHidden(i))
+ continue;
if (!sectionIsCascadable(i))
continue;
int currentSectionSize = headerSectionSize(i);
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index 0efee755a2..7f027595b7 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -2873,10 +2873,19 @@ void QIconModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
if (column() >= topLeft.column() && column() <= bottomRight.column()) {
- QStyleOptionViewItem option = viewOptions();
- int bottom = qMin(items.count(), bottomRight.row() + 1);
+ const QStyleOptionViewItem option = viewOptions();
+ const int bottom = qMin(items.count(), bottomRight.row() + 1);
+ const bool useItemSize = !dd->grid.isValid();
for (int row = topLeft.row(); row < bottom; ++row)
- items[row].resize(itemSize(option, modelIndex(row)));
+ {
+ QSize s = itemSize(option, modelIndex(row));
+ if (!useItemSize)
+ {
+ s.setWidth(qMin(dd->grid.width(), s.width()));
+ s.setHeight(qMin(dd->grid.height(), s.height()));
+ }
+ items[row].resize(s);
+ }
}
}
diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp
index 2813340ea2..853e27cd6e 100644
--- a/src/widgets/kernel/qaction.cpp
+++ b/src/widgets/kernel/qaction.cpp
@@ -1120,6 +1120,8 @@ void
QAction::setData(const QVariant &data)
{
Q_D(QAction);
+ if (d->userData == data)
+ return;
d->userData = data;
d->sendDataChanged();
}
diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp
index 1e455b0d64..f3db4f4e2d 100644
--- a/src/widgets/kernel/qlayout.cpp
+++ b/src/widgets/kernel/qlayout.cpp
@@ -1350,7 +1350,8 @@ QRect QLayout::alignmentRect(const QRect &r) const
/*!
Removes the widget \a widget from the layout. After this call, it
is the caller's responsibility to give the widget a reasonable
- geometry or to put the widget back into a layout.
+ geometry or to put the widget back into a layout or to explicitly
+ hide it if necessary.
\b{Note:} The ownership of \a widget remains the same as
when it was added.
diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp
index f944a7097b..32600d4152 100644
--- a/src/widgets/kernel/qshortcut.cpp
+++ b/src/widgets/kernel/qshortcut.cpp
@@ -205,7 +205,7 @@ static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidge
#if defined(DEBUG_QSHORTCUTMAP)
qDebug().nospace() << "..true [Pass-through]";
#endif
- return true;
+ return QApplicationPrivate::tryModalHelper(w, nullptr);
}
#if QT_CONFIG(graphicsview)
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 6a633fb575..c5eea1c514 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1374,6 +1374,8 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
d->setWindowIconText_helper(d->topData()->iconText);
if (isWindow() && !d->topData()->caption.isEmpty())
d->setWindowTitle_helper(d->topData()->caption);
+ if (isWindow() && !d->topData()->filePath.isEmpty())
+ d->setWindowFilePath_helper(d->topData()->filePath);
if (windowType() != Qt::Desktop) {
d->updateSystemBackground();
diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp
index dbd94e890d..5854472ff0 100644
--- a/src/widgets/widgets/qabstractbutton.cpp
+++ b/src/widgets/widgets/qabstractbutton.cpp
@@ -991,13 +991,14 @@ void QAbstractButton::mousePressEvent(QMouseEvent *e)
void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QAbstractButton);
- d->pressed = false;
if (e->button() != Qt::LeftButton) {
e->ignore();
return;
}
+ d->pressed = false;
+
if (!d->down) {
// refresh is required by QMacStyle to resume the default button animation
d->refresh();
diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp
index d97fedadab..00ee0a9d10 100644
--- a/src/widgets/widgets/qmainwindow.cpp
+++ b/src/widgets/widgets/qmainwindow.cpp
@@ -545,6 +545,7 @@ void QMainWindow::setMenuBar(QMenuBar *menuBar)
menuBar->setCornerWidget(cornerWidget, Qt::TopRightCorner);
}
oldMenuBar->hide();
+ oldMenuBar->setParent(nullptr);
oldMenuBar->deleteLater();
}
topLayout->setMenuBar(menuBar);
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index cf6167bace..c4bb02fd5b 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -234,9 +234,6 @@ void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu)
}
}
-// forward declare function
-static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu);
-
void QMenuPrivate::syncPlatformMenu()
{
Q_Q(QMenu);
@@ -246,19 +243,64 @@ void QMenuPrivate::syncPlatformMenu()
QPlatformMenuItem *beforeItem = nullptr;
const QList<QAction*> actions = q->actions();
for (QList<QAction*>::const_reverse_iterator it = actions.rbegin(), end = actions.rend(); it != end; ++it) {
- QPlatformMenuItem *menuItem = platformMenu->createMenuItem();
- QAction *action = *it;
- menuItem->setTag(reinterpret_cast<quintptr>(action));
- QObject::connect(menuItem, SIGNAL(activated()), action, SLOT(trigger()), Qt::QueuedConnection);
- QObject::connect(menuItem, SIGNAL(hovered()), action, SIGNAL(hovered()), Qt::QueuedConnection);
- copyActionToPlatformItem(action, menuItem, platformMenu.data());
- platformMenu->insertMenuItem(menuItem, beforeItem);
+ QPlatformMenuItem *menuItem = insertActionInPlatformMenu(*it, beforeItem);
beforeItem = menuItem;
}
platformMenu->syncSeparatorsCollapsible(collapsibleSeparators);
platformMenu->setEnabled(q->isEnabled());
}
+void QMenuPrivate::copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item)
+{
+ item->setText(action->text());
+ item->setIsSeparator(action->isSeparator());
+ if (action->isIconVisibleInMenu()) {
+ item->setIcon(action->icon());
+ if (QWidget *w = action->parentWidget()) {
+ QStyleOption opt;
+ opt.init(w);
+ item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w));
+ } else {
+ QStyleOption opt;
+ item->setIconSize(qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, 0));
+ }
+ } else {
+ item->setIcon(QIcon());
+ }
+ item->setVisible(action->isVisible());
+#if QT_CONFIG(shortcut)
+ item->setShortcut(action->shortcut());
+#endif
+ item->setCheckable(action->isCheckable());
+ item->setChecked(action->isChecked());
+ item->setHasExclusiveGroup(action->actionGroup() && action->actionGroup()->isExclusive());
+ item->setFont(action->font());
+ item->setRole((QPlatformMenuItem::MenuRole) action->menuRole());
+ item->setEnabled(action->isEnabled());
+
+ if (action->menu()) {
+ if (!action->menu()->platformMenu())
+ action->menu()->setPlatformMenu(platformMenu->createSubMenu());
+ item->setMenu(action->menu()->platformMenu());
+ } else {
+ item->setMenu(0);
+ }
+}
+
+QPlatformMenuItem * QMenuPrivate::insertActionInPlatformMenu(const QAction *action, QPlatformMenuItem *beforeItem)
+{
+ QPlatformMenuItem *menuItem = platformMenu->createMenuItem();
+ Q_ASSERT(menuItem);
+
+ menuItem->setTag(reinterpret_cast<quintptr>(action));
+ QObject::connect(menuItem, &QPlatformMenuItem::activated, action, &QAction::trigger, Qt::QueuedConnection);
+ QObject::connect(menuItem, &QPlatformMenuItem::hovered, action, &QAction::hovered, Qt::QueuedConnection);
+ copyActionToPlatformItem(action, menuItem);
+ platformMenu->insertMenuItem(menuItem, beforeItem);
+
+ return menuItem;
+}
+
int QMenuPrivate::scrollerHeight() const
{
Q_Q(const QMenu);
@@ -2338,6 +2380,12 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
d->updateLayoutDirection();
d->adjustMenuScreen(p);
+ const bool contextMenu = d->isContextMenu();
+ if (d->lastContextMenu != contextMenu) {
+ d->itemsDirty = true;
+ d->lastContextMenu = contextMenu;
+ }
+
#if QT_CONFIG(menubar)
// if this menu is part of a chain attached to a QMenuBar, set the
// _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type
@@ -3476,43 +3524,6 @@ QMenu::timerEvent(QTimerEvent *e)
}
}
-static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu)
-{
- item->setText(action->text());
- item->setIsSeparator(action->isSeparator());
- if (action->isIconVisibleInMenu()) {
- item->setIcon(action->icon());
- if (QWidget *w = action->parentWidget()) {
- QStyleOption opt;
- opt.init(w);
- item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w));
- } else {
- QStyleOption opt;
- item->setIconSize(qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, 0));
- }
- } else {
- item->setIcon(QIcon());
- }
- item->setVisible(action->isVisible());
-#ifndef QT_NO_SHORTCUT
- item->setShortcut(action->shortcut());
-#endif
- item->setCheckable(action->isCheckable());
- item->setChecked(action->isChecked());
- item->setHasExclusiveGroup(action->actionGroup() && action->actionGroup()->isExclusive());
- item->setFont(action->font());
- item->setRole((QPlatformMenuItem::MenuRole) action->menuRole());
- item->setEnabled(action->isEnabled());
-
- if (action->menu()) {
- if (!action->menu()->platformMenu())
- action->menu()->setPlatformMenu(itemsMenu->createSubMenu());
- item->setMenu(action->menu()->platformMenu());
- } else {
- item->setMenu(0);
- }
-}
-
/*!
\reimp
*/
@@ -3566,15 +3577,10 @@ void QMenu::actionEvent(QActionEvent *e)
if (!d->platformMenu.isNull()) {
if (e->type() == QEvent::ActionAdded) {
- QPlatformMenuItem *menuItem = d->platformMenu->createMenuItem();
- menuItem->setTag(reinterpret_cast<quintptr>(e->action()));
- QObject::connect(menuItem, SIGNAL(activated()), e->action(), SLOT(trigger()));
- QObject::connect(menuItem, SIGNAL(hovered()), e->action(), SIGNAL(hovered()));
- copyActionToPlatformItem(e->action(), menuItem, d->platformMenu);
QPlatformMenuItem *beforeItem = e->before()
? d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->before()))
: nullptr;
- d->platformMenu->insertMenuItem(menuItem, beforeItem);
+ d->insertActionInPlatformMenu(e->action(), beforeItem);
} else if (e->type() == QEvent::ActionRemoved) {
QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->action()));
d->platformMenu->removeMenuItem(menuItem);
@@ -3582,7 +3588,7 @@ void QMenu::actionEvent(QActionEvent *e)
} else if (e->type() == QEvent::ActionChanged) {
QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->action()));
if (menuItem) {
- copyActionToPlatformItem(e->action(), menuItem, d->platformMenu);
+ d->copyActionToPlatformItem(e->action(), menuItem);
d->platformMenu->syncMenuItem(menuItem);
}
}
diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h
index fac58f59ab..b6afb05e3a 100644
--- a/src/widgets/widgets/qmenu_p.h
+++ b/src/widgets/widgets/qmenu_p.h
@@ -91,19 +91,10 @@ class QMenuSloppyState
Q_DISABLE_COPY(QMenuSloppyState)
public:
QMenuSloppyState()
- : m_menu(nullptr)
- , m_enabled(false)
+ : m_enabled(false)
, m_uni_directional(false)
, m_select_other_actions(false)
- , m_first_mouse(true)
- , m_init_guard(false)
, m_use_reset_action(true)
- , m_uni_dir_discarded_count(0)
- , m_uni_dir_fail_at_count(0)
- , m_timeout(0)
- , m_reset_action(nullptr)
- , m_origin_action(nullptr)
- , m_parent(nullptr)
{ }
~QMenuSloppyState() { reset(); }
@@ -252,44 +243,46 @@ public:
QMenu *subMenu() const { return m_sub_menu; }
private:
- QMenu *m_menu;
- bool m_enabled;
- bool m_uni_directional;
- bool m_select_other_actions;
- bool m_first_mouse;
- bool m_init_guard;
- bool m_discard_state_when_entering_parent;
- bool m_dont_start_time_on_leave;
- bool m_use_reset_action;
- short m_uni_dir_discarded_count;
- short m_uni_dir_fail_at_count;
- short m_timeout;
- QBasicTimer m_time;
- QAction *m_reset_action;
- QAction *m_origin_action;
+ QMenu *m_menu = nullptr;
+ QAction *m_reset_action = nullptr;
+ QAction *m_origin_action = nullptr;
QRectF m_action_rect;
QPointF m_previous_point;
QPointer<QMenu> m_sub_menu;
- QMenuSloppyState *m_parent;
+ QMenuSloppyState *m_parent = nullptr;
+ QBasicTimer m_time;
+ short m_uni_dir_discarded_count = 0;
+ short m_uni_dir_fail_at_count = 0;
+ short m_timeout = 0;
+ bool m_init_guard = false;
+ bool m_first_mouse = true;
+
+ bool m_enabled : 1;
+ bool m_uni_directional : 1;
+ bool m_select_other_actions : 1;
+ bool m_discard_state_when_entering_parent : 1;
+ bool m_dont_start_time_on_leave : 1;
+ bool m_use_reset_action : 1;
};
class QMenuPrivate : public QWidgetPrivate
{
Q_DECLARE_PUBLIC(QMenu)
public:
- QMenuPrivate() : itemsDirty(0), maxIconWidth(0), tabWidth(0), ncols(0),
- collapsibleSeparators(true), toolTipsVisible(false),
- activationRecursionGuard(false), delayedPopupGuard(false),
- hasReceievedEnter(false),
- hasHadMouse(0), aboutToHide(0), motions(0),
- currentAction(0),
-#ifdef QT_KEYPAD_NAVIGATION
- selectAction(0),
- cancelAction(0),
-#endif
- scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0),
- hasCheckableItems(0), doChildEffects(false), platformMenu(0),
- scrollUpTearOffItem(nullptr), scrollDownItem(nullptr)
+ QMenuPrivate() :
+ itemsDirty(false),
+ hasCheckableItems(false),
+ lastContextMenu(false),
+ collapsibleSeparators(true),
+ toolTipsVisible(false),
+ delayedPopupGuard(false),
+ hasReceievedEnter(false),
+ hasHadMouse(false),
+ aboutToHide(false),
+ tearoff(false),
+ tornoff(false),
+ tearoffHighlighted(false),
+ doChildEffects(false)
{ }
~QMenuPrivate()
@@ -302,6 +295,9 @@ public:
QPlatformMenu *createPlatformMenu();
void setPlatformMenu(QPlatformMenu *menu);
void syncPlatformMenu();
+ void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item);
+ QPlatformMenuItem *insertActionInPlatformMenu(const QAction *action, QPlatformMenuItem *beforeItem);
+
#ifdef Q_OS_OSX
void moveWidgetToPlatformItem(QWidget *w, QPlatformMenuItem* item);
#endif
@@ -312,8 +308,6 @@ public:
bool isContextMenu() const;
//item calculations
- mutable uint itemsDirty : 1;
- mutable uint maxIconWidth, tabWidth;
QRect actionRect(QAction *) const;
mutable QVector<QRect> actionRects;
@@ -322,31 +316,19 @@ public:
void updateActionRects(const QRect &screen) const;
QRect popupGeometry() const;
QRect popupGeometry(int screen) const;
- mutable uint ncols : 4; //4 bits is probably plenty
- uint collapsibleSeparators : 1;
- uint toolTipsVisible : 1;
int getLastVisibleAction() const;
- bool activationRecursionGuard;
- bool delayedPopupGuard;
- bool hasReceievedEnter;
-
//selection
static QMenu *mouseDown;
QPoint mousePopupPos;
- uint hasHadMouse : 1;
- uint aboutToHide : 1;
- int motions;
- int mousePopupDelay;
- QAction *currentAction;
+
+ QAction *currentAction = nullptr;
#ifdef QT_KEYPAD_NAVIGATION
- QAction *selectAction;
- QAction *cancelAction;
+ QAction *selectAction = nullptr;
+ QAction *cancelAction = nullptr;
#endif
struct DelayState {
DelayState()
- : parent(0)
- , action(0)
{ }
void initialize(QMenu *parent)
{
@@ -366,9 +348,9 @@ public:
timer.stop();
}
- QMenu *parent;
+ QMenu *parent = nullptr;
+ QAction *action = nullptr;
QBasicTimer timer;
- QAction *action;
} delayState;
enum SelectionReason {
SelectedFromKeyboard,
@@ -385,19 +367,20 @@ public:
struct QMenuScroller {
enum ScrollLocation { ScrollStay, ScrollBottom, ScrollTop, ScrollCenter };
enum ScrollDirection { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
- uint scrollFlags : 2, scrollDirection : 2;
- int scrollOffset;
+ int scrollOffset = 0;
QBasicTimer scrollTimer;
+ quint8 scrollFlags = ScrollNone;
+ quint8 scrollDirection = ScrollNone;
- QMenuScroller() : scrollFlags(ScrollNone), scrollDirection(ScrollNone), scrollOffset(0) { }
+ QMenuScroller() { }
~QMenuScroller() { }
- } *scroll;
+ } *scroll = nullptr;
void scrollMenu(QMenuScroller::ScrollLocation location, bool active=false);
void scrollMenu(QMenuScroller::ScrollDirection direction, bool page=false, bool active=false);
void scrollMenu(QAction *action, QMenuScroller::ScrollLocation location, bool active=false);
//synchronous operation (ie exec())
- QEventLoop *eventLoop;
+ QEventLoop *eventLoop = nullptr;
QPointer<QAction> syncAction;
//search buffer
@@ -423,18 +406,15 @@ public:
inline int indexOf(QAction *act) const { return q_func()->actions().indexOf(act); }
//tear off support
- uint tearoff : 1, tornoff : 1, tearoffHighlighted : 1;
QPointer<QTornOffMenu> tornPopup;
- mutable bool hasCheckableItems;
-
QMenuSloppyState sloppyState;
//default action
QPointer<QAction> defaultAction;
- QAction *menuAction;
- QAction *defaultMenuAction;
+ QAction *menuAction = nullptr;
+ QAction *defaultMenuAction = nullptr;
void setOverrideMenuAction(QAction *);
void _q_overrideMenuActionDestroyed();
@@ -452,9 +432,6 @@ public:
void adjustMenuScreen(const QPoint &p);
void updateLayoutDirection();
- //menu fading/scrolling effects
- bool doChildEffects;
-
QPointer<QPlatformMenu> platformMenu;
QPointer<QAction> actionAboutToTrigger;
@@ -473,12 +450,38 @@ public:
QMenuPrivate *menuPrivate;
Type scrollType;
};
- ScrollerTearOffItem *scrollUpTearOffItem;
- ScrollerTearOffItem *scrollDownItem;
+ ScrollerTearOffItem *scrollUpTearOffItem = nullptr;
+ ScrollerTearOffItem *scrollDownItem = nullptr;
void drawScroller(QPainter *painter, ScrollerTearOffItem::Type type, const QRect &rect);
void drawTearOff(QPainter *painter, const QRect &rect);
QRect rect() const;
+
+ mutable uint maxIconWidth = 0;
+ mutable uint tabWidth = 0;
+ int motions = 0;
+ int mousePopupDelay = 0;
+
+ bool activationRecursionGuard = false;
+
+ mutable quint8 ncols = 0; // "255cols ought to be enough for anybody."
+
+ mutable bool itemsDirty : 1;
+ mutable bool hasCheckableItems : 1;
+ bool lastContextMenu : 1;
+ bool collapsibleSeparators : 1;
+ bool toolTipsVisible : 1;
+ bool delayedPopupGuard : 1;
+ bool hasReceievedEnter : 1;
+ // Selection
+ bool hasHadMouse : 1;
+ bool aboutToHide : 1;
+ // Tear-off menus
+ bool tearoff : 1;
+ bool tornoff : 1;
+ bool tearoffHighlighted : 1;
+ //menu fading/scrolling effects
+ bool doChildEffects : 1;
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp
index c469c0b793..80c6d28e85 100644
--- a/src/widgets/widgets/qmenubar.cpp
+++ b/src/widgets/widgets/qmenubar.cpp
@@ -1188,7 +1188,7 @@ void QMenuBar::leaveEvent(QEvent *)
d->setCurrentAction(0);
}
-QPlatformMenu *QMenuBarPrivate::getPlatformMenu(QAction *action)
+QPlatformMenu *QMenuBarPrivate::getPlatformMenu(const QAction *action)
{
if (!action || !action->menu())
return 0;
@@ -1203,6 +1203,29 @@ QPlatformMenu *QMenuBarPrivate::getPlatformMenu(QAction *action)
return platformMenu;
}
+QPlatformMenu *QMenuBarPrivate::findInsertionPlatformMenu(const QAction *action)
+{
+ Q_Q(QMenuBar);
+ QPlatformMenu *beforeMenu = nullptr;
+ for (int beforeIndex = indexOf(const_cast<QAction *>(action)) + 1;
+ !beforeMenu && (beforeIndex < q->actions().size());
+ ++beforeIndex) {
+ beforeMenu = getPlatformMenu(q->actions().at(beforeIndex));
+ }
+
+ return beforeMenu;
+}
+
+void QMenuBarPrivate::copyActionToPlatformMenu(const QAction *action, QPlatformMenu *menu)
+{
+ const auto tag = reinterpret_cast<quintptr>(action);
+ if (menu->tag() != tag)
+ menu->setTag(tag);
+ menu->setText(action->text());
+ menu->setVisible(action->isVisible());
+ menu->setEnabled(action->isEnabled());
+}
+
/*!
\reimp
*/
@@ -1219,16 +1242,9 @@ void QMenuBar::actionEvent(QActionEvent *e)
if (e->type() == QEvent::ActionAdded) {
QPlatformMenu *menu = d->getPlatformMenu(e->action());
if (menu) {
- QPlatformMenu* beforeMenu = NULL;
- for (int beforeIndex = d->indexOf(e->action()) + 1;
- !beforeMenu && (beforeIndex < actions().size());
- ++beforeIndex)
- {
- beforeMenu = d->getPlatformMenu(actions().at(beforeIndex));
- }
+ d->copyActionToPlatformMenu(e->action(), menu);
- menu->setTag(reinterpret_cast<quintptr>(e->action()));
- menu->setText(e->action()->text());
+ QPlatformMenu *beforeMenu = d->findInsertionPlatformMenu(e->action());
d->platformMenuBar->insertMenu(menu, beforeMenu);
}
} else if (e->type() == QEvent::ActionRemoved) {
@@ -1236,7 +1252,7 @@ void QMenuBar::actionEvent(QActionEvent *e)
if (menu)
d->platformMenuBar->removeMenu(menu);
} else if (e->type() == QEvent::ActionChanged) {
- QPlatformMenu* cur = d->platformMenuBar->menuForTag(reinterpret_cast<quintptr>(e->action()));
+ QPlatformMenu *cur = d->platformMenuBar->menuForTag(reinterpret_cast<quintptr>(e->action()));
QPlatformMenu *menu = d->getPlatformMenu(e->action());
// the menu associated with the action can change, need to
@@ -1245,21 +1261,13 @@ void QMenuBar::actionEvent(QActionEvent *e)
if (cur)
d->platformMenuBar->removeMenu(cur);
if (menu) {
- menu->setTag(reinterpret_cast<quintptr>(e->action()));
-
- QPlatformMenu* beforeMenu = NULL;
- for (int beforeIndex = d->indexOf(e->action()) + 1;
- !beforeMenu && (beforeIndex < actions().size());
- ++beforeIndex)
- {
- beforeMenu = d->getPlatformMenu(actions().at(beforeIndex));
- }
+ d->copyActionToPlatformMenu(e->action(), menu);
+
+ QPlatformMenu *beforeMenu = d->findInsertionPlatformMenu(e->action());
d->platformMenuBar->insertMenu(menu, beforeMenu);
}
} else if (menu) {
- menu->setText(e->action()->text());
- menu->setVisible(e->action()->isVisible());
- menu->setEnabled(e->action()->isEnabled());
+ d->copyActionToPlatformMenu(e->action(), menu);
d->platformMenuBar->syncMenu(menu);
}
}
diff --git a/src/widgets/widgets/qmenubar_p.h b/src/widgets/widgets/qmenubar_p.h
index 01d8793a3a..c276a4512d 100644
--- a/src/widgets/widgets/qmenubar_p.h
+++ b/src/widgets/widgets/qmenubar_p.h
@@ -132,7 +132,9 @@ public:
QBasicTimer autoReleaseTimer;
QPlatformMenuBar *platformMenuBar;
- QPlatformMenu *getPlatformMenu(QAction *action);
+ QPlatformMenu *getPlatformMenu(const QAction *action);
+ QPlatformMenu *findInsertionPlatformMenu(const QAction *action);
+ void copyActionToPlatformMenu(const QAction *e, QPlatformMenu *menu);
inline int indexOf(QAction *act) const { return q_func()->actions().indexOf(act); }
};