summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/accessible/qaccessible.cpp21
-rw-r--r--src/gui/accessible/qaccessiblebridge.cpp2
-rw-r--r--src/gui/accessible/qaccessiblecache.cpp2
-rw-r--r--src/gui/accessible/qaccessibleplugin.cpp2
-rw-r--r--src/gui/configure.json15
-rw-r--r--src/gui/doc/qtgui.qdocconf1
-rw-r--r--src/gui/doc/snippets/code/src_gui_painting_qtransform.cpp8
-rw-r--r--src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp2
-rw-r--r--src/gui/doc/snippets/transform/main.cpp19
-rw-r--r--src/gui/doc/src/coordsys.qdoc2
-rw-r--r--src/gui/doc/src/external-resources.qdoc2
-rw-r--r--src/gui/image/qiconengineplugin.cpp2
-rw-r--r--src/gui/image/qimage.cpp73
-rw-r--r--src/gui/image/qimage_conversions.cpp6
-rw-r--r--src/gui/image/qimage_neon.cpp2
-rw-r--r--src/gui/image/qimage_p.h61
-rw-r--r--src/gui/image/qimageiohandler.cpp2
-rw-r--r--src/gui/image/qimagereader.cpp7
-rw-r--r--src/gui/image/qimagewriter.cpp7
-rw-r--r--src/gui/image/qpixmap.cpp1
-rw-r--r--src/gui/image/qpixmapcache.cpp5
-rw-r--r--src/gui/image/qpnghandler.cpp6
-rw-r--r--src/gui/image/qppmhandler.cpp49
-rw-r--r--src/gui/image/qxpmhandler.cpp35
-rw-r--r--src/gui/kernel/qclipboard.cpp6
-rw-r--r--src/gui/kernel/qcursor.cpp6
-rw-r--r--src/gui/kernel/qdnd.cpp2
-rw-r--r--src/gui/kernel/qdrag.cpp2
-rw-r--r--src/gui/kernel/qevent.cpp2
-rw-r--r--src/gui/kernel/qgenericplugin.cpp2
-rw-r--r--src/gui/kernel/qguiapplication.cpp81
-rw-r--r--src/gui/kernel/qhighdpiscaling.cpp2
-rw-r--r--src/gui/kernel/qinputdevicemanager.cpp2
-rw-r--r--src/gui/kernel/qinternalmimedata.cpp2
-rw-r--r--src/gui/kernel/qkeymapper.cpp2
-rw-r--r--src/gui/kernel/qkeysequence.cpp6
-rw-r--r--src/gui/kernel/qoffscreensurface.cpp2
-rw-r--r--src/gui/kernel/qopenglcontext.cpp3
-rw-r--r--src/gui/kernel/qpaintdevicewindow.cpp2
-rw-r--r--src/gui/kernel/qpalette.cpp7
-rw-r--r--src/gui/kernel/qplatformdialoghelper.cpp2
-rw-r--r--src/gui/kernel/qplatformgraphicsbuffer.cpp2
-rw-r--r--src/gui/kernel/qplatforminputcontext.cpp2
-rw-r--r--src/gui/kernel/qplatforminputcontextplugin.cpp2
-rw-r--r--src/gui/kernel/qplatformintegrationplugin.cpp2
-rw-r--r--src/gui/kernel/qplatformmenu.cpp2
-rw-r--r--src/gui/kernel/qplatformnativeinterface.cpp2
-rw-r--r--src/gui/kernel/qplatformscreen.cpp2
-rw-r--r--src/gui/kernel/qplatformsharedgraphicscache.cpp2
-rw-r--r--src/gui/kernel/qplatformtheme.cpp22
-rw-r--r--src/gui/kernel/qplatformthemeplugin.cpp2
-rw-r--r--src/gui/kernel/qplatformwindow.cpp39
-rw-r--r--src/gui/kernel/qrasterwindow.cpp2
-rw-r--r--src/gui/kernel/qscreen.cpp14
-rw-r--r--src/gui/kernel/qsessionmanager.cpp2
-rw-r--r--src/gui/kernel/qshapedpixmapdndwindow.cpp2
-rw-r--r--src/gui/kernel/qstylehints.cpp2
-rw-r--r--src/gui/kernel/qsurface.cpp2
-rw-r--r--src/gui/kernel/qsurfaceformat.cpp2
-rw-r--r--src/gui/kernel/qtestsupport_gui.cpp24
-rw-r--r--src/gui/kernel/qwindow.cpp31
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp8
-rw-r--r--src/gui/math3d/qmatrix4x4.h10
-rw-r--r--src/gui/math3d/qquaternion.cpp77
-rw-r--r--src/gui/opengl/qopengl.h3
-rw-r--r--src/gui/opengl/qopenglpaintdevice.cpp2
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache.cpp61
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache_p.h4
-rw-r--r--src/gui/opengl/qopengltextureblitter.cpp188
-rw-r--r--src/gui/opengl/qopengltextureglyphcache.cpp5
-rw-r--r--src/gui/painting/painting.pri2
-rw-r--r--src/gui/painting/qbackingstore.cpp40
-rw-r--r--src/gui/painting/qblendfunctions_p.h53
-rw-r--r--src/gui/painting/qbrush.cpp173
-rw-r--r--src/gui/painting/qcolor.cpp4
-rw-r--r--src/gui/painting/qcolorspace.cpp66
-rw-r--r--src/gui/painting/qcolorspace.h4
-rw-r--r--src/gui/painting/qcolorspace_p.h4
-rw-r--r--src/gui/painting/qcolortransfertable_p.h51
-rw-r--r--src/gui/painting/qcolortrc_p.h2
-rw-r--r--src/gui/painting/qcolortrclut_p.h1
-rw-r--r--src/gui/painting/qcompositionfunctions.cpp8
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp18
-rw-r--r--src/gui/painting/qdatabuffer_p.h3
-rw-r--r--src/gui/painting/qdrawhelper.cpp40
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp4
-rw-r--r--src/gui/painting/qdrawhelper_sse4.cpp8
-rw-r--r--src/gui/painting/qicc.cpp42
-rw-r--r--src/gui/painting/qimagescale.cpp2
-rw-r--r--src/gui/painting/qimagescale_neon.cpp2
-rw-r--r--src/gui/painting/qimagescale_sse4.cpp2
-rw-r--r--src/gui/painting/qmemrotate.cpp42
-rw-r--r--src/gui/painting/qpagesize.h2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp54
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h3
-rw-r--r--src/gui/painting/qpaintengineex.cpp44
-rw-r--r--src/gui/painting/qpainter.cpp68
-rw-r--r--src/gui/painting/qpainterpath.cpp7
-rw-r--r--src/gui/painting/qpainterpath_p.h1
-rw-r--r--src/gui/painting/qpathclipper_p.h6
-rw-r--r--src/gui/painting/qpdf.cpp35
-rw-r--r--src/gui/painting/qpdf_p.h1
-rw-r--r--src/gui/painting/qpdfwriter.cpp2
-rw-r--r--src/gui/painting/qpen.cpp11
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp2
-rw-r--r--src/gui/painting/qregion.cpp2
-rw-r--r--src/gui/painting/qstroker.cpp56
-rw-r--r--src/gui/painting/qstroker_p.h1
-rw-r--r--src/gui/painting/qt_attribution.json2
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp6
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h2
-rw-r--r--src/gui/painting/qtransform.cpp23
-rw-r--r--src/gui/painting/qtriangulatingstroker.cpp1
-rw-r--r--src/gui/qtgui.tracepoints10
-rw-r--r--src/gui/rhi/qrhid3d11.cpp14
-rw-r--r--src/gui/rhi/qrhimetal.mm45
-rw-r--r--src/gui/rhi/qrhivulkan.cpp8
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.cpp6
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.h1
-rw-r--r--src/gui/text/qcssparser.cpp6
-rw-r--r--src/gui/text/qfont.cpp64
-rw-r--r--src/gui/text/qfontdatabase.cpp98
-rw-r--r--src/gui/text/qfontdatabase.h2
-rw-r--r--src/gui/text/qfontengine.cpp6
-rw-r--r--src/gui/text/qfontmetrics.cpp22
-rw-r--r--src/gui/text/qfontsubset.cpp18
-rw-r--r--src/gui/text/qfontsubset_p.h1
-rw-r--r--src/gui/text/qinputcontrol.cpp5
-rw-r--r--src/gui/text/qrawfont.cpp2
-rw-r--r--src/gui/text/qtextdocument.cpp31
-rw-r--r--src/gui/text/qtextdocument_p.cpp5
-rw-r--r--src/gui/text/qtextdocument_p.h1
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp3
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp28
-rw-r--r--src/gui/text/qtextdocumentwriter.cpp7
-rw-r--r--src/gui/text/qtextengine.cpp50
-rw-r--r--src/gui/text/qtextformat.cpp2
-rw-r--r--src/gui/text/qtexthtmlparser.cpp8
-rw-r--r--src/gui/text/qtexthtmlparser_p.h4
-rw-r--r--src/gui/text/qtextimagehandler.cpp50
-rw-r--r--src/gui/text/qtextlayout.cpp68
-rw-r--r--src/gui/text/qtextlist.cpp2
-rw-r--r--src/gui/text/qtextmarkdownimporter.cpp4
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp2
-rw-r--r--src/gui/text/qtextobject.cpp2
-rw-r--r--src/gui/text/qtextodfwriter.cpp4
-rw-r--r--src/gui/text/qtexttable.cpp15
-rw-r--r--src/gui/text/qtexttable_p.h7
-rw-r--r--src/gui/text/qzip.cpp20
-rw-r--r--src/gui/util/qdesktopservices.cpp24
-rw-r--r--src/gui/util/qlayoutpolicy.cpp2
-rw-r--r--src/gui/util/qpkmhandler.cpp2
-rw-r--r--src/gui/util/qvalidator.cpp10
-rw-r--r--src/gui/vulkan/qvulkaninstance.cpp7
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp37
-rw-r--r--src/gui/vulkan/qvulkanwindow_p.h2
156 files changed, 1799 insertions, 787 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp
index c424afa3b4..32d0e6ca91 100644
--- a/src/gui/accessible/qaccessible.cpp
+++ b/src/gui/accessible/qaccessible.cpp
@@ -54,6 +54,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/private/qmetaobject_p.h>
#include <QtCore/qhash.h>
#include <private/qfactoryloader_p.h>
@@ -162,7 +163,6 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\value hasPopup The object opens a popup.
\value hotTracked The object's appearance is sensitive to the mouse cursor position.
\value invalid The object is no longer valid (because it has been deleted).
- \value invalidEntry Input validation current input invalid.
\value invisible The object is not visible to the user.
\value linked The object is linked to another object, e.g. a hyperlink.
\value marqueed The object displays scrolling contents, e.g. a log view.
@@ -681,6 +681,25 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
// Create a QAccessibleInterface for the object class. Start by the most
// derived class and walk up the class hierarchy.
const QMetaObject *mo = object->metaObject();
+ const auto *objectPriv = QObjectPrivate::get(object);
+ /*
+ We do not want to cache each and every QML metaobject (Button_QMLTYPE_124,
+ Button_QMLTYPE_125, etc.). Those dynamic metaobjects shouldn't have an
+ accessible interface in any case. Instead, we start the whole checking
+ with the first non-dynamic meta-object. To avoid potential regressions
+ in other areas of Qt that also use dynamic metaobjects, we only do this
+ for objects that are QML-related (approximated by checking whether they
+ have ddata set).
+ */
+ const bool qmlRelated = !objectPriv->isDeletingChildren &&
+ objectPriv->declarativeData;
+ while (qmlRelated && mo) {
+ auto mop = QMetaObjectPrivate::get(mo);
+ if (!mop || !(mop->flags & DynamicMetaObject))
+ break;
+
+ mo = mo->superClass();
+ };
while (mo) {
const QString cn = QLatin1String(mo->className());
diff --git a/src/gui/accessible/qaccessiblebridge.cpp b/src/gui/accessible/qaccessiblebridge.cpp
index c6a417e063..7c8a415493 100644
--- a/src/gui/accessible/qaccessiblebridge.cpp
+++ b/src/gui/accessible/qaccessiblebridge.cpp
@@ -138,4 +138,6 @@ QAccessibleBridgePlugin::~QAccessibleBridgePlugin()
QT_END_NAMESPACE
+#include "moc_qaccessiblebridge.cpp"
+
#endif // QT_NO_ACCESSIBILITY
diff --git a/src/gui/accessible/qaccessiblecache.cpp b/src/gui/accessible/qaccessiblecache.cpp
index 20376a54c4..28c797a0f1 100644
--- a/src/gui/accessible/qaccessiblecache.cpp
+++ b/src/gui/accessible/qaccessiblecache.cpp
@@ -159,4 +159,6 @@ void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj)
QT_END_NAMESPACE
+#include "moc_qaccessiblecache_p.cpp"
+
#endif
diff --git a/src/gui/accessible/qaccessibleplugin.cpp b/src/gui/accessible/qaccessibleplugin.cpp
index 27497858b5..709e0f3daa 100644
--- a/src/gui/accessible/qaccessibleplugin.cpp
+++ b/src/gui/accessible/qaccessibleplugin.cpp
@@ -89,4 +89,6 @@ QAccessiblePlugin::~QAccessiblePlugin()
QT_END_NAMESPACE
+#include "moc_qaccessibleplugin.cpp"
+
#endif // QT_NO_ACCESSIBILITY
diff --git a/src/gui/configure.json b/src/gui/configure.json
index c8c4864eca..7b80162faa 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -601,15 +601,6 @@
],
"use": "xcb"
},
- "xcb_util": {
- "label": "XCB Util >= 0.3.9",
- "headers": "xcb/xcb_util.h",
- "sources": [
- { "type": "pkgConfig", "args": "xcb-util >= 0.3.9" },
- "-lxcb-util"
- ],
- "use": "xcb"
- },
"xcb_image": {
"label": "XCB Image >= 0.3.9",
"headers": "xcb/xcb_image.h",
@@ -617,7 +608,7 @@
{ "type": "pkgConfig", "args": "xcb-image >= 0.3.9" },
"-lxcb-image"
],
- "use": "xcb_shm xcb_util xcb"
+ "use": "xcb_shm xcb"
},
"xcb_keysyms": {
"label": "XCB Keysyms >= 0.3.9",
@@ -1065,7 +1056,6 @@
"tail": "#undef explicit",
"include": [
"xcb/xcb.h",
- "xcb/xcb_util.h",
"xcb/xcb_image.h",
"xcb/xcb_keysyms.h",
"xcb/randr.h",
@@ -1097,7 +1087,7 @@
"xcb_xkb_get_kbd_by_name_replies_key_names_value_list_sizeof(nullptr, 0, 0, 0, 0, 0, 0, 0, 0);"
]
},
- "use": "xcb_icccm xcb_util xcb_image xcb_keysyms xcb_randr xcb_render xcb_renderutil xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama xcb_xkb xcb"
+ "use": "xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_render xcb_renderutil xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama xcb_xkb xcb"
},
"x11prefix": {
"label": "X11 prefix",
@@ -1373,6 +1363,7 @@
"vkgen": {
"label": "vkgen",
"condition": "features.xmlstreamreader",
+ "disable": "input.vulkan == 'no'",
"output": [ "privateFeature" ]
},
"vulkan": {
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf
index d149caf069..dbdf1c9193 100644
--- a/src/gui/doc/qtgui.qdocconf
+++ b/src/gui/doc/qtgui.qdocconf
@@ -35,6 +35,7 @@ depends += \
qtnetwork \
qtopengl \
qtplatformheaders \
+ qtprintsupport \
qtsvg \
qtqml \
qtquick \
diff --git a/src/gui/doc/snippets/code/src_gui_painting_qtransform.cpp b/src/gui/doc/snippets/code/src_gui_painting_qtransform.cpp
index 4acc2f12b7..149265c083 100644
--- a/src/gui/doc/snippets/code/src_gui_painting_qtransform.cpp
+++ b/src/gui/doc/snippets/code/src_gui_painting_qtransform.cpp
@@ -51,7 +51,7 @@
//! [0]
x' = m11*x + m21*y + dx
y' = m22*y + m12*x + dy
-if (is not affine) {
+if (!isAffine()) {
w' = m13*x + m23*y + m33
x' /= w'
y' /= w'
@@ -62,7 +62,7 @@ if (is not affine) {
//! [1]
x' = m11*x + m21*y + dx
y' = m22*y + m12*x + dy
-if (is not affine) {
+if (!isAffine()) {
w' = m13*x + m23*y + m33
x' /= w'
y' /= w'
@@ -73,7 +73,7 @@ if (is not affine) {
//! [2]
x' = m11*x + m21*y + dx
y' = m22*y + m12*x + dy
-if (is not affine) {
+if (!isAffine()) {
w' = m13*x + m23*y + m33
x' /= w'
y' /= w'
@@ -84,7 +84,7 @@ if (is not affine) {
//! [3]
x' = m11*x + m21*y + dx
y' = m22*y + m12*x + dy
-if (is not affine) {
+if (!isAffine()) {
w' = m13*x + m23*y + m33
x' /= w'
y' /= w'
diff --git a/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp b/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp
index 6527021dd6..5cb100c711 100644
--- a/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp
+++ b/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp
@@ -66,7 +66,7 @@ mailto:user@foo.com?subject=Test&body=Just a test
//! [1]
//! [2]
-QDesktopServices::openUrl(QUrl("file:///C:/Documents and Settings/All Users/Desktop", QUrl::TolerantMode));
+QDesktopServices::openUrl(QUrl("file:///C:/Program Files", QUrl::TolerantMode));
//! [2]
//! [3]
diff --git a/src/gui/doc/snippets/transform/main.cpp b/src/gui/doc/snippets/transform/main.cpp
index e30a3b63bf..5120709aef 100644
--- a/src/gui/doc/snippets/transform/main.cpp
+++ b/src/gui/doc/snippets/transform/main.cpp
@@ -47,8 +47,12 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#include <QApplication>
+#include <QMath>
+#include <QPainter>
+#include <QVBoxLayout>
+#include <QWidget>
-#include <QtGui>
#include <cmath>
class SimpleTransformation : public QWidget
@@ -103,18 +107,15 @@ class BasicOperations : public QWidget
//! [2]
void BasicOperations::paintEvent(QPaintEvent *)
{
- double pi = 3.14;
-
- double a = pi/180 * 45.0;
+ const double a = qDegreesToRadians(45.0);
double sina = sin(a);
double cosa = cos(a);
- QTransform translationTransform(1, 0, 0, 1, 50.0, 50.0);
- QTransform rotationTransform(cosa, sina, -sina, cosa, 0, 0);
- QTransform scalingTransform(0.5, 0, 0, 1.0, 0, 0);
+ QTransform scale(0.5, 0, 0, 1.0, 0, 0);
+ QTransform rotate(cosa, sina, -sina, cosa, 0, 0);
+ QTransform translate(1, 0, 0, 1, 50.0, 50.0);
- QTransform transform;
- transform = scalingTransform * rotationTransform * translationTransform;
+ QTransform transform = scale * rotate * translate;
QPainter painter(this);
painter.setPen(QPen(Qt::blue, 1, Qt::DashLine));
diff --git a/src/gui/doc/src/coordsys.qdoc b/src/gui/doc/src/coordsys.qdoc
index ed413b500f..4df7151750 100644
--- a/src/gui/doc/src/coordsys.qdoc
+++ b/src/gui/doc/src/coordsys.qdoc
@@ -119,7 +119,7 @@
\table
\header
- \li {3,1} QRectF
+ \li {2,1} QRectF
\row
\li \inlineimage qrect-diagram-zero.png
\li \inlineimage qrectf-diagram-one.png
diff --git a/src/gui/doc/src/external-resources.qdoc b/src/gui/doc/src/external-resources.qdoc
index 0addbb21cd..ce550b546b 100644
--- a/src/gui/doc/src/external-resources.qdoc
+++ b/src/gui/doc/src/external-resources.qdoc
@@ -32,7 +32,7 @@
*/
/*!
- \externalpage http://www.linux-foundation.org/en/Accessibility/IAccessible2
+ \externalpage https://accessibility.linuxfoundation.org/a11yspecs/ia2/docs/html/index.html
\title IAccessible2 Specification
*/
diff --git a/src/gui/image/qiconengineplugin.cpp b/src/gui/image/qiconengineplugin.cpp
index ca80ee50a7..74e9fcab6c 100644
--- a/src/gui/image/qiconengineplugin.cpp
+++ b/src/gui/image/qiconengineplugin.cpp
@@ -97,3 +97,5 @@ QIconEnginePlugin::~QIconEnginePlugin()
QT_END_NAMESPACE
+
+#include "moc_qiconengineplugin.cpp"
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index ced5a505eb..04e1a00429 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -182,7 +182,7 @@ QImageData::~QImageData()
data = nullptr;
}
-#if defined(_M_ARM)
+#if defined(_M_ARM) && defined(_MSC_VER)
#pragma optimize("", off)
#endif
@@ -312,7 +312,7 @@ bool QImageData::checkForAlphaPixels() const
return has_alpha_pixels;
}
-#if defined(_M_ARM)
+#if defined(_M_ARM) && defined(_MSC_VER)
#pragma optimize("", on)
#endif
@@ -1749,10 +1749,14 @@ void QImage::fill(uint pixel)
w, d->height, d->bytes_per_line);
return;
} else if (d->depth == 16) {
+ if (d->format == Format_RGB444)
+ pixel |= 0xf000;
qt_rectfill<quint16>(reinterpret_cast<quint16*>(d->data), pixel,
0, 0, d->width, d->height, d->bytes_per_line);
return;
} else if (d->depth == 24) {
+ if (d->format == Format_RGB666)
+ pixel |= 0xfc0000;
qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
0, 0, d->width, d->height, d->bytes_per_line);
return;
@@ -1821,6 +1825,8 @@ void QImage::fill(const QColor &color)
if (!d)
return;
+ QRgba64 opaque = color.rgba64();
+ opaque.setAlpha(65535);
switch (d->format) {
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
@@ -1839,12 +1845,10 @@ void QImage::fill(const QColor &color)
fill(ARGB2RGBA(qPremultiply(color.rgba())));
break;
case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- fill(qConvertRgb64ToRgb30<PixelOrderBGR>(color.rgba64()));
+ fill(qConvertRgb64ToRgb30<PixelOrderBGR>(opaque));
break;
case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- fill(qConvertRgb64ToRgb30<PixelOrderRGB>(color.rgba64()));
+ fill(qConvertRgb64ToRgb30<PixelOrderRGB>(opaque));
break;
case QImage::Format_RGB16:
fill((uint) qConvertRgb32To16(color.rgba()));
@@ -1867,19 +1871,18 @@ void QImage::fill(const QColor &color)
else
fill((uint) 0);
break;
- case QImage::Format_RGBX64: {
- QRgba64 c = color.rgba64();
- c.setAlpha(65535);
- qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), c,
+ case QImage::Format_RGBX64:
+ qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), opaque,
0, 0, d->width, d->height, d->bytes_per_line);
break;
-
- }
case QImage::Format_RGBA64:
- case QImage::Format_RGBA64_Premultiplied:
qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), color.rgba64(),
0, 0, d->width, d->height, d->bytes_per_line);
break;
+ case QImage::Format_RGBA64_Premultiplied:
+ qt_rectfill<quint64>(reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
+ 0, 0, d->width, d->height, d->bytes_per_line);
+ break;
default: {
QPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_Source);
@@ -2154,7 +2157,7 @@ static QImage convertWithPalette(const QImage &src, QImage::Format format,
QImage dest(src.size(), format);
dest.setColorTable(clut);
- QImageData::get(dest)->text = QImageData::get(src)->text;
+ copyMetadata(QImageData::get(dest), QImageData::get(src));
int h = src.height();
int w = src.width();
@@ -2255,6 +2258,7 @@ bool QImage::reinterpretAsFormat(Format format)
// In case detach() ran out of memory
if (!d) {
d = oldD;
+ d->ref.ref();
return false;
}
}
@@ -2494,7 +2498,7 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
((uint *)s)[x] = index_or_rgb;
return;
case Format_RGB16:
- ((quint16 *)s)[x] = qConvertRgb32To16(qUnpremultiply(index_or_rgb));
+ ((quint16 *)s)[x] = qConvertRgb32To16(index_or_rgb);
return;
case Format_RGBX8888:
((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
@@ -2515,6 +2519,10 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
case Format_A2RGB30_Premultiplied:
((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
return;
+ case Format_RGBA64:
+ case Format_RGBA64_Premultiplied:
+ ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
+ return;
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
@@ -2524,7 +2532,10 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
}
const QPixelLayout *layout = &qPixelLayouts[d->format];
- layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
+ if (!hasAlphaChannel())
+ layout->storeFromRGB32(s, &index_or_rgb, x, 1, nullptr, nullptr);
+ else
+ layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
}
/*!
@@ -2647,12 +2658,9 @@ void QImage::setPixelColor(int x, int y, const QColor &color)
((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c);
return;
case Format_RGBX64:
- ((QRgba64 *)s)[x] = color.rgba64();
- ((QRgba64 *)s)[x].setAlpha(65535);
- return;
case Format_RGBA64:
case Format_RGBA64_Premultiplied:
- ((QRgba64 *)s)[x] = color.rgba64();
+ ((QRgba64 *)s)[x] = c;
return;
default:
setPixel(x, y, c.toArgb32());
@@ -4686,6 +4694,8 @@ QImage QImage::smoothScaled(int w, int h) const {
static QImage rotated90(const QImage &image)
{
QImage out(image.height(), image.width(), image.format());
+ if (out.isNull())
+ return out;
copyMetadata(&out, image);
if (image.colorCount() > 0)
out.setColorTable(image.colorTable());
@@ -4714,6 +4724,8 @@ static QImage rotated180(const QImage &image)
return image.mirrored(true, true);
QImage out(image.width(), image.height(), image.format());
+ if (out.isNull())
+ return out;
copyMetadata(&out, image);
if (image.colorCount() > 0)
out.setColorTable(image.colorTable());
@@ -4726,6 +4738,8 @@ static QImage rotated180(const QImage &image)
static QImage rotated270(const QImage &image)
{
QImage out(image.height(), image.width(), image.format());
+ if (out.isNull())
+ return out;
copyMetadata(&out, image);
if (image.colorCount() > 0)
out.setColorTable(image.colorTable());
@@ -4967,7 +4981,8 @@ void QImage::convertToColorSpace(const QColorSpace &colorSpace)
qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
return;
}
- detach();
+ if (d->colorSpace == colorSpace)
+ return;
applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));
d->colorSpace = colorSpace;
}
@@ -5009,6 +5024,14 @@ QColorSpace QImage::colorSpace() const
*/
void QImage::applyColorTransform(const QColorTransform &transform)
{
+ detach();
+ if (!d)
+ return;
+ if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
+ for (int i = 0; i < d->colortable.size(); ++i)
+ d->colortable[i] = transform.map(d->colortable[i]);
+ return;
+ }
QImage::Format oldFormat = format();
if (depth() > 32) {
if (format() != QImage::Format_RGBX64 && format() != QImage::Format_RGBA64
@@ -5044,14 +5067,14 @@ void QImage::applyColorTransform(const QColorTransform &transform)
if (depth() > 32) {
transformSegment = [&](int yStart, int yEnd) {
for (int y = yStart; y < yEnd; ++y) {
- QRgba64 *scanline = reinterpret_cast<QRgba64 *>(scanLine(y));
+ QRgba64 *scanline = reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
transform.d->apply(scanline, scanline, width(), flags);
}
};
} else {
transformSegment = [&](int yStart, int yEnd) {
for (int y = yStart; y < yEnd; ++y) {
- QRgb *scanline = reinterpret_cast<QRgb *>(scanLine(y));
+ QRgb *scanline = reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
transform.d->apply(scanline, scanline, width(), flags);
}
};
@@ -5061,7 +5084,7 @@ void QImage::applyColorTransform(const QColorTransform &transform)
int segments = sizeInBytes() / (1<<16);
segments = std::min(segments, height());
QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
@@ -5640,3 +5663,5 @@ QMap<QString, QString> qt_getImageTextFromDescription(const QString &description
}
QT_END_NAMESPACE
+
+#include "moc_qimage.cpp"
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index e804b3b788..9257ab8cfe 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -237,7 +237,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments <= 1 || threadPool->contains(QThread::currentThread()))
+ if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height);
QSemaphore semaphore;
@@ -292,7 +292,7 @@ void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::Image
segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments <= 1 || threadPool->contains(QThread::currentThread()))
+ if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height);
QSemaphore semaphore;
@@ -399,7 +399,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
int segments = data->nbytes / (1<<16);
segments = std::min(segments, data->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp
index 9dbcb11db5..c17f76f2b0 100644
--- a/src/gui/image/qimage_neon.cpp
+++ b/src/gui/image/qimage_neon.cpp
@@ -54,7 +54,7 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, cons
// align dst on 128 bits
const int offsetToAlignOn16Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x3;
- for (int i = 0; i < offsetToAlignOn16Bytes; ++i) {
+ for (int i = 0; i < qMin(len, offsetToAlignOn16Bytes); ++i) {
*dst++ = qRgb(src[0], src[1], src[2]);
src += 3;
}
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index 03ec43eaf7..b272377fb2 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -167,7 +167,7 @@ void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionF
const uchar *qt_get_bitflip_array();
Q_GUI_EXPORT void qGamma_correct_back_to_linear_cs(QImage *image);
-#if defined(_M_ARM) // QTBUG-42038
+#if defined(_M_ARM) && defined(_MSC_VER) // QTBUG-42038
#pragma optimize("", off)
#endif
inline int qt_depthForFormat(QImage::Format format)
@@ -222,7 +222,7 @@ inline int qt_depthForFormat(QImage::Format format)
return depth;
}
-#if defined(_M_ARM)
+#if defined(_M_ARM) && defined(_MSC_VER)
#pragma optimize("", on)
#endif
@@ -249,14 +249,38 @@ inline QImage::Format qt_opaqueVersion(QImage::Format format)
return QImage::Format_RGBX64;
case QImage::Format_ARGB32_Premultiplied:
case QImage::Format_ARGB32:
- default:
return QImage::Format_RGB32;
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB32:
+ case QImage::Format_RGB444:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB666:
+ case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
+ case QImage::Format_RGBX8888:
+ case QImage::Format_BGR30:
+ case QImage::Format_RGB30:
+ case QImage::Format_RGBX64:
+ case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
+ return format;
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ case QImage::Format_Alpha8:
+ case QImage::Format_Invalid:
+ case QImage::NImageFormats:
+ break;
}
+ return QImage::Format_RGB32;
}
inline QImage::Format qt_alphaVersion(QImage::Format format)
{
switch (format) {
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ return QImage::Format_ARGB32_Premultiplied;
case QImage::Format_RGB16:
return QImage::Format_ARGB8565_Premultiplied;
case QImage::Format_RGB555:
@@ -266,14 +290,35 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
case QImage::Format_RGB444:
return QImage::Format_ARGB4444_Premultiplied;
case QImage::Format_RGBX8888:
+ case QImage::Format_RGBA8888:
return QImage::Format_RGBA8888_Premultiplied;
case QImage::Format_BGR30:
return QImage::Format_A2BGR30_Premultiplied;
case QImage::Format_RGB30:
return QImage::Format_A2RGB30_Premultiplied;
case QImage::Format_RGBX64:
+ case QImage::Format_RGBA64:
+ case QImage::Format_Grayscale16:
return QImage::Format_RGBA64_Premultiplied;
- default:
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::Format_RGBA8888_Premultiplied:
+ case QImage::Format_A2BGR30_Premultiplied:
+ case QImage::Format_A2RGB30_Premultiplied:
+ case QImage::Format_RGBA64_Premultiplied:
+ return format;
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
+ case QImage::Format_Alpha8:
+ case QImage::Format_Grayscale8:
+ case QImage::Format_Invalid:
+ case QImage::NImageFormats:
break;
}
return QImage::Format_ARGB32_Premultiplied;
@@ -310,7 +355,11 @@ inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)
{
- return qt_opaqueVersion(format);
+ QImage::Format toFormat = qt_opaqueVersion(format);
+ // If we are switching depth anyway upgrade to RGB32
+ if (qt_depthForFormat(format) != qt_depthForFormat(toFormat) && qt_depthForFormat(toFormat) <= 32)
+ toFormat = QImage::Format_RGB32;
+ return toFormat;
}
inline QImage::Format qt_alphaVersionForPainting(QImage::Format format)
@@ -318,7 +367,7 @@ inline QImage::Format qt_alphaVersionForPainting(QImage::Format format)
QImage::Format toFormat = qt_alphaVersion(format);
#if defined(__ARM_NEON__) || defined(__SSE2__)
// If we are switching depth anyway and we have optimized ARGB32PM routines, upgrade to that.
- if (qt_depthForFormat(format) != qt_depthForFormat(toFormat))
+ if (qt_depthForFormat(format) != qt_depthForFormat(toFormat) && qt_depthForFormat(toFormat) <= 32)
toFormat = QImage::Format_ARGB32_Premultiplied;
#endif
return toFormat;
diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp
index 0c9083a16e..1be0dfff78 100644
--- a/src/gui/image/qimageiohandler.cpp
+++ b/src/gui/image/qimageiohandler.cpp
@@ -618,3 +618,5 @@ QImageIOPlugin::~QImageIOPlugin()
#endif // QT_NO_IMAGEFORMATPLUGIN
QT_END_NAMESPACE
+
+#include "moc_qimageiohandler.cpp"
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 5cb7e1328e..12bba77512 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -47,7 +47,6 @@
\inmodule QtGui
\reentrant
\ingroup painting
- \ingroup io
The most common way to read images is through QImage and QPixmap's
constructors, or by calling QImage::load() and
@@ -515,9 +514,9 @@ QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq)
*/
QImageReaderPrivate::~QImageReaderPrivate()
{
+ delete handler;
if (deleteDevice)
delete device;
- delete handler;
}
/*!
@@ -774,12 +773,12 @@ bool QImageReader::decideFormatFromContent() const
*/
void QImageReader::setDevice(QIODevice *device)
{
+ delete d->handler;
+ d->handler = nullptr;
if (d->device && d->deleteDevice)
delete d->device;
d->device = device;
d->deleteDevice = false;
- delete d->handler;
- d->handler = nullptr;
d->text.clear();
}
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index 33f5e491c7..feb05413c2 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -45,7 +45,6 @@
\inmodule QtGui
\reentrant
\ingroup painting
- \ingroup io
QImageWriter supports setting format specific options, such as
compression level and quality, prior to storing the
@@ -349,9 +348,9 @@ QImageWriter::QImageWriter(const QString &fileName, const QByteArray &format)
*/
QImageWriter::~QImageWriter()
{
+ delete d->handler;
if (d->deleteDevice)
delete d->device;
- delete d->handler;
delete d;
}
@@ -396,13 +395,13 @@ QByteArray QImageWriter::format() const
*/
void QImageWriter::setDevice(QIODevice *device)
{
+ delete d->handler;
+ d->handler = nullptr;
if (d->device && d->deleteDevice)
delete d->device;
d->device = device;
d->deleteDevice = false;
- delete d->handler;
- d->handler = nullptr;
}
/*!
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 9ea1e18c45..a9cc404256 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -926,6 +926,7 @@ void QPixmap::fill(const QColor &color)
// it will be filled with new pixel data anyway.
QPlatformPixmap *d = data->createCompatiblePlatformPixmap();
d->resize(data->width(), data->height());
+ d->setDevicePixelRatio(data->devicePixelRatio());
data = d;
}
data->fill(color);
diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp
index 9709df9e0c..b6e5e70f55 100644
--- a/src/gui/image/qpixmapcache.cpp
+++ b/src/gui/image/qpixmapcache.cpp
@@ -461,6 +461,11 @@ void QPMCache::clear()
for (int i = 0; i < keys.size(); ++i)
keys.at(i).d->isValid = false;
QCache<QPixmapCache::Key, QPixmapCacheEntry>::clear();
+ // Nothing left to flush; stop the timer
+ if (theid) {
+ killTimer(theid);
+ theid = 0;
+ }
}
QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key)
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index 6807ce937a..2811d2e049 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -612,7 +612,7 @@ bool QPngHandlerPrivate::readPngHeader()
png_get_iCCP(png_ptr, info_ptr, &name, &compressionType, &profileData, &profLen);
colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen));
if (!colorSpace.isValid()) {
- qWarning() << "QPngHandler: Failed to parse ICC profile";
+ qDebug() << "QPngHandler: Failed to parse ICC profile";
} else {
QColorSpacePrivate *csD = QColorSpacePrivate::getWritable(colorSpace);
if (csD->description.isEmpty())
@@ -649,10 +649,10 @@ bool QPngHandlerPrivate::readPngHeader()
}
if (primaries.areValid()) {
colorSpace = QColorSpace(primaries.whitePoint, primaries.redPoint, primaries.greenPoint, primaries.bluePoint,
- QColorSpace::TransferFunction::Gamma, fileGamma);
+ QColorSpace::TransferFunction::Gamma, 1.0f / fileGamma);
} else {
colorSpace = QColorSpace(QColorSpace::Primaries::SRgb,
- QColorSpace::TransferFunction::Gamma, fileGamma);
+ QColorSpace::TransferFunction::Gamma, 1.0f / fileGamma);
}
colorSpaceState = GammaChrm;
}
diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp
index 728259ba9e..b03458bdd9 100644
--- a/src/gui/image/qppmhandler.cpp
+++ b/src/gui/image/qppmhandler.cpp
@@ -63,7 +63,7 @@ static void discard_pbm_line(QIODevice *d)
} while (res > 0 && buf[res-1] != '\n');
}
-static int read_pbm_int(QIODevice *d)
+static int read_pbm_int(QIODevice *d, bool *ok)
{
char c;
int val = -1;
@@ -97,6 +97,8 @@ static int read_pbm_int(QIODevice *d)
else
break;
}
+ if (val < 0)
+ *ok = false;
return hasOverflow ? -1 : val;
}
@@ -113,16 +115,17 @@ static bool read_pbm_header(QIODevice *device, char& type, int& w, int& h, int&
if (type < '1' || type > '6')
return false;
- w = read_pbm_int(device); // get image width
- h = read_pbm_int(device); // get image height
+ bool ok = true;
+ w = read_pbm_int(device, &ok); // get image width
+ h = read_pbm_int(device, &ok); // get image height
if (type == '1' || type == '4')
mcc = 1; // ignore max color component
else
- mcc = read_pbm_int(device); // get max color component
+ mcc = read_pbm_int(device, &ok); // get max color component
- if (w <= 0 || w > 32767 || h <= 0 || h > 32767 || mcc <= 0 || mcc > 0xffff)
- return false; // weird P.M image
+ if (!ok || w <= 0 || w > 32767 || h <= 0 || h > 32767 || mcc <= 0 || mcc > 0xffff)
+ return false; // weird P.M image
return true;
}
@@ -233,18 +236,18 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
} else { // read ascii data
uchar *p;
int n;
- char buf;
- for (y = 0; (y < h) && (device->peek(&buf, 1) == 1); y++) {
+ bool ok = true;
+ for (y = 0; y < h && ok; y++) {
p = outImage->scanLine(y);
n = pbm_bpl;
if (nbits == 1) {
int b;
int bitsLeft = w;
- while (n--) {
+ while (n-- && ok) {
b = 0;
for (int i=0; i<8; i++) {
if (i < bitsLeft)
- b = (b << 1) | (read_pbm_int(device) & 1);
+ b = (b << 1) | (read_pbm_int(device, &ok) & 1);
else
b = (b << 1) | (0 & 1); // pad it our self if we need to
}
@@ -253,36 +256,38 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
}
} else if (nbits == 8) {
if (mcc == 255) {
- while (n--) {
- *p++ = read_pbm_int(device);
+ while (n-- && ok) {
+ *p++ = read_pbm_int(device, &ok);
}
} else {
- while (n--) {
- *p++ = (read_pbm_int(device) & 0xffff) * 255 / mcc;
+ while (n-- && ok) {
+ *p++ = (read_pbm_int(device, &ok) & 0xffff) * 255 / mcc;
}
}
} else { // 32 bits
n /= 4;
int r, g, b;
if (mcc == 255) {
- while (n--) {
- r = read_pbm_int(device);
- g = read_pbm_int(device);
- b = read_pbm_int(device);
+ while (n-- && ok) {
+ r = read_pbm_int(device, &ok);
+ g = read_pbm_int(device, &ok);
+ b = read_pbm_int(device, &ok);
*((QRgb*)p) = qRgb(r, g, b);
p += 4;
}
} else {
- while (n--) {
- r = read_pbm_int(device);
- g = read_pbm_int(device);
- b = read_pbm_int(device);
+ while (n-- && ok) {
+ r = read_pbm_int(device, &ok);
+ g = read_pbm_int(device, &ok);
+ b = read_pbm_int(device, &ok);
*((QRgb*)p) = scale_pbm_color(mcc, r, g, b);
p += 4;
}
}
}
}
+ if (!ok)
+ return false;
}
if (format == QImage::Format_Mono) {
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index 8acc80776c..f78a7fee81 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -50,6 +50,7 @@
#include <qvariant.h>
#include <algorithm>
+#include <array>
QT_BEGIN_NAMESPACE
@@ -924,7 +925,7 @@ static bool read_xpm_body(
colorMap.insert(xpmHash(QLatin1String(index.constData())), 0);
}
} else {
- QRgb c_rgb;
+ QRgb c_rgb = 0;
if (((buf.length()-1) % 3) && (buf[0] == '#')) {
buf.truncate(((buf.length()-1) / 4 * 3) + 1); // remove alpha channel left by imagemagick
}
@@ -1056,15 +1057,23 @@ bool qt_read_xpm_image_or_array(QIODevice *device, const char * const * source,
return read_xpm_body(device, source, index, state, cpp, ncols, w, h, image);
}
-static const char* xpm_color_name(int cpp, int index)
+namespace {
+template <size_t N>
+struct CharBuffer : std::array<char, N>
+{
+ CharBuffer() {} // avoid value-initializing the whole array
+};
+}
+
+static const char* xpm_color_name(int cpp, int index, CharBuffer<5> && returnable = {})
{
- static char returnable[5];
static const char code[] = ".#abcdefghijklmnopqrstuvwxyzABCD"
"EFGHIJKLMNOPQRSTUVWXYZ0123456789";
// cpp is limited to 4 and index is limited to 64^cpp
if (cpp > 1) {
if (cpp > 2) {
if (cpp > 3) {
+ returnable[4] = '\0';
returnable[3] = code[index % 64];
index /= 64;
} else
@@ -1084,7 +1093,7 @@ static const char* xpm_color_name(int cpp, int index)
returnable[1] = '\0';
returnable[0] = code[index];
- return returnable;
+ return returnable.data();
}
@@ -1121,8 +1130,11 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const
++cpp;
// limit to 4 characters per pixel
// 64^4 colors is enough for a 4096x4096 image
- if (cpp > 4)
- break;
+ if (cpp > 4) {
+ qWarning("Qt does not support writing XPM images with more than "
+ "64^4 colors (requested: %d colors).", ncolors);
+ return false;
+ }
}
// write header
@@ -1150,16 +1162,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const
const QRgb *yp = reinterpret_cast<const QRgb *>(image.constScanLine(y));
for(x=0; x<w; x++) {
int color = (int)(*(yp + x));
- const QByteArray chars(xpm_color_name(cpp, colorMap[color]));
- line.append(chars[0]);
- if (cpp > 1) {
- line.append(chars[1]);
- if (cpp > 2) {
- line.append(chars[2]);
- if (cpp > 3)
- line.append(chars[3]);
- }
- }
+ line.append(xpm_color_name(cpp, colorMap[color]));
}
s << ',' << Qt::endl << '\"' << line << '\"';
}
diff --git a/src/gui/kernel/qclipboard.cpp b/src/gui/kernel/qclipboard.cpp
index db22ef2486..7158d96c86 100644
--- a/src/gui/kernel/qclipboard.cpp
+++ b/src/gui/kernel/qclipboard.cpp
@@ -150,6 +150,10 @@ QT_BEGIN_NAMESPACE
\endlist
+ \section1 Notes for Android Users
+
+ On Android only these mime types are supported: text/plain, text/html, and text/uri-list.
+
\sa QGuiApplication
*/
@@ -610,4 +614,6 @@ void QClipboard::emitChanged(Mode mode)
QT_END_NAMESPACE
+#include "moc_qclipboard.cpp"
+
#endif // QT_NO_CLIPBOARD
diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp
index 1efa28a5af..455088241c 100644
--- a/src/gui/kernel/qcursor.cpp
+++ b/src/gui/kernel/qcursor.cpp
@@ -251,7 +251,8 @@ void QCursor::setPos(QScreen *screen, int x, int y)
{
if (screen) {
if (QPlatformCursor *cursor = screen->handle()->cursor()) {
- const QPoint devicePos = QHighDpi::toNativePixels(QPoint(x, y), screen);
+ const QPoint pos(x, y);
+ const QPoint devicePos = QHighDpi::toNativePixels(pos, screen->virtualSiblingAt(pos));
// Need to check, since some X servers generate null mouse move
// events, causing looping in applications which call setPos() on
// every mouse move event.
@@ -529,8 +530,7 @@ bool operator==(const QCursor &lhs, const QCursor &rhs) noexcept
*/
/*!
- Returns the cursor shape identifier. The return value is one of
- the \l Qt::CursorShape enum values (cast to an int).
+ Returns the cursor shape identifier.
\sa setShape()
*/
diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp
index fe766c900e..ecf8b3f4ce 100644
--- a/src/gui/kernel/qdnd.cpp
+++ b/src/gui/kernel/qdnd.cpp
@@ -123,3 +123,5 @@ Qt::DropAction QDragManager::drag(QDrag *o)
}
QT_END_NAMESPACE
+
+#include "moc_qdnd_p.cpp"
diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp
index 3712eace15..ee4b816e72 100644
--- a/src/gui/kernel/qdrag.cpp
+++ b/src/gui/kernel/qdrag.cpp
@@ -423,3 +423,5 @@ void QDrag::cancel()
*/
QT_END_NAMESPACE
+
+#include "moc_qdrag.cpp"
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index a6da24e4b2..542f3e3217 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -5320,3 +5320,5 @@ uint qHash(QPointingDeviceUniqueId key, uint seed) noexcept
}
QT_END_NAMESPACE
+
+#include "moc_qevent.cpp"
diff --git a/src/gui/kernel/qgenericplugin.cpp b/src/gui/kernel/qgenericplugin.cpp
index a53b60b008..7ecdc72d97 100644
--- a/src/gui/kernel/qgenericplugin.cpp
+++ b/src/gui/kernel/qgenericplugin.cpp
@@ -94,3 +94,5 @@ QGenericPlugin::~QGenericPlugin()
*/
QT_END_NAMESPACE
+
+#include "moc_qgenericplugin.cpp"
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 239a78313c..c7ff2a6dac 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -61,7 +61,7 @@
#include <QtCore/private/qlocking_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qnumeric.h>
+#include <QtCore/private/qnumeric_p.h>
#include <QtDebug>
#ifndef QT_NO_ACCESSIBILITY
#include "qaccessible.h"
@@ -140,7 +140,7 @@ Q_GUI_EXPORT bool qt_is_gui_used = true;
Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
-QPointF QGuiApplicationPrivate::lastCursorPosition(qInf(), qInf());
+QPointF QGuiApplicationPrivate::lastCursorPosition(qt_inf(), qt_inf());
QWindow *QGuiApplicationPrivate::currentMouseWindow = nullptr;
@@ -201,7 +201,7 @@ static bool force_reverse = false;
QGuiApplicationPrivate *QGuiApplicationPrivate::self = nullptr;
QTouchDevice *QGuiApplicationPrivate::m_fakeTouchDevice = nullptr;
-int QGuiApplicationPrivate::m_fakeMouseSourcePointId = 0;
+int QGuiApplicationPrivate::m_fakeMouseSourcePointId = -1;
#ifndef QT_NO_CLIPBOARD
QClipboard *QGuiApplicationPrivate::qt_clipboard = nullptr;
@@ -1316,7 +1316,10 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
}
#endif
- fontSmoothingGamma = QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
+ const auto platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ fontSmoothingGamma = platformIntegration->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
+ QCoreApplication::setAttribute(Qt::AA_DontShowShortcutsInContextMenus,
+ !platformIntegration->styleHint(QPlatformIntegration::ShowShortcutsInContextMenus).toBool());
}
static void init_plugins(const QList<QByteArray> &pluginList)
@@ -1382,11 +1385,11 @@ void QGuiApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options)
QGuiApplication::tr("ID of the X11 Visual to use."), QStringLiteral("id")));
// Not using the "QStringList names" solution for those aliases, because it makes the first column too wide
options->append(QCommandLineOption(QStringLiteral("geometry"),
- QGuiApplication::tr("Alias for --windowgeometry."), QStringLiteral("geometry")));
+ QGuiApplication::tr("Alias for --qwindowgeometry."), QStringLiteral("geometry")));
options->append(QCommandLineOption(QStringLiteral("icon"),
- QGuiApplication::tr("Alias for --windowicon."), QStringLiteral("icon")));
+ QGuiApplication::tr("Alias for --qwindowicon."), QStringLiteral("icon")));
options->append(QCommandLineOption(QStringLiteral("title"),
- QGuiApplication::tr("Alias for --windowtitle."), QStringLiteral("title")));
+ QGuiApplication::tr("Alias for --qwindowtitle."), QStringLiteral("title")));
}
}
#endif // QT_CONFIG(commandlineparser)
@@ -2131,6 +2134,11 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
bool mouseMove = false;
bool mousePress = false;
+ if (qIsNaN(e->globalPos.x()) || qIsNaN(e->globalPos.y())) {
+ qWarning("QGuiApplicationPrivate::processMouseEvent: Got NaN in mouse position");
+ return;
+ }
+
if (e->enhancedMouseEvent()) {
type = e->buttonType;
button = e->button;
@@ -2151,7 +2159,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
processMouseEvent(e); // the original mouse event
return;
}
- if (mouseMove && !positionChanged) {
+ if (type == QEvent::MouseMove && !positionChanged) {
// On Windows, and possibly other platforms, a touchpad can send a mouse move
// that does not change position, between a press and a release. This may
// confuse applications, so we always filter out these mouse events for
@@ -3052,32 +3060,32 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) {
// exclude devices which generate their own mouse events
if (!(touchEvent.device()->capabilities() & QTouchDevice::MouseEmulation)) {
-
- if (eventType == QEvent::TouchEnd)
- self->synthesizedMousePoints.clear();
-
const QList<QTouchEvent::TouchPoint> &touchPoints = touchEvent.touchPoints();
- if (eventType == QEvent::TouchBegin)
+ QEvent::Type mouseEventType = QEvent::MouseMove;
+ Qt::MouseButton button = Qt::NoButton;
+ Qt::MouseButtons buttons = Qt::LeftButton;
+ if (eventType == QEvent::TouchBegin || m_fakeMouseSourcePointId < 0)
m_fakeMouseSourcePointId = touchPoints.first().id();
-
- const QEvent::Type mouseType = [&]() {
- switch (eventType) {
- case QEvent::TouchBegin: return QEvent::MouseButtonPress;
- case QEvent::TouchUpdate: return QEvent::MouseMove;
- case QEvent::TouchEnd: return QEvent::MouseButtonRelease;
- default: Q_UNREACHABLE();
- }
- }();
-
- Qt::MouseButton button = mouseType == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton;
- Qt::MouseButtons buttons = mouseType == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton;
-
- for (int i = 0; i < touchPoints.count(); ++i) {
- const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
+ for (const auto &touchPoint : touchPoints) {
if (touchPoint.id() == m_fakeMouseSourcePointId) {
- if (eventType != QEvent::TouchEnd)
+ switch (touchPoint.state()) {
+ case Qt::TouchPointPressed:
+ mouseEventType = QEvent::MouseButtonPress;
+ button = Qt::LeftButton;
+ break;
+ case Qt::TouchPointReleased:
+ mouseEventType = QEvent::MouseButtonRelease;
+ button = Qt::LeftButton;
+ buttons = Qt::NoButton;
+ m_fakeMouseSourcePointId = -1;
+ break;
+ default:
+ break;
+ }
+ if (touchPoint.state() != Qt::TouchPointReleased) {
self->synthesizedMousePoints.insert(w, SynthesizedMouseData(
touchPoint.pos(), touchPoint.screenPos(), w));
+ }
// All touch events that are not accepted by the application will be translated to
// left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp,
@@ -3086,13 +3094,15 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
buttons,
e->modifiers,
button,
- mouseType,
+ mouseEventType,
Qt::MouseEventSynthesizedByQt);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
processMouseEvent(&fake);
break;
}
}
+ if (eventType == QEvent::TouchEnd)
+ self->synthesizedMousePoints.clear();
}
}
}
@@ -3162,13 +3172,14 @@ void QGuiApplicationPrivate::processScreenGeometryChange(QWindowSystemInterfaceP
bool availableGeometryChanged = e->availableGeometry != s->d_func()->availableGeometry;
s->d_func()->availableGeometry = e->availableGeometry;
- if (geometryChanged) {
- Qt::ScreenOrientation primaryOrientation = s->primaryOrientation();
+ const Qt::ScreenOrientation primaryOrientation = s->primaryOrientation();
+ if (geometryChanged)
s->d_func()->updatePrimaryOrientation();
- emit s->geometryChanged(s->geometry());
+ s->d_func()->emitGeometryChangeSignals(geometryChanged, availableGeometryChanged);
+
+ if (geometryChanged) {
emit s->physicalSizeChanged(s->physicalSize());
- emit s->physicalDotsPerInchChanged(s->physicalDotsPerInch());
emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
if (s->primaryOrientation() != primaryOrientation)
@@ -3178,8 +3189,6 @@ void QGuiApplicationPrivate::processScreenGeometryChange(QWindowSystemInterfaceP
updateFilteredScreenOrientation(s);
}
- s->d_func()->emitGeometryChangeSignals(geometryChanged, availableGeometryChanged);
-
resetCachedDevicePixelRatio();
}
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index 9bbf2773a9..85ff58c14c 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -726,3 +726,5 @@ QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QWindow *w
#endif //QT_NO_HIGHDPISCALING
QT_END_NAMESPACE
+
+#include "moc_qhighdpiscaling_p.cpp"
diff --git a/src/gui/kernel/qinputdevicemanager.cpp b/src/gui/kernel/qinputdevicemanager.cpp
index 11442407e1..13e32a08f9 100644
--- a/src/gui/kernel/qinputdevicemanager.cpp
+++ b/src/gui/kernel/qinputdevicemanager.cpp
@@ -116,3 +116,5 @@ void QInputDeviceManager::setKeyboardModifiers(Qt::KeyboardModifiers mods)
}
QT_END_NAMESPACE
+
+#include "moc_qinputdevicemanager_p.cpp"
diff --git a/src/gui/kernel/qinternalmimedata.cpp b/src/gui/kernel/qinternalmimedata.cpp
index d5cdc743ee..a2b47879cc 100644
--- a/src/gui/kernel/qinternalmimedata.cpp
+++ b/src/gui/kernel/qinternalmimedata.cpp
@@ -233,3 +233,5 @@ QByteArray QInternalMimeData::renderDataHelper(const QString &mimeType, const QM
}
QT_END_NAMESPACE
+
+#include "moc_qinternalmimedata_p.cpp"
diff --git a/src/gui/kernel/qkeymapper.cpp b/src/gui/kernel/qkeymapper.cpp
index 274574f561..38180105e0 100644
--- a/src/gui/kernel/qkeymapper.cpp
+++ b/src/gui/kernel/qkeymapper.cpp
@@ -147,3 +147,5 @@ QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
}
QT_END_NAMESPACE
+
+#include "moc_qkeymapper_p.cpp"
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index a75b8ef920..56cd2d02bc 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -73,8 +73,7 @@ static const int kControlUnicode = 0x2303;
static const int kOptionUnicode = 0x2325;
static const int kCommandUnicode = 0x2318;
-static const int NumEntries = 21;
-static const MacSpecialKey entries[NumEntries] = {
+static const MacSpecialKey entries[] = {
{ Qt::Key_Escape, 0x238B },
{ Qt::Key_Tab, 0x21E5 },
{ Qt::Key_Backtab, 0x21E4 },
@@ -96,6 +95,7 @@ static const MacSpecialKey entries[NumEntries] = {
{ Qt::Key_Alt, kOptionUnicode },
{ Qt::Key_CapsLock, 0x21EA },
};
+static const int NumEntries = sizeof entries / sizeof *entries;
static bool operator<(const MacSpecialKey &entry, int key)
{
@@ -1693,3 +1693,5 @@ QDebug operator<<(QDebug dbg, const QKeySequence &p)
*/
QT_END_NAMESPACE
+
+#include "moc_qkeysequence.cpp"
diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp
index c74fe0b3a1..ae7bc33291 100644
--- a/src/gui/kernel/qoffscreensurface.cpp
+++ b/src/gui/kernel/qoffscreensurface.cpp
@@ -435,3 +435,5 @@ QPlatformSurface *QOffscreenSurface::surfaceHandle() const
}
QT_END_NAMESPACE
+
+#include "moc_qoffscreensurface.cpp"
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 927e9cb94a..2291bfe70f 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -1031,7 +1031,8 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
|| qstrcmp(rendererString, "GC800 core") == 0
|| qstrcmp(rendererString, "GC1000 core") == 0
|| strstr(rendererString, "GC2000") != nullptr
- || qstrcmp(rendererString, "Immersion.16") == 0;
+ || qstrcmp(rendererString, "Immersion.16") == 0
+ || qstrncmp(rendererString, "Apple Mx", 7) == 0;
}
needsWorkaroundSet = true;
}
diff --git a/src/gui/kernel/qpaintdevicewindow.cpp b/src/gui/kernel/qpaintdevicewindow.cpp
index 4f45fc5fde..0ba52cc7ab 100644
--- a/src/gui/kernel/qpaintdevicewindow.cpp
+++ b/src/gui/kernel/qpaintdevicewindow.cpp
@@ -223,3 +223,5 @@ QPaintEngine *QPaintDeviceWindow::paintEngine() const
}
QT_END_NAMESPACE
+
+#include "moc_qpaintdevicewindow.cpp"
diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp
index 397c50f3dc..a192b7aef4 100644
--- a/src/gui/kernel/qpalette.cpp
+++ b/src/gui/kernel/qpalette.cpp
@@ -531,7 +531,10 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
*/
/*!
- Constructs a palette object that uses the application's default palette.
+ Constructs an empty palette object with no color roles set.
+
+ When used as the palette of a QWidget the colors are resolved
+ as described by QWidget::setPalette().
\sa QApplication::setPalette(), QApplication::palette()
*/
@@ -1231,3 +1234,5 @@ QDebug operator<<(QDebug dbg, const QPalette &p)
#endif
QT_END_NAMESPACE
+
+#include "moc_qpalette.cpp"
diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp
index 33cd004234..4ca5421bc1 100644
--- a/src/gui/kernel/qplatformdialoghelper.cpp
+++ b/src/gui/kernel/qplatformdialoghelper.cpp
@@ -1012,3 +1012,5 @@ void QPlatformMessageDialogHelper::setOptions(const QSharedPointer<QMessageDialo
}
QT_END_NAMESPACE
+
+#include "moc_qplatformdialoghelper.cpp"
diff --git a/src/gui/kernel/qplatformgraphicsbuffer.cpp b/src/gui/kernel/qplatformgraphicsbuffer.cpp
index 73ec033e19..371fd543be 100644
--- a/src/gui/kernel/qplatformgraphicsbuffer.cpp
+++ b/src/gui/kernel/qplatformgraphicsbuffer.cpp
@@ -274,3 +274,5 @@ QPlatformGraphicsBuffer::Origin QPlatformGraphicsBuffer::origin() const
*/
QT_END_NAMESPACE
+
+#include "moc_qplatformgraphicsbuffer.cpp"
diff --git a/src/gui/kernel/qplatforminputcontext.cpp b/src/gui/kernel/qplatforminputcontext.cpp
index 9771e6ba11..5b6b2d11d8 100644
--- a/src/gui/kernel/qplatforminputcontext.cpp
+++ b/src/gui/kernel/qplatforminputcontext.cpp
@@ -298,3 +298,5 @@ void QPlatformInputContext::setSelectionOnFocusObject(const QPointF &anchorPos,
}
QT_END_NAMESPACE
+
+#include "moc_qplatforminputcontext.cpp"
diff --git a/src/gui/kernel/qplatforminputcontextplugin.cpp b/src/gui/kernel/qplatforminputcontextplugin.cpp
index 53d56dbb48..48be855743 100644
--- a/src/gui/kernel/qplatforminputcontextplugin.cpp
+++ b/src/gui/kernel/qplatforminputcontextplugin.cpp
@@ -51,3 +51,5 @@ QPlatformInputContextPlugin::~QPlatformInputContextPlugin()
}
QT_END_NAMESPACE
+
+#include "moc_qplatforminputcontextplugin_p.cpp"
diff --git a/src/gui/kernel/qplatformintegrationplugin.cpp b/src/gui/kernel/qplatformintegrationplugin.cpp
index b100eacbb5..fd4abcd791 100644
--- a/src/gui/kernel/qplatformintegrationplugin.cpp
+++ b/src/gui/kernel/qplatformintegrationplugin.cpp
@@ -65,3 +65,5 @@ QPlatformIntegration *QPlatformIntegrationPlugin::create(const QString &key, con
}
QT_END_NAMESPACE
+
+#include "moc_qplatformintegrationplugin.cpp"
diff --git a/src/gui/kernel/qplatformmenu.cpp b/src/gui/kernel/qplatformmenu.cpp
index 0d76f2039d..5d7b3c1bab 100644
--- a/src/gui/kernel/qplatformmenu.cpp
+++ b/src/gui/kernel/qplatformmenu.cpp
@@ -92,3 +92,5 @@ QPlatformMenu *QPlatformMenuBar::createMenu() const
}
QT_END_NAMESPACE
+
+#include "moc_qplatformmenu.cpp"
diff --git a/src/gui/kernel/qplatformnativeinterface.cpp b/src/gui/kernel/qplatformnativeinterface.cpp
index 8c9e73fbc2..560ff24dfd 100644
--- a/src/gui/kernel/qplatformnativeinterface.cpp
+++ b/src/gui/kernel/qplatformnativeinterface.cpp
@@ -175,3 +175,5 @@ void QPlatformNativeInterface::setWindowProperty(QPlatformWindow *window, const
}
QT_END_NAMESPACE
+
+#include "moc_qplatformnativeinterface.cpp"
diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp
index 7c1e2158b1..952bcd7073 100644
--- a/src/gui/kernel/qplatformscreen.cpp
+++ b/src/gui/kernel/qplatformscreen.cpp
@@ -189,6 +189,8 @@ QDpi QPlatformScreen::logicalDpi() const
QSizeF ps = physicalSize();
QSize s = geometry().size();
+ if (qFuzzyIsNull(ps.width()) || qFuzzyIsNull(ps.height()))
+ return QDpi(96, 96);
return QDpi(25.4 * s.width() / ps.width(),
25.4 * s.height() / ps.height());
}
diff --git a/src/gui/kernel/qplatformsharedgraphicscache.cpp b/src/gui/kernel/qplatformsharedgraphicscache.cpp
index f6c4e3309e..f5e86c341d 100644
--- a/src/gui/kernel/qplatformsharedgraphicscache.cpp
+++ b/src/gui/kernel/qplatformsharedgraphicscache.cpp
@@ -292,3 +292,5 @@ QT_BEGIN_NAMESPACE
*/
QT_END_NAMESPACE
+
+#include "moc_qplatformsharedgraphicscache.cpp"
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index 71521c0339..a11388fdb6 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -748,7 +748,20 @@ QString QPlatformTheme::defaultStandardButtonText(int button)
QString QPlatformTheme::removeMnemonics(const QString &original)
{
- QString returnText(original.size(), 0);
+ const auto mnemonicInParentheses = [](QStringView text) {
+ /* Format of mnemonics to remove is /\(&[^&]\)/ but accept full-width
+ forms of ( and ) as equivalent, for cross-platform compatibility with
+ MS (and consequent behavior of translators, see QTBUG-110829).
+ */
+ Q_ASSERT(text.size() == 4); // Caller's responsibility.
+ const QChar wideOpen(0xff08), wideClose(0xff09), ampersand(QLatin1Char('&'));
+ if (!text.startsWith(QLatin1Char('(')) && !text.startsWith(wideOpen))
+ return false;
+ if (text[1] != ampersand || text[2] == ampersand)
+ return false;
+ return text.endsWith(QLatin1Char(')')) || text.endsWith(wideClose);
+ };
+ QString returnText(original.size(), QLatin1Char('\0'));
int finalDest = 0;
int currPos = 0;
int l = original.length();
@@ -758,11 +771,8 @@ QString QPlatformTheme::removeMnemonics(const QString &original)
--l;
if (l == 0)
break;
- } else if (original.at(currPos) == QLatin1Char('(') && l >= 4 &&
- original.at(currPos + 1) == QLatin1Char('&') &&
- original.at(currPos + 2) != QLatin1Char('&') &&
- original.at(currPos + 3) == QLatin1Char(')')) {
- /* remove mnemonics its format is "\s*(&X)" */
+ } else if (l >= 4 && mnemonicInParentheses(QStringView{original}.mid(currPos, 4))) {
+ // Also strip any leading space before the mnemonic:
int n = 0;
while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
++n;
diff --git a/src/gui/kernel/qplatformthemeplugin.cpp b/src/gui/kernel/qplatformthemeplugin.cpp
index c09476bee5..59c0731e8d 100644
--- a/src/gui/kernel/qplatformthemeplugin.cpp
+++ b/src/gui/kernel/qplatformthemeplugin.cpp
@@ -60,3 +60,5 @@ QPlatformThemePlugin::~QPlatformThemePlugin()
}
QT_END_NAMESPACE
+
+#include "moc_qplatformthemeplugin.cpp"
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index fc736033c2..7207ff4d7e 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -229,7 +229,7 @@ bool QPlatformWindow::isActive() const
*/
bool QPlatformWindow::isAncestorOf(const QPlatformWindow *child) const
{
- for (const QPlatformWindow *parent = child->parent(); parent; parent = child->parent()) {
+ for (const QPlatformWindow *parent = child->parent(); parent; parent = parent->parent()) {
if (parent == this)
return true;
}
@@ -664,16 +664,16 @@ void QPlatformWindow::invalidateSurface()
{
}
-static QSize fixInitialSize(QSize size, const QWindow *w,
- int defaultWidth, int defaultHeight)
+static QSize fixInitialSize(QSize size, const QWindow *w, int deviceIndependentDefaultWidth,
+ int deviceIndependentDefaultHeight)
{
if (size.width() == 0) {
const int minWidth = w->minimumWidth();
- size.setWidth(minWidth > 0 ? minWidth : defaultWidth);
+ size.setWidth(minWidth > 0 ? minWidth : deviceIndependentDefaultWidth);
}
if (size.height() == 0) {
const int minHeight = w->minimumHeight();
- size.setHeight(minHeight > 0 ? minHeight : defaultHeight);
+ size.setHeight(minHeight > 0 ? minHeight : deviceIndependentDefaultHeight);
}
return size;
}
@@ -686,6 +686,10 @@ static QSize fixInitialSize(QSize size, const QWindow *w,
layout new windows to optimize usage of the available desktop space.
However if the given window already has geometry which the application has
initialized, it takes priority.
+
+ \a initialGeometry has to be provided in native pixels.
+ \a defaultWidth has to be provided in device independent pixels
+ \a defaultHeight has to be provided in device independent pixels
*/
QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry,
int defaultWidth, int defaultHeight,
@@ -695,9 +699,10 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeo
*resultingScreenReturn = w->screen();
if (!w->isTopLevel()) {
const qreal factor = QHighDpiScaling::factor(w);
- const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor),
- w, defaultWidth, defaultHeight);
- return QRect(initialGeometry.topLeft(), QHighDpi::toNative(size, factor));
+ const QSize deviceIndependentSize =
+ fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor), w,
+ defaultWidth, defaultHeight);
+ return QRect(initialGeometry.topLeft(), QHighDpi::toNative(deviceIndependentSize, factor));
}
const auto *wp = qt_window_private(const_cast<QWindow*>(w));
const bool position = wp->positionAutomatic && w->type() != Qt::Popup;
@@ -711,26 +716,28 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeo
if (resultingScreenReturn)
*resultingScreenReturn = screen;
// initialGeometry refers to window's screen
- QRect rect(QHighDpi::fromNativePixels(initialGeometry, w));
+ QRect deviceIndependentRect(QHighDpi::fromNativePixels(initialGeometry, w));
if (wp->resizeAutomatic)
- rect.setSize(fixInitialSize(rect.size(), w, defaultWidth, defaultHeight));
+ deviceIndependentRect.setSize(
+ fixInitialSize(deviceIndependentRect.size(), w, defaultWidth, defaultHeight));
if (position) {
- const QRect availableGeometry = screen->availableGeometry();
+ const QRect availableDeviceIndependentGeometry = screen->availableGeometry();
// Center unless the geometry ( + unknown window frame) is too large for the screen).
- if (rect.height() < (availableGeometry.height() * 8) / 9
- && rect.width() < (availableGeometry.width() * 8) / 9) {
+ if (deviceIndependentRect.height() < (availableDeviceIndependentGeometry.height() * 8) / 9
+ && deviceIndependentRect.width()
+ < (availableDeviceIndependentGeometry.width() * 8) / 9) {
const QWindow *tp = w->transientParent();
if (tp) {
// A transient window should be centered w.r.t. its transient parent.
- rect.moveCenter(tp->geometry().center());
+ deviceIndependentRect.moveCenter(tp->geometry().center());
} else {
// Center the window on the screen. (Only applicable on platforms
// which do not provide a better way.)
- rect.moveCenter(availableGeometry.center());
+ deviceIndependentRect.moveCenter(availableDeviceIndependentGeometry.center());
}
}
}
- return QHighDpi::toNativePixels(rect, screen);
+ return QHighDpi::toNativePixels(deviceIndependentRect, screen);
}
/*!
diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp
index 70d87347c3..c45f9a4e11 100644
--- a/src/gui/kernel/qrasterwindow.cpp
+++ b/src/gui/kernel/qrasterwindow.cpp
@@ -139,3 +139,5 @@ QPaintDevice *QRasterWindow::redirected(QPoint *) const
}
QT_END_NAMESPACE
+
+#include "moc_qrasterwindow.cpp"
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index df628fcc73..990272b0c2 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -88,6 +88,9 @@ void QScreenPrivate::updateGeometriesWithSignals()
void QScreenPrivate::emitGeometryChangeSignals(bool geometryChanged, bool availableGeometryChanged)
{
Q_Q(QScreen);
+ if (geometryChanged)
+ emit q->geometryChanged(geometry);
+
if (availableGeometryChanged)
emit q->availableGeometryChanged(availableGeometry);
@@ -96,6 +99,9 @@ void QScreenPrivate::emitGeometryChangeSignals(bool geometryChanged, bool availa
for (QScreen* sibling : siblings)
emit sibling->virtualGeometryChanged(sibling->virtualGeometry());
}
+
+ if (geometryChanged)
+ emit q->physicalDotsPerInchChanged(q->physicalDotsPerInch());
}
void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen)
@@ -112,13 +118,13 @@ void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen)
if (refreshRate < 1.0)
refreshRate = 60.0;
- updatePrimaryOrientation();
+ updateHighDpi();
+
+ updatePrimaryOrientation(); // derived from the geometry
filteredOrientation = orientation;
if (filteredOrientation == Qt::PrimaryOrientation)
filteredOrientation = primaryOrientation;
-
- updateHighDpi();
}
@@ -843,3 +849,5 @@ Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QScreen *screen)
#endif // !QT_NO_DEBUG_STREAM
QT_END_NAMESPACE
+
+#include "moc_qscreen.cpp"
diff --git a/src/gui/kernel/qsessionmanager.cpp b/src/gui/kernel/qsessionmanager.cpp
index 8747e02719..e1066de451 100644
--- a/src/gui/kernel/qsessionmanager.cpp
+++ b/src/gui/kernel/qsessionmanager.cpp
@@ -423,4 +423,6 @@ void QSessionManager::requestPhase2()
QT_END_NAMESPACE
+#include "moc_qsessionmanager.cpp"
+
#endif // QT_NO_SESSIONMANAGER
diff --git a/src/gui/kernel/qshapedpixmapdndwindow.cpp b/src/gui/kernel/qshapedpixmapdndwindow.cpp
index 1a85a5e853..bb0d8e4ee7 100644
--- a/src/gui/kernel/qshapedpixmapdndwindow.cpp
+++ b/src/gui/kernel/qshapedpixmapdndwindow.cpp
@@ -112,3 +112,5 @@ void QShapedPixmapWindow::updateGeometry(const QPoint &pos)
}
QT_END_NAMESPACE
+
+#include "moc_qshapedpixmapdndwindow_p.cpp"
diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp
index 7b3c70c51b..288bdf1b3c 100644
--- a/src/gui/kernel/qstylehints.cpp
+++ b/src/gui/kernel/qstylehints.cpp
@@ -621,3 +621,5 @@ int QStyleHints::mouseQuickSelectionThreshold() const
}
QT_END_NAMESPACE
+
+#include "moc_qstylehints.cpp"
diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp
index 85c576b21c..e76b618c65 100644
--- a/src/gui/kernel/qsurface.cpp
+++ b/src/gui/kernel/qsurface.cpp
@@ -160,3 +160,5 @@ QSurface::SurfaceClass QSurface::surfaceClass() const
QT_END_NAMESPACE
+#include "moc_qsurface.cpp"
+
diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp
index 6c04abc293..461f6776ce 100644
--- a/src/gui/kernel/qsurfaceformat.cpp
+++ b/src/gui/kernel/qsurfaceformat.cpp
@@ -908,3 +908,5 @@ QDebug operator<<(QDebug dbg, const QSurfaceFormat &f)
#endif
QT_END_NAMESPACE
+
+#include "moc_qsurfaceformat.cpp"
diff --git a/src/gui/kernel/qtestsupport_gui.cpp b/src/gui/kernel/qtestsupport_gui.cpp
index 79da26f2ca..5e9029dc89 100644
--- a/src/gui/kernel/qtestsupport_gui.cpp
+++ b/src/gui/kernel/qtestsupport_gui.cpp
@@ -52,9 +52,16 @@ QT_BEGIN_NAMESPACE
/*!
\since 5.0
- Waits for \a timeout milliseconds or until the \a window is active.
+ Returns \c true, if \a window is active within \a timeout milliseconds. Otherwise returns \c false.
- Returns \c true if \c window is active within \a timeout milliseconds, otherwise returns \c false.
+ The method is useful in tests that call QWindow::show() and rely on the window actually being
+ active (i.e. being visible and having focus) before proceeding.
+
+ \note The method will time out and return \c false if another window prevents \a window from
+ becoming active.
+
+ \note Since focus is an exclusive property, \a window may loose its focus to another window at
+ any time - even after the method has returned \c true.
\sa qWaitForWindowExposed(), QWindow::isActive()
*/
@@ -74,15 +81,14 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
/*!
\since 5.0
- Waits for \a timeout milliseconds or until the \a window is exposed.
- Returns \c true if \c window is exposed within \a timeout milliseconds, otherwise returns \c false.
+ Returns \c true, if \a window is exposed within \a timeout milliseconds. Otherwise returns \c false.
- This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some
- time after being asked to show itself on the screen.
+ The method is useful in tests that call QWindow::show() and rely on the window actually being
+ being visible before proceeding.
- Note that a window that is mapped to screen may still not be considered exposed if the window client
- area is completely covered by other windows, or if the window is otherwise not visible. This function
- will then time out when waiting for such a window.
+ \note A window mapped to screen may still not be considered exposed, if the window client area is
+ not visible, e.g. because it is completely covered by other windows.
+ In such cases, the method will time out and return \c false.
\sa qWaitForWindowActive(), QWindow::isExposed()
*/
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index fd89e479b8..639817257e 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -458,7 +458,7 @@ void QWindowPrivate::updateSiblingPosition(SiblingPosition position)
siblings.move(currentPosition, targetPosition);
}
-inline bool QWindowPrivate::windowRecreationRequired(QScreen *newScreen) const
+bool QWindowPrivate::windowRecreationRequired(QScreen *newScreen) const
{
Q_Q(const QWindow);
const QScreen *oldScreen = q->screen();
@@ -466,7 +466,7 @@ inline bool QWindowPrivate::windowRecreationRequired(QScreen *newScreen) const
&& !(oldScreen && oldScreen->virtualSiblings().contains(newScreen));
}
-inline void QWindowPrivate::disconnectFromScreen()
+void QWindowPrivate::disconnectFromScreen()
{
if (topLevelScreen)
topLevelScreen = nullptr;
@@ -614,6 +614,13 @@ QWindow::SurfaceType QWindow::surfaceType() const
By default, the window is not visible, you must call setVisible(true), or
show() or similar to make it visible.
+ \note Hiding a window does not remove the window from the windowing system,
+ it only hides it. On windowing systems that give full screen applications a
+ dedicated desktop (such as macOS), hiding a full screen window will not remove
+ that desktop, but leave it blank. Another window from the same application
+ might be shown full screen, and will fill that desktop. Use QWindow::close to
+ completely remove a window from the windowing system.
+
\sa show()
*/
void QWindow::setVisible(bool visible)
@@ -1224,11 +1231,13 @@ bool QWindow::isExposed() const
*/
/*!
- Returns \c true if the window should appear active from a style perspective.
+ Returns \c true if the window is active.
This is the case for the window that has input focus as well as windows
that are in the same parent / transient parent chain as the focus window.
+ Typically active windows should appear active from a style perspective.
+
To get the window that currently has focus, use QGuiApplication::focusWindow().
*/
bool QWindow::isActive() const
@@ -1926,7 +1935,12 @@ void QWindow::resize(const QSize &newSize)
Q_D(QWindow);
d->positionPolicy = QWindowPrivate::WindowFrameExclusive;
if (d->platformWindow) {
- d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(position(), newSize), this));
+ if (isTopLevel()) {
+ d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(position(), newSize), this));
+ } else {
+ d->platformWindow->setGeometry(QRect(QHighDpi::toNativeLocalPosition(position(), this),
+ QHighDpi::toNativePixels(newSize, this)));
+ }
} else {
const QSize oldSize = d->geometry.size();
d->geometry.setSize(newSize);
@@ -2201,6 +2215,9 @@ void QWindow::showMaximized()
Equivalent to calling setWindowStates(Qt::WindowFullScreen) and then
setVisible(true).
+ See the \l{QWidget::showFullScreen()} documentation for platform-specific
+ considerations and limitations.
+
\sa setWindowStates(), setVisible()
*/
void QWindow::showFullScreen()
@@ -2705,8 +2722,7 @@ void QWindowPrivate::maybeQuitOnLastWindowClosed()
Q_Q(QWindow);
if (!q->isTopLevel())
return;
- // Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent
- bool quitOnClose = QGuiApplication::quitOnLastWindowClosed() && !q->parent();
+
QWindowList list = QGuiApplication::topLevelWindows();
bool lastWindowClosed = true;
for (int i = 0; i < list.size(); ++i) {
@@ -2718,7 +2734,8 @@ void QWindowPrivate::maybeQuitOnLastWindowClosed()
}
if (lastWindowClosed) {
QGuiApplicationPrivate::emitLastWindowClosed();
- if (quitOnClose) {
+
+ if (QGuiApplication::quitOnLastWindowClosed()) {
QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
applicationPrivate->maybeQuit();
}
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
index cdaed788e9..0b1f8c5b30 100644
--- a/src/gui/math3d/qmatrix4x4.cpp
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -1950,15 +1950,15 @@ QMatrix4x4 QMatrix4x4::orthonormalInverse() const
Normally the QMatrix4x4 class keeps track of this special type internally
as operations are performed. However, if the matrix is modified
- directly with {QLoggingCategory::operator()}{operator()()} or data(), then QMatrix4x4 will lose track of
- the special type and will revert to the safest but least efficient
- operations thereafter.
+ directly with \l {QMatrix4x4::}{operator()()} or data(), then
+ QMatrix4x4 will lose track of the special type and will revert to the
+ safest but least efficient operations thereafter.
By calling optimize() after directly modifying the matrix,
the programmer can force QMatrix4x4 to recover the special type if
the elements appear to conform to one of the known optimized types.
- \sa {QLoggingCategory::operator()}{operator()()}, data(), translate()
+ \sa {QMatrix4x4::}{operator()()}, data(), translate()
*/
void QMatrix4x4::optimize()
{
diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h
index 6a726a197c..c1b61db5e5 100644
--- a/src/gui/math3d/qmatrix4x4.h
+++ b/src/gui/math3d/qmatrix4x4.h
@@ -164,14 +164,14 @@ public:
QTransform toTransform() const;
QTransform toTransform(float distanceToPlane) const;
- QPoint map(const QPoint& point) const;
- QPointF map(const QPointF& point) const;
+ inline QPoint map(const QPoint& point) const;
+ inline QPointF map(const QPointF& point) const;
#ifndef QT_NO_VECTOR3D
- QVector3D map(const QVector3D& point) const;
- QVector3D mapVector(const QVector3D& vector) const;
+ inline QVector3D map(const QVector3D& point) const;
+ inline QVector3D mapVector(const QVector3D& vector) const;
#endif
#ifndef QT_NO_VECTOR4D
- QVector4D map(const QVector4D& point) const;
+ inline QVector4D map(const QVector4D& point) const;
#endif
QRect mapRect(const QRect& rect) const;
QRectF mapRect(const QRectF& rect) const;
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index 5f15949c5b..4f6d063515 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -508,46 +508,47 @@ void QQuaternion::getEulerAngles(float *pitch, float *yaw, float *roll) const
{
Q_ASSERT(pitch && yaw && roll);
- // Algorithm from:
- // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q37
-
- float xx = xp * xp;
- float xy = xp * yp;
- float xz = xp * zp;
- float xw = xp * wp;
- float yy = yp * yp;
- float yz = yp * zp;
- float yw = yp * wp;
- float zz = zp * zp;
- float zw = zp * wp;
-
- const float lengthSquared = xx + yy + zz + wp * wp;
- if (!qFuzzyIsNull(lengthSquared - 1.0f) && !qFuzzyIsNull(lengthSquared)) {
- xx /= lengthSquared;
- xy /= lengthSquared; // same as (xp / length) * (yp / length)
- xz /= lengthSquared;
- xw /= lengthSquared;
- yy /= lengthSquared;
- yz /= lengthSquared;
- yw /= lengthSquared;
- zz /= lengthSquared;
- zw /= lengthSquared;
- }
-
- *pitch = std::asin(-2.0f * (yz - xw));
- if (*pitch < M_PI_2) {
- if (*pitch > -M_PI_2) {
- *yaw = std::atan2(2.0f * (xz + yw), 1.0f - 2.0f * (xx + yy));
- *roll = std::atan2(2.0f * (xy + zw), 1.0f - 2.0f * (xx + zz));
- } else {
- // not a unique solution
- *roll = 0.0f;
- *yaw = -std::atan2(-2.0f * (xy - zw), 1.0f - 2.0f * (yy + zz));
- }
+ // Algorithm adapted from:
+ // https://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf
+ // "A tutorial on SE(3) transformation parameterizations and on-manifold optimization".
+
+ // We can only detect Gimbal lock when we normalize, which we can't do when
+ // length is nearly zero. Do so before multiplying co-ordinates, to avoid
+ // underflow.
+ const float len = length();
+ const bool rescale = !qFuzzyIsNull(len);
+ const float xps = rescale ? xp / len : xp;
+ const float yps = rescale ? yp / len : yp;
+ const float zps = rescale ? zp / len : zp;
+ const float wps = rescale ? wp / len : wp;
+
+ const float xx = xps * xps;
+ const float xy = xps * yps;
+ const float xz = xps * zps;
+ const float xw = xps * wps;
+ const float yy = yps * yps;
+ const float yz = yps * zps;
+ const float yw = yps * wps;
+ const float zz = zps * zps;
+ const float zw = zps * wps;
+
+ // For the common case, we have a hidden division by cos(pitch) to calculate
+ // yaw and roll: atan2(a / cos(pitch), b / cos(pitch)) = atan2(a, b). This equation
+ // wouldn't work if cos(pitch) is close to zero (i.e. abs(sin(pitch)) =~ 1.0).
+ // This threshold is copied from qFuzzyIsNull() to avoid the hidden division by zero.
+ constexpr float epsilon = 0.00001f;
+
+ const float sinp = -2.0f * (yz - xw);
+ if (std::abs(sinp) < 1.0f - epsilon) {
+ *pitch = std::asin(sinp);
+ *yaw = std::atan2(2.0f * (xz + yw), 1.0f - 2.0f * (xx + yy));
+ *roll = std::atan2(2.0f * (xy + zw), 1.0f - 2.0f * (xx + zz));
} else {
- // not a unique solution
+ // Gimbal lock case, which doesn't have a unique solution. We just use
+ // XY rotation.
+ *pitch = std::copysign(static_cast<float>(M_PI_2), sinp);
+ *yaw = 2.0f * std::atan2(yps, wps);
*roll = 0.0f;
- *yaw = std::atan2(-2.0f * (xy - zw), 1.0f - 2.0f * (yy + zz));
}
*pitch = qRadiansToDegrees(*pitch);
diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h
index 3a2393ea58..9dee796eab 100644
--- a/src/gui/opengl/qopengl.h
+++ b/src/gui/opengl/qopengl.h
@@ -157,8 +157,6 @@ typedef char GLchar;
# endif
#endif
-QT_BEGIN_NAMESPACE
-
// When all else fails we provide sensible fallbacks - this is needed to
// allow compilation on OS X 10.6
@@ -287,6 +285,7 @@ typedef GLintptr GLvdpauSurfaceNV;
// End of block copied from glext.h
#endif
+QT_BEGIN_NAMESPACE
// Types that aren't defined in all system's gl.h files.
typedef ptrdiff_t qopengl_GLintptr;
diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp
index 3920a10467..9e7d2861fd 100644
--- a/src/gui/opengl/qopenglpaintdevice.cpp
+++ b/src/gui/opengl/qopenglpaintdevice.cpp
@@ -331,7 +331,7 @@ void QOpenGLPaintDevice::setDotsPerMeterX(qreal dpmx)
void QOpenGLPaintDevice::setDotsPerMeterY(qreal dpmy)
{
- d_ptr->dpmx = dpmy;
+ d_ptr->dpmy = dpmy;
}
/*!
diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp
index 72bdacf43f..dd1462018f 100644
--- a/src/gui/opengl/qopenglprogrambinarycache.cpp
+++ b/src/gui/opengl/qopenglprogrambinarycache.cpp
@@ -120,20 +120,24 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
{
const QString subPath = QLatin1String("/qtshadercache-") + QSysInfo::buildAbi() + QLatin1Char('/');
const QString sharedCachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
+ m_globalCacheDir = sharedCachePath + subPath;
+ m_localCacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
+
if (!sharedCachePath.isEmpty()) {
- m_cacheDir = sharedCachePath + subPath;
- m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
+ m_currentCacheDir = m_globalCacheDir;
+ m_cacheWritable = qt_ensureWritableDir(m_currentCacheDir);
}
if (!m_cacheWritable) {
- m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
- m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
+ m_currentCacheDir = m_localCacheDir;
+ m_cacheWritable = qt_ensureWritableDir(m_currentCacheDir);
}
- qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
+
+ qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_currentCacheDir), m_cacheWritable);
}
QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
{
- return m_cacheDir + QString::fromUtf8(cacheKey);
+ return m_currentCacheDir + QString::fromUtf8(cacheKey);
}
#define BASE_HEADER_SIZE (int(4 * sizeof(quint32)))
@@ -362,6 +366,25 @@ static inline void writeStr(uchar **p, const QByteArray &str)
*p += str.size();
}
+static inline bool writeFile(const QString &filename, const QByteArray &data)
+{
+#if QT_CONFIG(temporaryfile)
+ QSaveFile f(filename);
+ if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ f.write(data);
+ if (f.commit())
+ return true;
+ }
+#else
+ QFile f(filename);
+ if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ if (f.write(data) == data.length())
+ return true;
+ }
+#endif
+ return false;
+}
+
void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
{
if (!m_cacheWritable)
@@ -428,20 +451,20 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
writeUInt(&blobFormatPtr, blobFormat);
-#if QT_CONFIG(temporaryfile)
- QSaveFile f(cacheFileName(cacheKey));
- if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- f.write(blob);
- if (!f.commit())
-#else
- QFile f(cacheFileName(cacheKey));
- if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- if (f.write(blob) < blob.length())
-#endif
- qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(f.fileName()));
- } else {
- qCDebug(lcOpenGLProgramDiskCache, "Failed to create %s in shader cache", qPrintable(f.fileName()));
+ QString filename = cacheFileName(cacheKey);
+ bool ok = writeFile(filename, blob);
+ if (!ok && m_currentCacheDir == m_globalCacheDir) {
+ m_currentCacheDir = m_localCacheDir;
+ m_cacheWritable = qt_ensureWritableDir(m_currentCacheDir);
+ qCDebug(lcOpenGLProgramDiskCache, "Cache location changed to '%s' writable = %d",
+ qPrintable(m_currentCacheDir), m_cacheWritable);
+ if (m_cacheWritable) {
+ filename = cacheFileName(cacheKey);
+ ok = writeFile(filename, blob);
+ }
}
+ if (!ok)
+ qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(filename));
}
#if defined(QT_OPENGL_ES_2)
diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h
index f1cf24cd87..55685f362e 100644
--- a/src/gui/opengl/qopenglprogrambinarycache_p.h
+++ b/src/gui/opengl/qopenglprogrambinarycache_p.h
@@ -89,7 +89,9 @@ private:
bool verifyHeader(const QByteArray &buf) const;
bool setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize);
- QString m_cacheDir;
+ QString m_globalCacheDir;
+ QString m_localCacheDir;
+ QString m_currentCacheDir;
bool m_cacheWritable;
struct MemCacheEntry {
MemCacheEntry(const void *p, int size, uint format)
diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp
index b709f2f639..bf3cba8794 100644
--- a/src/gui/opengl/qopengltextureblitter.cpp
+++ b/src/gui/opengl/qopengltextureblitter.cpp
@@ -44,10 +44,20 @@
#include <QtGui/QOpenGLVertexArrayObject>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLExtraFunctions>
#ifndef GL_TEXTURE_EXTERNAL_OES
#define GL_TEXTURE_EXTERNAL_OES 0x8D65
#endif
+#ifndef GL_TEXTURE_RECTANGLE
+#define GL_TEXTURE_RECTANGLE 0x84F5
+#endif
+#ifndef GL_TEXTURE_WIDTH
+#define GL_TEXTURE_WIDTH 0x1000
+#endif
+#ifndef GL_TEXTURE_HEIGHT
+#define GL_TEXTURE_HEIGHT 0x1001
+#endif
QT_BEGIN_NAMESPACE
@@ -153,6 +163,30 @@ static const char fragment_shader_external_oes[] =
" gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
"}";
+static const char fragment_shader_rectangle[] =
+ "varying highp vec2 uv;"
+ "uniform sampler2DRect textureSampler;"
+ "uniform bool swizzle;"
+ "uniform highp float opacity;"
+ "void main() {"
+ " highp vec4 tmpFragColor = texture2DRect(textureSampler,uv);"
+ " tmpFragColor.a *= opacity;"
+ " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
+ "}";
+
+static const char fragment_shader150_rectangle[] =
+ "#version 150 core\n"
+ "in vec2 uv;"
+ "out vec4 fragcolor;"
+ "uniform sampler2DRect textureSampler;"
+ "uniform bool swizzle;"
+ "uniform float opacity;"
+ "void main() {"
+ " vec4 tmpFragColor = texture(textureSampler, uv);"
+ " tmpFragColor.a *= opacity;"
+ " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
+ "}";
+
static const GLfloat vertex_buffer_data[] = {
-1,-1, 0,
-1, 1, 0,
@@ -198,10 +232,12 @@ public:
enum ProgramIndex {
TEXTURE_2D,
- TEXTURE_EXTERNAL_OES
+ TEXTURE_EXTERNAL_OES,
+ TEXTURE_RECTANGLE
};
- QOpenGLTextureBlitterPrivate() :
+ QOpenGLTextureBlitterPrivate(QOpenGLTextureBlitter *q_ptr) :
+ q(q_ptr),
swizzle(false),
opacity(1.0f),
vao(new QOpenGLVertexArrayObject),
@@ -209,12 +245,18 @@ public:
{ }
bool buildProgram(ProgramIndex idx, const char *vs, const char *fs);
+ bool ensureProgram(ProgramIndex idx);
+
+ void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform);
+ void blit(GLuint texture, const QMatrix4x4 &targetTransform, QOpenGLTextureBlitter::Origin origin);
- void blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform);
- void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin);
+ QMatrix3x3 toTextureCoordinates(const QMatrix3x3 &sourceTransform) const;
- void prepareProgram(const QMatrix4x4 &vertexTransform);
+ bool prepareProgram(const QMatrix4x4 &vertexTransform);
+ bool supportsRectangleTarget() const;
+
+ QOpenGLTextureBlitter *q;
QOpenGLBuffer vertexBuffer;
QOpenGLBuffer textureBuffer;
struct Program {
@@ -239,7 +281,7 @@ public:
bool swizzle;
float opacity;
TextureMatrixUniform textureMatrixUniformState;
- } programs[2];
+ } programs[3];
bool swizzle;
float opacity;
QScopedPointer<QOpenGLVertexArrayObject> vao;
@@ -253,15 +295,21 @@ static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GL
return QOpenGLTextureBlitterPrivate::TEXTURE_2D;
case GL_TEXTURE_EXTERNAL_OES:
return QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES;
+ case GL_TEXTURE_RECTANGLE:
+ return QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE;
default:
qWarning("Unsupported texture target 0x%x", target);
return QOpenGLTextureBlitterPrivate::TEXTURE_2D;
}
}
-void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform)
+bool QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform)
{
- Program *program = &programs[targetToProgramIndex(currentTarget)];
+ ProgramIndex programIndex = targetToProgramIndex(currentTarget);
+ if (!ensureProgram(programIndex))
+ return false;
+
+ Program *program = &programs[programIndex];
vertexBuffer.bind();
program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0);
@@ -284,16 +332,38 @@ void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransf
program->glProgram->setUniformValue(program->opacityUniformPos, opacity);
program->opacity = opacity;
}
+
+ return true;
+}
+
+QMatrix3x3 QOpenGLTextureBlitterPrivate::toTextureCoordinates(const QMatrix3x3 &sourceTransform) const
+{
+ if (currentTarget == GL_TEXTURE_RECTANGLE) {
+ // Non-normalized coordinates
+ QMatrix4x4 textureTransform(sourceTransform);
+ if (auto *glFunctions = QOpenGLContext::currentContext()->extraFunctions()) {
+ int width, height;
+ glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_WIDTH, &width);
+ glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_HEIGHT, &height);
+ textureTransform.scale(width, height);
+ }
+ return textureTransform.toGenericMatrix<3, 3>();
+ }
+
+ return sourceTransform; // Normalized coordinates
}
void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
- const QMatrix4x4 &vertexTransform,
- const QMatrix3x3 &textureTransform)
+ const QMatrix4x4 &targetTransform,
+ const QMatrix3x3 &sourceTransform)
{
TextureBinder binder(currentTarget, texture);
- prepareProgram(vertexTransform);
+ if (!prepareProgram(targetTransform))
+ return;
Program *program = &programs[targetToProgramIndex(currentTarget)];
+
+ const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform);
program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
program->textureMatrixUniformState = User;
@@ -301,23 +371,27 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
}
void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
- const QMatrix4x4 &vertexTransform,
+ const QMatrix4x4 &targetTransform,
QOpenGLTextureBlitter::Origin origin)
{
TextureBinder binder(currentTarget, texture);
- prepareProgram(vertexTransform);
+ if (!prepareProgram(targetTransform))
+ return;
Program *program = &programs[targetToProgramIndex(currentTarget)];
+
if (origin == QOpenGLTextureBlitter::OriginTopLeft) {
if (program->textureMatrixUniformState != IdentityFlipped) {
- QMatrix3x3 flipped;
- flipped(1,1) = -1;
- flipped(1,2) = 1;
- program->glProgram->setUniformValue(program->textureTransformUniformPos, flipped);
+ QMatrix3x3 sourceTransform;
+ sourceTransform(1,1) = -1;
+ sourceTransform(1,2) = 1;
+ const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform);
+ program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
program->textureMatrixUniformState = IdentityFlipped;
}
} else if (program->textureMatrixUniformState != Identity) {
- program->glProgram->setUniformValue(program->textureTransformUniformPos, QMatrix3x3());
+ const QMatrix3x3 textureTransform = toTextureCoordinates(QMatrix3x3());
+ program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
program->textureMatrixUniformState = Identity;
}
@@ -335,6 +409,7 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs
p->glProgram->link();
if (!p->glProgram->isLinked()) {
qWarning() << "Could not link shader program:\n" << p->glProgram->log();
+ p->glProgram.reset();
return false;
}
@@ -355,6 +430,35 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs
return true;
}
+bool QOpenGLTextureBlitterPrivate::ensureProgram(ProgramIndex idx)
+{
+ if (programs[idx].glProgram)
+ return true;
+
+ QOpenGLContext *currentContext = QOpenGLContext::currentContext();
+ if (!currentContext)
+ return false;
+
+ QSurfaceFormat format = currentContext->format();
+ if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) {
+ if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && supportsRectangleTarget()) {
+ if (!buildProgram(idx, vertex_shader150, fragment_shader150_rectangle))
+ return false;
+ }
+ } else {
+ if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && supportsRectangleTarget()) {
+ if (!buildProgram(idx, vertex_shader, fragment_shader_rectangle))
+ return false;
+ }
+ if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES && q->supportsExternalOESTarget()) {
+ if (!buildProgram(idx, vertex_shader, fragment_shader_external_oes))
+ return false;
+ }
+ }
+
+ return programs[idx].glProgram;
+}
+
/*!
Constructs a new QOpenGLTextureBlitter instance.
@@ -365,7 +469,7 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs
create().
*/
QOpenGLTextureBlitter::QOpenGLTextureBlitter()
- : d_ptr(new QOpenGLTextureBlitterPrivate)
+ : d_ptr(new QOpenGLTextureBlitterPrivate(this))
{
}
@@ -405,15 +509,14 @@ bool QOpenGLTextureBlitter::create()
return true;
QSurfaceFormat format = currentContext->format();
+ // Build the most common, 2D texture shader variant.
+ // The other special ones are deferred and compiled only when first needed.
if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) {
if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150))
return false;
} else {
if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader))
return false;
- if (supportsExternalOESTarget())
- if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES, vertex_shader, fragment_shader_external_oes))
- return false;
}
// Create and bind the VAO, if supported.
@@ -459,6 +562,7 @@ void QOpenGLTextureBlitter::destroy()
Q_D(QOpenGLTextureBlitter);
d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset();
d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset();
+ d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE].glProgram.reset();
d->vertexBuffer.destroy();
d->textureBuffer.destroy();
d->vao.reset();
@@ -477,13 +581,39 @@ bool QOpenGLTextureBlitter::supportsExternalOESTarget() const
}
/*!
+ \return \c true when bind() accepts \c GL_TEXTURE_RECTANGLE as
+ its target argument.
+
+ \sa bind(), blit()
+ */
+bool QOpenGLTextureBlitterPrivate::supportsRectangleTarget() const
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx || ctx->isOpenGLES())
+ return false;
+
+ if (ctx->hasExtension("GL_ARB_texture_rectangle"))
+ return true;
+
+ if (ctx->hasExtension("GL_EXT_texture_rectangle"))
+ return true;
+
+ QSurfaceFormat f = ctx->format();
+ const auto version = qMakePair(f.majorVersion(), f.minorVersion());
+ if (version >= qMakePair(3, 1))
+ return true;
+
+ return false;
+}
+
+/*!
Binds the graphics resources used by the blitter. This must be
called before calling blit(). Code modifying the OpenGL state
should be avoided between the call to bind() and blit() because
otherwise conflicts may arise.
\a target is the texture target for the source texture and must be
- either \c GL_TEXTURE_2D or \c GL_OES_EGL_image_external.
+ either \c GL_TEXTURE_2D, \c GL_TEXTURE_RECTANGLE, or \c GL_OES_EGL_image_external.
\sa release(), blit()
*/
@@ -495,7 +625,11 @@ void QOpenGLTextureBlitter::bind(GLenum target)
d->vao->bind();
d->currentTarget = target;
- QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target)];
+ QOpenGLTextureBlitterPrivate::ProgramIndex programIndex = targetToProgramIndex(target);
+ if (!d->ensureProgram(programIndex))
+ return;
+
+ QOpenGLTextureBlitterPrivate::Program *p = &d->programs[programIndex];
p->glProgram->bind();
d->vertexBuffer.bind();
@@ -517,7 +651,9 @@ void QOpenGLTextureBlitter::bind(GLenum target)
void QOpenGLTextureBlitter::release()
{
Q_D(QOpenGLTextureBlitter);
- d->programs[targetToProgramIndex(d->currentTarget)].glProgram->release();
+ QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(d->currentTarget)];
+ if (p->glProgram)
+ p->glProgram->release();
if (d->vao->isCreated())
d->vao->release();
}
@@ -586,7 +722,7 @@ void QOpenGLTextureBlitter::blit(GLuint texture,
Origin sourceOrigin)
{
Q_D(QOpenGLTextureBlitter);
- d->blit(texture,targetTransform, sourceOrigin);
+ d->blit(texture, targetTransform, sourceOrigin);
}
/*!
diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp
index 41027d26e0..7da156bf0f 100644
--- a/src/gui/opengl/qopengltextureglyphcache.cpp
+++ b/src/gui/opengl/qopengltextureglyphcache.cpp
@@ -441,7 +441,10 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
int QOpenGLTextureGlyphCache::glyphPadding() const
{
- return 1;
+ if (m_format == QFontEngine::Format_Mono)
+ return 8;
+ else
+ return 1;
}
int QOpenGLTextureGlyphCache::maxTextureWidth() const
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index c68e8d6e9a..bb0fc0ffba 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -146,7 +146,7 @@ gcc:equals(QT_GCC_MAJOR_VERSION, 5) {
NEON_HEADERS += painting/qdrawhelper_neon_p.h
}
!uikit:!win32:contains(QT_ARCH, "arm"): CONFIG += no_clang_integrated_as
-!android:!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") {
+!macos:!android:!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") {
NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S
DEFINES += ENABLE_PIXMAN_DRAWHELPERS
}
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 2147d9d61d..ebce163ed3 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -249,8 +249,18 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients));
- handle()->flush(window, QHighDpi::toNativeLocalRegion(region, window),
- QHighDpi::toNativeLocalPosition(offset, window));
+ QRegion nativeRegion = QHighDpi::toNativeLocalRegion(region, window);
+ QPoint nativeOffset;
+ if (!offset.isNull()) {
+ nativeOffset = QHighDpi::toNativeLocalPosition(offset, window);
+ // Under fractional DPR, rounding of region and offset may accumulate to an off-by-one
+ QPoint topLeft = region.boundingRect().topLeft() + offset;
+ QPoint nativeTopLeft = QHighDpi::toNativeLocalPosition(topLeft, window);
+ QPoint diff = nativeTopLeft - (nativeRegion.boundingRect().topLeft() + nativeOffset);
+ Q_ASSERT(qMax(qAbs(diff.x()), qAbs(diff.y())) <= 1);
+ nativeRegion.translate(diff);
+ }
+ handle()->flush(window, nativeRegion, nativeOffset);
}
/*!
@@ -320,32 +330,34 @@ bool QBackingStore::hasStaticContents() const
void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
{
// make sure we don't detach
- uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits());
+ uchar *mem = const_cast<uchar*>(img.constBits());
int lineskip = img.bytesPerLine();
int depth = img.depth() >> 3;
const QRect imageRect(0, 0, img.width(), img.height());
- const QRect r = rect & imageRect & imageRect.translated(-offset);
- const QPoint p = rect.topLeft() + offset;
-
- if (r.isEmpty())
+ const QRect sourceRect = rect.intersected(imageRect).intersected(imageRect.translated(-offset));
+ if (sourceRect.isEmpty())
return;
+ const QRect destRect = sourceRect.translated(offset);
+ Q_ASSERT_X(imageRect.contains(destRect), "qt_scrollRectInImage",
+ "The sourceRect should already account for clipping, both pre and post scroll");
+
const uchar *src;
uchar *dest;
- if (r.top() < p.y()) {
- src = mem + r.bottom() * lineskip + r.left() * depth;
- dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth;
+ if (sourceRect.top() < destRect.top()) {
+ src = mem + sourceRect.bottom() * lineskip + sourceRect.left() * depth;
+ dest = mem + (destRect.top() + sourceRect.height() - 1) * lineskip + destRect.left() * depth;
lineskip = -lineskip;
} else {
- src = mem + r.top() * lineskip + r.left() * depth;
- dest = mem + p.y() * lineskip + p.x() * depth;
+ src = mem + sourceRect.top() * lineskip + sourceRect.left() * depth;
+ dest = mem + destRect.top() * lineskip + destRect.left() * depth;
}
- const int w = r.width();
- int h = r.height();
+ const int w = sourceRect.width();
+ int h = sourceRect.height();
const int bytes = w * depth;
// overlapping segments?
diff --git a/src/gui/painting/qblendfunctions_p.h b/src/gui/painting/qblendfunctions_p.h
index 080da98ec4..6997d62b3c 100644
--- a/src/gui/painting/qblendfunctions_p.h
+++ b/src/gui/painting/qblendfunctions_p.h
@@ -246,25 +246,32 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
int dudx, int dvdx, int dudy, int dvdy, int u0, int v0,
Blender blender)
{
- int fromY = qMax(qRound(topY), clip.top());
- int toY = qMin(qRound(bottomY), clip.top() + clip.height());
+ qint64 fromY = qMax(qRound(topY), clip.top());
+ qint64 toY = qMin(qRound(bottomY), clip.top() + clip.height());
if (fromY >= toY)
return;
qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y);
qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y);
- int dx_l = int(leftSlope * 0x10000);
- int dx_r = int(rightSlope * 0x10000);
- int x_l = int((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000);
- int x_r = int((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000);
-
- int fromX, toX, x1, x2, u, v, i, ii;
+ qint64 dx_l = qint64(leftSlope * 0x10000);
+ qint64 dx_r = qint64(rightSlope * 0x10000);
+ qint64 x_l = qint64((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000);
+ qint64 x_r = qint64((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000);
+
+ qint64 sourceRectTop = qint64(sourceRect.top());
+ qint64 sourceRectLeft = qint64(sourceRect.left());
+ qint64 sourceRectWidth = qint64(sourceRect.width());
+ qint64 sourceRectHeight = qint64(sourceRect.height());
+ qint64 clipLeft = qint64(clip.left());
+ qint64 clipWidth = qint64(clip.width());
+
+ qint64 fromX, toX, x1, x2, u, v, i, ii;
DestT *line;
- for (int y = fromY; y < toY; ++y) {
+ for (qint64 y = fromY; y < toY; ++y) {
line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl);
- fromX = qMax(x_l >> 16, clip.left());
- toX = qMin(x_r >> 16, clip.left() + clip.width());
+ fromX = qMax(x_l >> 16, clipLeft);
+ toX = qMin(x_r >> 16, clipLeft + clipWidth);
if (fromX < toX) {
// Because of rounding, we can get source coordinates outside the source image.
// Clamp these coordinates to the source rect to avoid segmentation fault and
@@ -275,10 +282,10 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
u = x1 * dudx + y * dudy + u0;
v = x1 * dvdx + y * dvdy + v0;
for (; x1 < toX; ++x1) {
- int uu = u >> 16;
- int vv = v >> 16;
- if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
- && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
+ qint64 uu = u >> 16;
+ qint64 vv = v >> 16;
+ if (uu >= sourceRectLeft && uu < sourceRectLeft + sourceRectWidth
+ && vv >= sourceRectTop && vv < sourceRectTop + sourceRectHeight) {
break;
}
u += dudx;
@@ -290,10 +297,10 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
u = (x2 - 1) * dudx + y * dudy + u0;
v = (x2 - 1) * dvdx + y * dvdy + v0;
for (; x2 > x1; --x2) {
- int uu = u >> 16;
- int vv = v >> 16;
- if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
- && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
+ qint64 uu = u >> 16;
+ qint64 vv = v >> 16;
+ if (uu >= sourceRectLeft && uu < sourceRectLeft + sourceRectWidth
+ && vv >= sourceRectTop && vv < sourceRectTop + sourceRectHeight) {
break;
}
u -= dudx;
@@ -308,8 +315,8 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
// Beginning of the scan line, with per-pixel checks.
i = x1 - fromX;
while (i) {
- int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
- int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
+ qint64 uu = qBound(sourceRectLeft, u >> 16, sourceRectLeft + sourceRectWidth - 1);
+ qint64 vv = qBound(sourceRectTop, v >> 16, sourceRectTop + sourceRectHeight - 1);
blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
u += dudx;
v += dvdx;
@@ -348,8 +355,8 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
// End of the scan line, with per-pixel checks.
i = toX - x2;
while (i) {
- int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
- int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
+ qint64 uu = qBound(sourceRectLeft, u >> 16, sourceRectLeft + sourceRectWidth - 1);
+ qint64 vv = qBound(sourceRectTop, v >> 16, sourceRectTop + sourceRectHeight - 1);
blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
u += dudx;
v += dvdx;
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index 89f3374ea1..08d7055b82 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -1354,7 +1354,176 @@ QGradient::QGradient()
\since 5.12
This enum specifies a set of predefined presets for QGradient,
- based on the gradients from https://webgradients.com/.
+ based on the gradients from \l {https://webgradients.com/}.
+
+ \value WarmFlame
+ \value NightFade
+ \value SpringWarmth
+ \value JuicyPeach
+ \value YoungPassion
+ \value LadyLips
+ \value SunnyMorning
+ \value RainyAshville
+ \value FrozenDreams
+ \value WinterNeva
+ \value DustyGrass
+ \value TemptingAzure
+ \value HeavyRain
+ \value AmyCrisp
+ \value MeanFruit
+ \value DeepBlue
+ \value RipeMalinka
+ \value CloudyKnoxville
+ \value MalibuBeach
+ \value NewLife
+ \value TrueSunset
+ \value MorpheusDen
+ \value RareWind
+ \value NearMoon
+ \value WildApple
+ \value SaintPetersburg
+ \value PlumPlate
+ \value EverlastingSky
+ \value HappyFisher
+ \value Blessing
+ \value SharpeyeEagle
+ \value LadogaBottom
+ \value LemonGate
+ \value ItmeoBranding
+ \value ZeusMiracle
+ \value OldHat
+ \value StarWine
+ \value HappyAcid
+ \value AwesomePine
+ \value NewYork
+ \value ShyRainbow
+ \value MixedHopes
+ \value FlyHigh
+ \value StrongBliss
+ \value FreshMilk
+ \value SnowAgain
+ \value FebruaryInk
+ \value KindSteel
+ \value SoftGrass
+ \value GrownEarly
+ \value SharpBlues
+ \value ShadyWater
+ \value DirtyBeauty
+ \value GreatWhale
+ \value TeenNotebook
+ \value PoliteRumors
+ \value SweetPeriod
+ \value WideMatrix
+ \value SoftCherish
+ \value RedSalvation
+ \value BurningSpring
+ \value NightParty
+ \value SkyGlider
+ \value HeavenPeach
+ \value PurpleDivision
+ \value AquaSplash
+ \value SpikyNaga
+ \value LoveKiss
+ \value CleanMirror
+ \value PremiumDark
+ \value ColdEvening
+ \value CochitiLake
+ \value SummerGames
+ \value PassionateBed
+ \value MountainRock
+ \value DesertHump
+ \value JungleDay
+ \value PhoenixStart
+ \value OctoberSilence
+ \value FarawayRiver
+ \value AlchemistLab
+ \value OverSun
+ \value PremiumWhite
+ \value MarsParty
+ \value EternalConstance
+ \value JapanBlush
+ \value SmilingRain
+ \value CloudyApple
+ \value BigMango
+ \value HealthyWater
+ \value AmourAmour
+ \value RiskyConcrete
+ \value StrongStick
+ \value ViciousStance
+ \value PaloAlto
+ \value HappyMemories
+ \value MidnightBloom
+ \value Crystalline
+ \value PartyBliss
+ \value ConfidentCloud
+ \value LeCocktail
+ \value RiverCity
+ \value FrozenBerry
+ \value ChildCare
+ \value FlyingLemon
+ \value NewRetrowave
+ \value HiddenJaguar
+ \value AboveTheSky
+ \value Nega
+ \value DenseWater
+ \value Seashore
+ \value MarbleWall
+ \value CheerfulCaramel
+ \value NightSky
+ \value MagicLake
+ \value YoungGrass
+ \value ColorfulPeach
+ \value GentleCare
+ \value PlumBath
+ \value HappyUnicorn
+ \value AfricanField
+ \value SolidStone
+ \value OrangeJuice
+ \value GlassWater
+ \value NorthMiracle
+ \value FruitBlend
+ \value MillenniumPine
+ \value HighFlight
+ \value MoleHall
+ \value SpaceShift
+ \value ForestInei
+ \value RoyalGarden
+ \value RichMetal
+ \value JuicyCake
+ \value SmartIndigo
+ \value SandStrike
+ \value NorseBeauty
+ \value AquaGuidance
+ \value SunVeggie
+ \value SeaLord
+ \value BlackSea
+ \value GrassShampoo
+ \value LandingAircraft
+ \value WitchDance
+ \value SleeplessNight
+ \value AngelCare
+ \value CrystalRiver
+ \value SoftLipstick
+ \value SaltMountain
+ \value PerfectWhite
+ \value FreshOasis
+ \value StrictNovember
+ \value MorningSalad
+ \value DeepRelief
+ \value SeaStrike
+ \value NightCall
+ \value SupremeSky
+ \value LightBlue
+ \value MindCrawl
+ \value LilyMeadow
+ \value SugarLollipop
+ \value SweetDessert
+ \value MagicRay
+ \value TeenParty
+ \value FrozenHeat
+ \value GagarinView
+ \value FabledSunset
+ \value PerfectBlue
*/
/*!
@@ -2469,3 +2638,5 @@ void QConicalGradient::setAngle(qreal angle)
#undef Q_DUMMY_ACCESSOR
QT_END_NAMESPACE
+
+#include "moc_qbrush.cpp"
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index 7612f183bc..2352d6e18a 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -3203,7 +3203,7 @@ const uint qt_inv_premul_factor[256] = {
Returns the ARGB quadruplet (255, \a{r}, \a{g}, \a{b}).
- \sa qRgba(), qRed(), qGreen(), qBlue()
+ \sa qRgba(), qRed(), qGreen(), qBlue(), qAlpha()
*/
/*!
@@ -3212,7 +3212,7 @@ const uint qt_inv_premul_factor[256] = {
Returns the ARGB quadruplet (\a{a}, \a{r}, \a{g}, \a{b}).
- \sa qRgb(), qRed(), qGreen(), qBlue()
+ \sa qRgb(), qRed(), qGreen(), qBlue(), qAlpha()
*/
/*!
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 930e5aec87..dd30c64640 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -46,6 +46,7 @@
#include "qcolortransform_p.h"
#include "qicc_p.h"
+#include <qatomic.h>
#include <qmath.h>
#include <qtransform.h>
@@ -55,6 +56,18 @@ QT_BEGIN_NAMESPACE
QBasicMutex QColorSpacePrivate::s_lutWriteLock;
+static QAtomicPointer<QColorSpacePrivate> s_predefinedColorspacePrivates[QColorSpace::ProPhotoRgb] = {};
+static void cleanupPredefinedColorspaces()
+{
+ for (QAtomicPointer<QColorSpacePrivate> &ptr : s_predefinedColorspacePrivates) {
+ QColorSpacePrivate *prv = ptr.fetchAndStoreAcquire(nullptr);
+ if (prv && !prv->ref.deref())
+ delete prv;
+ }
+}
+
+Q_DESTRUCTOR_FUNCTION(cleanupPredefinedColorspaces)
+
QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Primaries primaries)
{
switch (primaries) {
@@ -133,13 +146,17 @@ QColorMatrix QColorSpacePrimaries::toXyzMatrix() const
QColorVector srcCone = abrad.map(wXyz);
QColorVector dstCone = abrad.map(wXyzD50);
- QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
- { 0, dstCone.y / srcCone.y, 0 },
- { 0, 0, dstCone.z / srcCone.z } };
+ if (srcCone.x && srcCone.y && srcCone.z) {
+ QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
+ { 0, dstCone.y / srcCone.y, 0 },
+ { 0, 0, dstCone.z / srcCone.z } };
- QColorMatrix chromaticAdaptation = abradinv * (wToD50 * abrad);
- toXyz = chromaticAdaptation * toXyz;
+ QColorMatrix chromaticAdaptation = abradinv * (wToD50 * abrad);
+ toXyz = chromaticAdaptation * toXyz;
+ } else {
+ toXyz.r = {0, 0, 0}; // set to invalid value
+ }
}
return toXyz;
@@ -185,9 +202,9 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSp
initialize();
}
-QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma)
+QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma)
: primaries(primaries)
- , transferFunction(fun)
+ , transferFunction(transferFunction)
, gamma(gamma)
{
identifyColorSpace();
@@ -195,10 +212,10 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorS
}
QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
- QColorSpace::TransferFunction fun,
+ QColorSpace::TransferFunction transferFunction,
float gamma)
: primaries(QColorSpace::Primaries::Custom)
- , transferFunction(fun)
+ , transferFunction(transferFunction)
, gamma(gamma)
{
Q_ASSERT(primaries.areValid());
@@ -318,6 +335,7 @@ void QColorSpacePrivate::setTransferFunction()
}
trc[1] = trc[0];
trc[2] = trc[0];
+ lut.generated.storeRelease(0);
}
QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpacePrivate *out) const
@@ -426,22 +444,28 @@ QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
qWarning() << "QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " << int(namedColorSpace);
return;
}
- static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::ProPhotoRgb + 1];
- if (!predefinedColorspacePrivates[namedColorSpace]) {
- predefinedColorspacePrivates[namedColorSpace] = new QColorSpacePrivate(namedColorSpace);
- predefinedColorspacePrivates[namedColorSpace]->ref.ref();
+ // The defined namespaces start at 1:
+ auto &atomicRef = s_predefinedColorspacePrivates[static_cast<int>(namedColorSpace) - 1];
+ QColorSpacePrivate *cspriv = atomicRef.loadAcquire();
+ if (!cspriv) {
+ auto *tmp = new QColorSpacePrivate(namedColorSpace);
+ tmp->ref.ref();
+ if (atomicRef.testAndSetOrdered(nullptr, tmp, cspriv))
+ cspriv = tmp;
+ else
+ delete tmp;
}
- d_ptr = predefinedColorspacePrivates[namedColorSpace];
+ d_ptr = cspriv;
d_ptr->ref.ref();
Q_ASSERT(isValid());
}
/*!
- Creates a custom color space with the primaries \a primaries, using the transfer function \a fun and
+ Creates a custom color space with the primaries \a primaries, using the transfer function \a transferFunction and
optionally \a gamma.
*/
-QColorSpace::QColorSpace(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma)
- : d_ptr(new QColorSpacePrivate(primaries, fun, gamma))
+QColorSpace::QColorSpace(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma)
+ : d_ptr(new QColorSpacePrivate(primaries, transferFunction, gamma))
{
d_ptr->ref.ref();
}
@@ -458,11 +482,11 @@ QColorSpace::QColorSpace(QColorSpace::Primaries primaries, float gamma)
/*!
Creates a custom colorspace with a primaries based on the chromaticities of the primary colors \a whitePoint,
- \a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a fun and optionally \a gamma.
+ \a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a transferFunction and optionally \a gamma.
*/
QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
const QPointF &greenPoint, const QPointF &bluePoint,
- QColorSpace::TransferFunction fun, float gamma)
+ QColorSpace::TransferFunction transferFunction, float gamma)
{
QColorSpacePrimaries primaries(whitePoint, redPoint, greenPoint, bluePoint);
if (!primaries.areValid()) {
@@ -470,7 +494,7 @@ QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
d_ptr = nullptr;
return;
}
- d_ptr = new QColorSpacePrivate(primaries, fun, gamma);
+ d_ptr = new QColorSpacePrivate(primaries, transferFunction, gamma);
d_ptr->ref.ref();
}
@@ -824,3 +848,5 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
#endif
QT_END_NAMESPACE
+
+#include "moc_qcolorspace.cpp"
diff --git a/src/gui/painting/qcolorspace.h b/src/gui/painting/qcolorspace.h
index 08c9944301..852ade9ab7 100644
--- a/src/gui/painting/qcolorspace.h
+++ b/src/gui/painting/qcolorspace.h
@@ -82,11 +82,11 @@ public:
QColorSpace();
QColorSpace(NamedColorSpace namedColorSpace);
- QColorSpace(Primaries primaries, TransferFunction fun, float gamma = 0.0f);
+ QColorSpace(Primaries primaries, TransferFunction transferFunction, float gamma = 0.0f);
QColorSpace(Primaries primaries, float gamma);
QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
const QPointF &greenPoint, const QPointF &bluePoint,
- TransferFunction fun, float gamma = 0.0f);
+ TransferFunction transferFunction, float gamma = 0.0f);
~QColorSpace();
QColorSpace(const QColorSpace &colorSpace);
diff --git a/src/gui/painting/qcolorspace_p.h b/src/gui/painting/qcolorspace_p.h
index e7add19ed3..094fdb0d37 100644
--- a/src/gui/painting/qcolorspace_p.h
+++ b/src/gui/painting/qcolorspace_p.h
@@ -91,8 +91,8 @@ class QColorSpacePrivate : public QSharedData
public:
QColorSpacePrivate();
QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace);
- QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma);
- QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction fun, float gamma);
+ QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma);
+ QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction transferFunction, float gamma);
QColorSpacePrivate(const QColorSpacePrivate &other) = default;
// named different from get to avoid accidental detachs
diff --git a/src/gui/painting/qcolortransfertable_p.h b/src/gui/painting/qcolortransfertable_p.h
index c8b2f7bd92..d6b514193d 100644
--- a/src/gui/painting/qcolortransfertable_p.h
+++ b/src/gui/painting/qcolortransfertable_p.h
@@ -69,43 +69,57 @@ public:
QColorTransferTable(uint32_t size, const QVector<uint8_t> &table) noexcept
: m_tableSize(size)
, m_table8(table)
- { }
+ {
+ Q_ASSERT(size <= uint32_t(table.count()));
+ }
QColorTransferTable(uint32_t size, const QVector<uint16_t> &table) noexcept
: m_tableSize(size)
, m_table16(table)
- { }
+ {
+ Q_ASSERT(size <= uint32_t(table.count()));
+ }
- bool isValid() const
+ bool isEmpty() const
{
+ return m_tableSize == 0;
+ }
+
+ bool checkValidity() const
+ {
+ if (isEmpty())
+ return true;
+ // Only one table can be set
+ if (!m_table8.isEmpty() && !m_table16.isEmpty())
+ return false;
+ // At least 2 elements
if (m_tableSize < 2)
return false;
-
-#if !defined(QT_NO_DEBUG)
// The table must describe an injective curve:
if (!m_table8.isEmpty()) {
uint8_t val = 0;
for (uint i = 0; i < m_tableSize; ++i) {
- Q_ASSERT(m_table8[i] >= val);
+ if (m_table8[i] < val)
+ return false;
val = m_table8[i];
}
}
if (!m_table16.isEmpty()) {
uint16_t val = 0;
for (uint i = 0; i < m_tableSize; ++i) {
- Q_ASSERT(m_table16[i] >= val);
+ if (m_table16[i] < val)
+ return false;
val = m_table16[i];
}
}
-#endif
- return !m_table8.isEmpty() || !m_table16.isEmpty();
+ return true;
}
float apply(float x) const
{
x = std::min(std::max(x, 0.0f), 1.0f);
x *= m_tableSize - 1;
- uint32_t lo = (int)std::floor(x);
- uint32_t hi = std::min(lo + 1, m_tableSize);
+ uint32_t lo = static_cast<uint32_t>(std::floor(x));
+ uint32_t hi = std::min(lo + 1, m_tableSize - 1);
float frac = x - lo;
if (!m_table16.isEmpty())
return (m_table16[lo] * (1.0f - frac) + m_table16[hi] * frac) * (1.0f/65535.0f);
@@ -124,7 +138,7 @@ public:
return 1.0f;
if (!m_table16.isEmpty()) {
float v = x * 65535.0f;
- uint i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1;
+ uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1));
for ( ; i < m_tableSize; ++i) {
if (m_table16[i] > v)
break;
@@ -133,14 +147,14 @@ public:
return 1.0f;
float y1 = m_table16[i - 1];
float y2 = m_table16[i];
- Q_ASSERT(x >= y1 && x < y2);
+ Q_ASSERT(v >= y1 && v <= y2);
float fr = (v - y1) / (y2 - y1);
return (i + fr) * (1.0f / (m_tableSize - 1));
}
if (!m_table8.isEmpty()) {
float v = x * 255.0f;
- uint i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1;
+ uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1));
for ( ; i < m_tableSize; ++i) {
if (m_table8[i] > v)
break;
@@ -149,7 +163,7 @@ public:
return 1.0f;
float y1 = m_table8[i - 1];
float y2 = m_table8[i];
- Q_ASSERT(x >= y1 && x < y2);
+ Q_ASSERT(v >= y1 && v <= y2);
float fr = (v - y1) / (y2 - y1);
return (i + fr) * (1.0f / (m_tableSize - 1));
}
@@ -158,8 +172,9 @@ public:
bool asColorTransferFunction(QColorTransferFunction *transferFn)
{
- Q_ASSERT(isValid());
Q_ASSERT(transferFn);
+ if (m_tableSize < 2)
+ return false;
if (!m_table8.isEmpty() && (m_table8[0] != 0 || m_table8[m_tableSize - 1] != 255))
return false;
if (!m_table16.isEmpty() && (m_table16[0] != 0 || m_table16[m_tableSize - 1] != 65535))
@@ -221,13 +236,13 @@ inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable
if (t1.m_table16.isEmpty() != t2.m_table16.isEmpty())
return true;
if (!t1.m_table8.isEmpty()) {
- for (quint32 i = 0; i < t1.m_tableSize; ++i) {
+ for (uint32_t i = 0; i < t1.m_tableSize; ++i) {
if (t1.m_table8[i] != t2.m_table8[i])
return true;
}
}
if (!t1.m_table16.isEmpty()) {
- for (quint32 i = 0; i < t1.m_tableSize; ++i) {
+ for (uint32_t i = 0; i < t1.m_tableSize; ++i) {
if (t1.m_table16[i] != t2.m_table16[i])
return true;
}
diff --git a/src/gui/painting/qcolortrc_p.h b/src/gui/painting/qcolortrc_p.h
index 3ef9d442fc..058be3c7ce 100644
--- a/src/gui/painting/qcolortrc_p.h
+++ b/src/gui/painting/qcolortrc_p.h
@@ -114,7 +114,7 @@ public:
if (x >= 0.0f && x <= 1.0f)
return applyInverse(x);
if (m_type == Type::Function)
- return std::copysign(applyInverse(x), x);
+ return std::copysign(applyInverse(std::abs(x)), x);
if (m_type == Type::Table)
return x < 0.0f ? 0.0f : 1.0f;
return x;
diff --git a/src/gui/painting/qcolortrclut_p.h b/src/gui/painting/qcolortrclut_p.h
index 76a6a60803..24fd522e6c 100644
--- a/src/gui/painting/qcolortrclut_p.h
+++ b/src/gui/painting/qcolortrclut_p.h
@@ -118,6 +118,7 @@ public:
return QRgba64::fromRgba64(r, g, b, qAlpha(rgb32) * 257);
#endif
}
+ QRgba64 toLinear64(QRgba64) const = delete;
QRgb toLinear(QRgb rgb32) const
{
diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp
index ced213e36d..aa3f148934 100644
--- a/src/gui/painting/qcompositionfunctions.cpp
+++ b/src/gui/painting/qcompositionfunctions.cpp
@@ -1045,12 +1045,12 @@ private:
static inline int mix_alpha(int da, int sa)
{
- return 255 - ((255 - sa) * (255 - da) >> 8);
+ return 255 - qt_div_255((255 - sa) * (255 - da));
}
static inline uint mix_alpha_rgb64(uint da, uint sa)
{
- return 65535 - ((65535 - sa) * (65535 - da) >> 16);
+ return 65535U - qt_div_65535((65535U - sa) * (65535U - da));
}
/*
@@ -1337,7 +1337,7 @@ static inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint
int da = qAlpha(d);
int sa = qAlpha(s);
-#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
+#define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
int r = OP( qRed(d), qRed(s));
int b = OP( qBlue(d), qBlue(s));
int g = OP(qGreen(d), qGreen(s));
@@ -1367,7 +1367,7 @@ static inline void comp_func_Screen_impl(QRgba64 *Q_DECL_RESTRICT dest, const QR
uint da = d.alpha();
uint sa = s.alpha();
-#define OP(a, b) 65535 - (((65535-a) * (65535-b)) >> 16)
+#define OP(a, b) 65535U - qt_div_65535((65535U-a) * (65535U-b))
uint r = OP( d.red(), s.red());
uint b = OP( d.blue(), s.blue());
uint g = OP(d.green(), s.green());
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
index b636f0739d..8501bd6989 100644
--- a/src/gui/painting/qcosmeticstroker.cpp
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -101,7 +101,7 @@ struct Dasher {
offset += stroker->patternLength;
dashIndex = 0;
- while (offset>= pattern[dashIndex])
+ while (dashIndex < stroker->patternSize - 1 && offset>= pattern[dashIndex])
++dashIndex;
// qDebug() << " dasher" << offset/64. << reverse << dashIndex;
@@ -250,7 +250,7 @@ void QCosmeticStroker::setup()
strokeSelection |= AntiAliased;
const QVector<qreal> &penPattern = state->lastPen.dashPattern();
- if (penPattern.isEmpty()) {
+ if (penPattern.isEmpty() || penPattern.size() > 1024) {
Q_ASSERT(!pattern && !reversePattern);
pattern = nullptr;
reversePattern = nullptr;
@@ -263,12 +263,12 @@ void QCosmeticStroker::setup()
patternLength = 0;
for (int i = 0; i < patternSize; ++i) {
- patternLength += (int) qMax(1. , penPattern.at(i)*64.);
+ patternLength += (int)qBound(1., penPattern.at(i) * 64, 65536.);
pattern[i] = patternLength;
}
patternLength = 0;
for (int i = 0; i < patternSize; ++i) {
- patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.);
+ patternLength += (int)qBound(1., penPattern.at(patternSize - 1 - i) * 64, 65536.);
reversePattern[i] = patternLength;
}
strokeSelection |= Dashed;
@@ -311,6 +311,8 @@ void QCosmeticStroker::setup()
// returns true if the whole line gets clipped away
bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
{
+ if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
+ return true;
// basic/rough clipping is done in floating point coordinates to avoid
// integer overflow problems.
if (x1 < xmin) {
@@ -365,14 +367,14 @@ bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2)
{
- if (p1 == p2) {
+ QPointF start = p1 * state->matrix;
+ QPointF end = p2 * state->matrix;
+
+ if (start == end) {
drawPoints(&p1, 1);
return;
}
- QPointF start = p1 * state->matrix;
- QPointF end = p2 * state->matrix;
-
patternOffset = state->lastPen.dashOffset()*64;
lastPixel.x = INT_MIN;
lastPixel.y = INT_MIN;
diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h
index 181d19da0b..8e519c400c 100644
--- a/src/gui/painting/qdatabuffer_p.h
+++ b/src/gui/painting/qdatabuffer_p.h
@@ -66,7 +66,10 @@ public:
{
capacity = res;
if (res) {
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Walloc-size-larger-than=")
buffer = (Type*) malloc(capacity * sizeof(Type));
+ QT_WARNING_POP
Q_CHECK_PTR(buffer);
} else {
buffer = nullptr;
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 7b3fffcceb..fe8ff2633b 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -887,9 +887,8 @@ static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar
static const QRgba64 *QT_FASTCALL convertGrayscale16ToRGBA64(QRgba64 *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *)
{
- const unsigned short *s = reinterpret_cast<const unsigned short *>(src);
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535);
+ buffer[i] = QRgba64::fromRgba64(src[i], src[i], src[i], 65535);
return buffer;
}
@@ -1420,7 +1419,7 @@ static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int in
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
for (int i = 0; i < count; ++i)
- d[i] = QRgba64::fromArgb32(src[i]);
+ d[i] = QRgba64::fromArgb32(src[i] | 0xff000000);
}
static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
@@ -1432,12 +1431,24 @@ static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *
return buffer;
}
+template<bool Mask>
static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QVector<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
- for (int i = 0; i < count; ++i)
+ for (int i = 0; i < count; ++i) {
d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied();
+ if (Mask)
+ d[i].setAlpha(65535);
+ }
+}
+
+static void QT_FASTCALL storeRGBA64FromARGB32(uchar *dest, const uint *src, int index, int count,
+ const QVector<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgba64::fromArgb32(src[i]);
}
// Note:
@@ -1524,15 +1535,15 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
{ false, false, QPixelLayout::BPP64, nullptr,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBX64
+ storeRGBA64FromARGB32PM<true>, storeRGB64FromRGB32 }, // Format_RGBX64
{ true, false, QPixelLayout::BPP64, nullptr,
convertARGB32ToARGB32PM, nullptr,
fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
- storeRGBA64FromARGB32PM, storeRGB64FromRGB32 }, // Format_RGBA64
+ storeRGBA64FromARGB32PM<false>, storeRGB64FromRGB32 }, // Format_RGBA64
{ true, true, QPixelLayout::BPP64, nullptr,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
+ storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
{ false, false, QPixelLayout::BPP16, nullptr,
convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
@@ -4018,6 +4029,7 @@ static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QIm
#define FIXPT_BITS 8
#define FIXPT_SIZE (1<<FIXPT_BITS)
+#define FIXPT_MAX (INT_MAX >> (FIXPT_BITS + 1))
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
{
@@ -4114,10 +4126,12 @@ static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template(
const BlendType *end = buffer + length;
if (affine) {
if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
- GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length);
+ if (std::abs(t) < FIXPT_MAX)
+ GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length);
+ else
+ GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, t / GRADIENT_STOPTABLE_SIZE), length);
} else {
- if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
- t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
+ if (std::abs(t) < FIXPT_MAX && std::abs(inc) < FIXPT_MAX && std::abs(t + inc * length) < FIXPT_MAX) {
// we can use fixed point math
int t_fixed = int(t * FIXPT_SIZE);
int inc_fixed = int(inc * FIXPT_SIZE);
@@ -6077,7 +6091,7 @@ static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba
static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
{
// Do a gammacorrected RGB alphablend...
- const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(dst) : dst;
+ const QRgba64 dlinear = colorProfile ? colorProfile->toLinear(dst) : dst;
QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
@@ -6725,7 +6739,7 @@ static void qInitDrawhelperFunctions()
qInitBlendFunctions();
#ifdef __SSE2__
-# ifndef __AVX2__
+# ifndef __haswell__
qt_memfill32 = qt_memfill32_sse2;
qt_memfill64 = qt_memfill64_sse2;
# endif
@@ -6830,7 +6844,7 @@ static void qInitDrawhelperFunctions()
const QVector<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
extern void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
-# ifndef __AVX2__
+# ifndef __haswell__
qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_sse4;
qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4;
qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_sse4;
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 77b5ab42c5..2f6b7f6bbf 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -233,7 +233,7 @@ void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, u
}
}
-#ifndef __AVX2__
+#ifndef __haswell__
static Q_NEVER_INLINE
void Q_DECL_VECTORCALL qt_memfillXX_aligned(void *dest, __m128i value128, quintptr bytecount)
{
@@ -317,7 +317,7 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, qsizetype count)
qt_memfillXX_aligned(dest, _mm_set1_epi32(value), count * sizeof(quint32));
}
-#endif // !__AVX2__
+#endif // !__haswell__
void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha)
{
diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp
index 68d887ae6d..8e4cfd702d 100644
--- a/src/gui/painting/qdrawhelper_sse4.cpp
+++ b/src/gui/painting/qdrawhelper_sse4.cpp
@@ -45,7 +45,7 @@
QT_BEGIN_NAMESPACE
-#ifndef __AVX2__
+#ifndef __haswell__
template<bool RGBA>
static void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int count)
{
@@ -141,7 +141,7 @@ static void convertARGBToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int cou
buffer[i] = QRgba64::fromArgb32(s).premultiplied();
}
}
-#endif // __AVX2__
+#endif // __haswell__
static inline __m128 Q_DECL_VECTORCALL reciprocal_mul_ps(__m128 a, float mul)
{
@@ -326,7 +326,7 @@ static inline void convertARGBFromRGBA64PM_sse4(uint *buffer, const QRgba64 *src
}
}
-#ifndef __AVX2__
+#ifndef __haswell__
void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *)
{
convertARGBToARGB32PM_sse4<false>(buffer, buffer, count);
@@ -378,7 +378,7 @@ const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const u
convertARGBToRGBA64PM_sse4<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
-#endif // __AVX2__
+#endif // __haswell__
void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
const QVector<QRgb> *, QDitherInfo *)
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index cb9afe3978..4651adbd2a 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -52,7 +52,7 @@
#include <array>
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc")
+Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc", QtWarningMsg)
struct ICCProfileHeader
{
@@ -165,7 +165,7 @@ struct XYZTagData : GenericTagData {
struct CurvTagData : GenericTagData {
quint32_be valueCount;
- quint16_be value[1];
+ // followed by curv values: quint16_be[]
};
struct ParaTagData : GenericTagData {
@@ -237,18 +237,20 @@ static bool isValidIccProfile(const ICCProfileHeader &header)
}
if (header.profileClass != uint(ProfileClass::Input)
- && header.profileClass != uint(ProfileClass::Display)) {
- qCWarning(lcIcc, "Unsupported ICC profile class %x", quint32(header.profileClass));
+ && header.profileClass != uint(ProfileClass::Display)
+ && (header.profileClass != uint(ProfileClass::Output)
+ || header.inputColorSpace != uint(ColorSpaceType::Gray))) {
+ qCInfo(lcIcc, "Unsupported ICC profile class 0x%x", quint32(header.profileClass));
return false;
}
if (header.inputColorSpace != uint(ColorSpaceType::Rgb)
&& header.inputColorSpace != uint(ColorSpaceType::Gray)) {
- qCWarning(lcIcc, "Unsupported ICC input color space %x", quint32(header.inputColorSpace));
+ qCInfo(lcIcc, "Unsupported ICC input color space 0x%x", quint32(header.inputColorSpace));
return false;
}
if (header.pcs != 0x58595a20 /* 'XYZ '*/) {
// ### support PCSLAB
- qCWarning(lcIcc, "Unsupported ICC profile connection space %x", quint32(header.pcs));
+ qCInfo(lcIcc, "Unsupported ICC profile connection space 0x%x", quint32(header.pcs));
return false;
}
@@ -468,28 +470,32 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
const GenericTagData trcData = qFromUnaligned<GenericTagData>(data.constData()
+ tagEntry.offset);
if (trcData.type == quint32(Tag::curv)) {
+ Q_STATIC_ASSERT(sizeof(CurvTagData) == 12);
const CurvTagData curv = qFromUnaligned<CurvTagData>(data.constData() + tagEntry.offset);
if (curv.valueCount > (1 << 16))
return false;
if (tagEntry.size - 12 < 2 * curv.valueCount)
return false;
+ const auto valueOffset = tagEntry.offset + sizeof(CurvTagData);
if (curv.valueCount == 0) {
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(); // Linear
} else if (curv.valueCount == 1) {
- float g = curv.value[0] * (1.0f / 256.0f);
+ const quint16 v = qFromBigEndian<quint16>(data.constData() + valueOffset);
gamma.m_type = QColorTrc::Type::Function;
- gamma.m_fun = QColorTransferFunction::fromGamma(g);
+ gamma.m_fun = QColorTransferFunction::fromGamma(v * (1.0f / 256.0f));
} else {
QVector<quint16> tabl;
tabl.resize(curv.valueCount);
static_assert(sizeof(GenericTagData) == 2 * sizeof(quint32_be),
"GenericTagData has padding. The following code is a subject to UB.");
- const auto offset = tagEntry.offset + sizeof(GenericTagData) + sizeof(quint32_be);
- qFromBigEndian<quint16>(data.constData() + offset, curv.valueCount, tabl.data());
+ qFromBigEndian<quint16>(data.constData() + valueOffset, curv.valueCount, tabl.data());
QColorTransferTable table = QColorTransferTable(curv.valueCount, std::move(tabl));
QColorTransferFunction curve;
- if (!table.asColorTransferFunction(&curve)) {
+ if (!table.checkValidity()) {
+ qCWarning(lcIcc) << "Invalid curv table";
+ return false;
+ } else if (!table.asColorTransferFunction(&curve)) {
gamma.m_type = QColorTrc::Type::Table;
gamma.m_table = table;
} else {
@@ -521,6 +527,8 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
return false;
std::array<quint32_be, 3> parameters =
qFromUnaligned<decltype(parameters)>(data.constData() + parametersOffset);
+ if (parameters[1] == 0)
+ return false;
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
@@ -534,6 +542,8 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
return false;
std::array<quint32_be, 4> parameters =
qFromUnaligned<decltype(parameters)>(data.constData() + parametersOffset);
+ if (parameters[1] == 0)
+ return false;
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
@@ -643,7 +653,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
const ICCProfileHeader header = qFromUnaligned<ICCProfileHeader>(data.constData());
if (!isValidIccProfile(header))
return false; // if failed we already printing a warning
- if (qsizetype(header.profileSize) > data.size()) {
+ if (qsizetype(header.profileSize) > data.size() || qsizetype(header.profileSize) < qsizetype(sizeof(ICCProfileHeader))) {
qCWarning(lcIcc) << "fromIccProfile: failed size sanity 2";
return false;
}
@@ -695,7 +705,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) ||
!tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) ||
!tagIndex.contains(Tag::wtpt)) {
- qCWarning(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based";
+ qCInfo(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based";
return false;
}
} else {
@@ -740,7 +750,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
QColorVector whitePoint;
if (!parseXyzData(data, tagIndex[Tag::wtpt], whitePoint))
return false;
- if (!qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z - whitePoint.x) == 0.0f) {
+ if (!qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z + whitePoint.x) == 0.0f) {
qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - gray white-point not normalized";
return false;
}
@@ -749,12 +759,12 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
} else {
colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
// Calculate chromaticity from xyz (assuming y == 1.0f).
- float y = 1.0f / (1.0f + whitePoint.z - whitePoint.x);
+ float y = 1.0f / (1.0f + whitePoint.z + whitePoint.x);
float x = whitePoint.x * y;
QColorSpacePrimaries primaries(QColorSpace::Primaries::SRgb);
primaries.whitePoint = QPointF(x,y);
if (!primaries.areValid()) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - invalid white-point";
+ qCWarning(lcIcc, "fromIccProfile: Invalid ICC profile - invalid white-point(%f, %f)", x, y);
return false;
}
colorspaceDPtr->toXyz = primaries.toXyzMatrix();
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp
index aac1e20f7b..86057cdd33 100644
--- a/src/gui/painting/qimagescale.cpp
+++ b/src/gui/painting/qimagescale.cpp
@@ -308,7 +308,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
diff --git a/src/gui/painting/qimagescale_neon.cpp b/src/gui/painting/qimagescale_neon.cpp
index 046e56b419..3c87ac8773 100644
--- a/src/gui/painting/qimagescale_neon.cpp
+++ b/src/gui/painting/qimagescale_neon.cpp
@@ -59,7 +59,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp
index 70cfa08d95..a5c9e68fad 100644
--- a/src/gui/painting/qimagescale_sse4.cpp
+++ b/src/gui/painting/qimagescale_sse4.cpp
@@ -60,7 +60,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index 685fbbb37a..b82adb5d35 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -43,12 +43,11 @@ QT_BEGIN_NAMESPACE
static const int tileSize = 32;
-template <class T>
-static
-inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
+template<class T>
+static inline void qt_memrotate90_tiled(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
- sstride /= sizeof(T);
- dstride /= sizeof(T);
+ const qsizetype sstride = isstride / sizeof(T);
+ const qsizetype dstride = idstride / sizeof(T);
const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
@@ -102,11 +101,11 @@ inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *des
}
}
-template <class T>
-static
-inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
+template<class T>
+static inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
const int numTilesX = (w + tileSize - 1) / tileSize;
const int numTilesY = (h + tileSize - 1) / tileSize;
@@ -130,12 +129,11 @@ inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int sstrid
}
}
-template <class T>
-static
-inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
+template<class T>
+static inline void qt_memrotate270_tiled(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
- sstride /= sizeof(T);
- dstride /= sizeof(T);
+ const qsizetype sstride = isstride / sizeof(T);
+ const qsizetype dstride = idstride / sizeof(T);
const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
@@ -189,11 +187,11 @@ inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *de
}
}
-template <class T>
-static
-inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
+template<class T>
+static inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
const int numTilesX = (w + tileSize - 1) / tileSize;
const int numTilesY = (h + tileSize - 1) / tileSize;
@@ -245,10 +243,12 @@ inline void qt_memrotate90_template<quint64>(const quint64 *src, int w, int h, i
qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
-template <class T>
-static
-inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
+template<class T>
+static inline void qt_memrotate180_template(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
+
const char *s = (const char*)(src) + (h - 1) * sstride;
for (int dy = 0; dy < h; ++dy) {
T *d = reinterpret_cast<T*>((char *)(dest) + dy * dstride);
diff --git a/src/gui/painting/qpagesize.h b/src/gui/painting/qpagesize.h
index 133274760f..5b53eae458 100644
--- a/src/gui/painting/qpagesize.h
+++ b/src/gui/painting/qpagesize.h
@@ -228,7 +228,7 @@ public:
};
QPageSize();
- explicit QPageSize(PageSizeId pageSizeId);
+ /*implicit*/ QPageSize(PageSizeId pageSizeId);
explicit QPageSize(const QSize &pointSize,
const QString &name = QString(),
SizeMatchPolicy matchPolicy = FuzzyMatch);
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index a3e199cec9..38bad9a6b0 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -560,31 +560,6 @@ void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
QRasterPaintEngineState *s = state();
// FALCON: get rid of this line, see drawImage call below.
s->matrix = matrix;
- QTransform::TransformationType txop = s->matrix.type();
-
- switch (txop) {
-
- case QTransform::TxNone:
- s->flags.int_xform = true;
- break;
-
- case QTransform::TxTranslate:
- s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
- && qreal(int(s->matrix.dy())) == s->matrix.dy();
- break;
-
- case QTransform::TxScale:
- s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
- && qreal(int(s->matrix.dy())) == s->matrix.dy()
- && qreal(int(s->matrix.m11())) == s->matrix.m11()
- && qreal(int(s->matrix.m22())) == s->matrix.m22();
- break;
-
- default: // shear / perspective...
- s->flags.int_xform = false;
- break;
- }
-
s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
ensureOutlineMapper();
@@ -617,7 +592,6 @@ QRasterPaintEngineState::QRasterPaintEngineState()
flags.bilinear = false;
flags.legacy_rounding = false;
flags.fast_text = true;
- flags.int_xform = true;
flags.tx_noshear = true;
flags.fast_images = true;
@@ -1793,7 +1767,7 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
QRectF cpRect = path.controlPointRect();
const QRectF pathDeviceRect = s->matrix.mapRect(cpRect);
// Skip paths that by conservative estimates are completely outside the paint device.
- if (!pathDeviceRect.intersects(QRectF(d->deviceRect)))
+ if (!pathDeviceRect.intersects(QRectF(d->deviceRect)) || !pathDeviceRect.isValid())
return;
ProcessSpans blend = d->getBrushFunc(pathDeviceRect, &s->brushData);
@@ -2414,15 +2388,20 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
QRectF targetBounds = s->matrix.mapRect(r);
bool exceedsPrecision = r.width() > 0x7fff
|| r.height() > 0x7fff
+ || targetBounds.left() < -0x7fff
+ || targetBounds.top() < -0x7fff
+ || targetBounds.right() > 0x7fff
+ || targetBounds.bottom() > 0x7fff
|| targetBounds.width() > 0x7fff
|| targetBounds.height() > 0x7fff
|| s->matrix.m11() >= 512
|| s->matrix.m22() >= 512;
-
if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
if (s->matrix.type() > QTransform::TxScale) {
SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
- if (func && (!clip || clip->hasRectClip)) {
+ // The fast transform methods doesn't really work on small targets, see QTBUG-93475
+ // And it can't antialias the edges
+ if (func && (!clip || clip->hasRectClip) && !s->flags.antialiased && targetBounds.width() >= 16 && targetBounds.height() >= 16) {
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
s->matrix, s->intOpacity);
@@ -3090,10 +3069,10 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
{
- QFixed clipLeft = QFixed::fromReal(clip.left());
- QFixed clipRight = QFixed::fromReal(clip.right());
- QFixed clipTop = QFixed::fromReal(clip.top());
- QFixed clipBottom = QFixed::fromReal(clip.bottom());
+ QFixed clipLeft = QFixed::fromReal(clip.left() - 1);
+ QFixed clipRight = QFixed::fromReal(clip.right() + 1);
+ QFixed clipTop = QFixed::fromReal(clip.top() - 1);
+ QFixed clipBottom = QFixed::fromReal(clip.bottom() + 1);
int first = 0;
while (first < numGlyphs) {
@@ -3309,6 +3288,11 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
qreal length = line.length();
Q_ASSERT(length > 0);
+ if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
+ rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
+ return;
+ }
+
while (length > 0) {
const bool rasterize = *inDash;
qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
@@ -3575,7 +3559,7 @@ QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
\internal
Returns the bounding rect of the currently set clip.
*/
-QRect QRasterPaintEngine::clipBoundingRect() const
+QRectF QRasterPaintEngine::clipBoundingRect() const
{
Q_D(const QRasterPaintEngine);
@@ -3587,7 +3571,7 @@ QRect QRasterPaintEngine::clipBoundingRect() const
if (clip->hasRectClip)
return clip->clipRect;
- return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
+ return QRectF(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
}
void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index 089aadc3f7..7b15292ebb 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -111,7 +111,6 @@ public:
uint bilinear : 1;
uint legacy_rounding : 1;
uint fast_text : 1;
- uint int_xform : 1;
uint tx_noshear : 1;
uint fast_images : 1;
};
@@ -206,7 +205,7 @@ public:
ComplexClip
};
ClipType clipType() const;
- QRect clipBoundingRect() const;
+ QRectF clipBoundingRect() const;
#ifdef Q_OS_WIN
void setDC(HDC hdc);
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 5d8f89eadd..9d8e068a5f 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -385,7 +385,7 @@ QPainterState *QPaintEngineEx::createState(QPainterState *orig) const
Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
-void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
+void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
{
#ifdef QT_DEBUG_DRAW
qDebug() << "QPaintEngineEx::stroke()" << pen;
@@ -403,6 +403,38 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
d->stroker.setCubicToHook(qpaintengineex_cubicTo);
}
+ QRectF clipRect;
+ QPen pen = inPen;
+ if (pen.style() > Qt::SolidLine) {
+ QRectF cpRect = path.controlPointRect();
+ const QTransform &xf = state()->matrix;
+ if (qt_pen_is_cosmetic(pen, state()->renderHints)) {
+ clipRect = d->exDeviceRect;
+ cpRect.translate(xf.dx(), xf.dy());
+ } else {
+ clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
+ }
+ // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
+ qreal pw = pen.widthF() ? pen.widthF() : 1;
+ QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
+ qreal extent = qMax(extentRect.width(), extentRect.height());
+ qreal patternLength = 0;
+ const QVector<qreal> pattern = pen.dashPattern();
+ const int patternSize = qMin(pattern.size(), 32);
+ for (int i = 0; i < patternSize; i++)
+ patternLength += qMax(pattern.at(i), qreal(0));
+ patternLength *= pw;
+ if (qFuzzyIsNull(patternLength)) {
+ pen.setStyle(Qt::NoPen);
+ } else if (extent / patternLength > QDashStroker::repetitionLimit()) {
+ // approximate stream of tiny dashes with semi-transparent solid line
+ pen.setStyle(Qt::SolidLine);
+ QColor color(pen.color());
+ color.setAlpha(color.alpha() / 2);
+ pen.setColor(color);
+ }
+ }
+
if (!qpen_fast_equals(pen, d->strokerPen)) {
d->strokerPen = pen;
d->stroker.setJoinStyle(pen.joinStyle());
@@ -430,14 +462,8 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
return;
}
- if (pen.style() > Qt::SolidLine) {
- if (qt_pen_is_cosmetic(pen, state()->renderHints)){
- d->activeStroker->setClipRect(d->exDeviceRect);
- } else {
- QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect));
- d->activeStroker->setClipRect(clipRect);
- }
- }
+ if (!clipRect.isNull())
+ d->activeStroker->setClipRect(clipRect);
if (d->activeStroker == &d->stroker)
d->stroker.setForceOpen(path.hasExplicitOpen());
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index aaeb0e86a2..fdb7f331aa 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -175,6 +175,23 @@ static bool qt_painter_thread_test(int devType, int engineType, const char *what
}
#endif
+static bool needsEmulation(const QBrush &brush)
+{
+ bool res = false;
+
+ const QGradient *bg = brush.gradient();
+ if (bg) {
+ res = (bg->coordinateMode() > QGradient::LogicalMode);
+ } else if (brush.style() == Qt::TexturePattern) {
+ if (qHasPixmapTexture(brush))
+ res = !qFuzzyCompare(brush.texture().devicePixelRatio(), qreal(1.0));
+ else
+ res = !qFuzzyCompare(brush.textureImage().devicePixelRatio(), qreal(1.0));
+ }
+
+ return res;
+}
+
void QPainterPrivate::checkEmulation()
{
Q_ASSERT(extended);
@@ -182,21 +199,12 @@ void QPainterPrivate::checkEmulation()
if (state->bgMode == Qt::OpaqueMode)
doEmulation = true;
- const QGradient *bg = state->brush.gradient();
- if (bg && bg->coordinateMode() > QGradient::LogicalMode)
+ if (needsEmulation(state->brush))
doEmulation = true;
- const QGradient *pg = qpen_brush(state->pen).gradient();
- if (pg && pg->coordinateMode() > QGradient::LogicalMode)
+ if (needsEmulation(qpen_brush(state->pen)))
doEmulation = true;
- if (state->brush.style() == Qt::TexturePattern) {
- if (qHasPixmapTexture(state->brush))
- doEmulation |= !qFuzzyCompare(state->brush.texture().devicePixelRatioF(), 1.0);
- else
- doEmulation |= !qFuzzyCompare(state->brush.textureImage().devicePixelRatioF(), 1.0);
- }
-
if (doEmulation && extended->flags() & QPaintEngineEx::DoNotEmulate)
return;
@@ -3319,12 +3327,9 @@ void QPainter::strokePath(const QPainterPath &path, const QPen &pen)
if (path.isEmpty())
return;
- if (d->extended) {
- const QGradient *g = qpen_brush(pen).gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->stroke(qtVectorPathForPath(path), pen);
- return;
- }
+ if (d->extended && !needsEmulation(pen.brush())) {
+ d->extended->stroke(qtVectorPathForPath(path), pen);
+ return;
}
QBrush oldBrush = d->state->brush;
@@ -3362,12 +3367,9 @@ void QPainter::fillPath(const QPainterPath &path, const QBrush &brush)
if (path.isEmpty())
return;
- if (d->extended) {
- const QGradient *g = brush.gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->fill(qtVectorPathForPath(path), brush);
- return;
- }
+ if (d->extended && !needsEmulation(brush)) {
+ d->extended->fill(qtVectorPathForPath(path), brush);
+ return;
}
QBrush oldBrush = d->state->brush;
@@ -6956,12 +6958,9 @@ void QPainter::fillRect(const QRectF &r, const QBrush &brush)
if (!d->engine)
return;
- if (d->extended) {
- const QGradient *g = brush.gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->fillRect(r, brush);
- return;
- }
+ if (d->extended && !needsEmulation(brush)) {
+ d->extended->fillRect(r, brush);
+ return;
}
QPen oldPen = pen();
@@ -6994,12 +6993,9 @@ void QPainter::fillRect(const QRect &r, const QBrush &brush)
if (!d->engine)
return;
- if (d->extended) {
- const QGradient *g = brush.gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->fillRect(r, brush);
- return;
- }
+ if (d->extended && !needsEmulation(brush)) {
+ d->extended->fillRect(r, brush);
+ return;
}
QPen oldPen = pen();
@@ -8592,3 +8588,5 @@ void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivat
}
QT_END_NAMESPACE
+
+#include "moc_qpainter.cpp"
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index ab60afd9cd..f9544a3241 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1222,6 +1222,11 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &
QTextLayout layout(text, f);
layout.setCacheEnabled(true);
+
+ QTextOption opt = layout.textOption();
+ opt.setUseDesignMetrics(true);
+ layout.setTextOption(opt);
+
QTextEngine *eng = layout.engine();
layout.beginLayout();
QTextLine line = layout.createLine();
@@ -1367,7 +1372,7 @@ void QPainterPath::addRegion(const QRegion &region)
*/
Qt::FillRule QPainterPath::fillRule() const
{
- return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
+ return !d_func() ? Qt::OddEvenFill : d_func()->fillRule;
}
/*!
diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h
index a420e0b3d9..287265653a 100644
--- a/src/gui/painting/qpainterpath_p.h
+++ b/src/gui/painting/qpainterpath_p.h
@@ -313,7 +313,6 @@ inline void QPainterPathData::clear()
elements.clear();
cStart = 0;
- fillRule = Qt::OddEvenFill;
bounds = {};
controlBounds = {};
diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h
index 9444a87b71..18f64c5e8c 100644
--- a/src/gui/painting/qpathclipper_p.h
+++ b/src/gui/painting/qpathclipper_p.h
@@ -156,7 +156,7 @@ public:
int vertex(Direction direction) const;
private:
- int m_next[2][2];
+ int m_next[2][2] = { { -1, -1 }, { -1, -1 } };
};
class QPathSegments
@@ -296,10 +296,6 @@ inline QPathEdge::QPathEdge(int a, int b)
, angle(0)
, invAngle(0)
{
- m_next[0][0] = -1;
- m_next[1][0] = -1;
- m_next[0][0] = -1;
- m_next[1][0] = -1;
}
inline int QPathEdge::next(Traversal traversal, Direction direction) const
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index de9fc13331..3066744f1b 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -856,14 +856,14 @@ void QPdfEngine::drawRects (const QRectF *rects, int rectCount)
if (!d->hasPen && !d->hasBrush)
return;
- if (d->simplePen || !d->hasPen) {
- // draw strokes natively in this case for better output
- if(!d->simplePen && !d->stroker.matrix.isIdentity())
+ if ((d->simplePen && !d->needsTransform) || !d->hasPen) {
+ // draw natively in this case for better output
+ if (!d->hasPen && d->needsTransform) // i.e. this is just a fillrect
*d->currentPage << "q\n" << QPdf::generateMatrix(d->stroker.matrix);
for (int i = 0; i < rectCount; ++i)
*d->currentPage << rects[i].x() << rects[i].y() << rects[i].width() << rects[i].height() << "re\n";
*d->currentPage << (d->hasPen ? (d->hasBrush ? "B\n" : "S\n") : "f\n");
- if(!d->simplePen && !d->stroker.matrix.isIdentity())
+ if (!d->hasPen && d->needsTransform)
*d->currentPage << "Q\n";
} else {
QPainterPath p;
@@ -920,7 +920,8 @@ void QPdfEngine::drawPath (const QPainterPath &p)
if (d->simplePen) {
// draw strokes natively in this case for better output
- *d->currentPage << QPdf::generatePath(p, QTransform(), d->hasBrush ? QPdf::FillAndStrokePath : QPdf::StrokePath);
+ *d->currentPage << QPdf::generatePath(p, d->needsTransform ? d->stroker.matrix : QTransform(),
+ d->hasBrush ? QPdf::FillAndStrokePath : QPdf::StrokePath);
} else {
if (d->hasBrush)
*d->currentPage << QPdf::generatePath(p, d->stroker.matrix, QPdf::FillPath);
@@ -967,7 +968,7 @@ void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, con
*d->currentPage
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
- rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
+ rectangle.x(), rectangle.y()) * (!d->needsTransform ? QTransform() : d->stroker.matrix));
if (bitmap) {
// set current pen as d->brush
d->brush = d->pen.brush();
@@ -1007,7 +1008,7 @@ void QPdfEngine::drawImage(const QRectF &rectangle, const QImage &image, const Q
*d->currentPage
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
- rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
+ rectangle.x(), rectangle.y()) * (!d->needsTransform ? QTransform() : d->stroker.matrix));
setBrush();
d->currentPage->streamImage(im.width(), im.height(), object);
*d->currentPage << "Q\n";
@@ -1056,7 +1057,7 @@ void QPdfEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
}
*d->currentPage << "q\n";
- if(!d->simplePen)
+ if (d->needsTransform)
*d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
bool hp = d->hasPen;
@@ -1135,12 +1136,12 @@ void QPdfEngine::updateState(const QPaintEngineState &state)
d->pen = state.pen();
}
d->hasPen = d->pen.style() != Qt::NoPen;
+ bool oldCosmetic = d->stroker.cosmeticPen;
d->stroker.setPen(d->pen, state.renderHints());
QBrush penBrush = d->pen.brush();
- bool cosmeticPen = qt_pen_is_cosmetic(d->pen, state.renderHints());
bool oldSimple = d->simplePen;
- d->simplePen = (d->hasPen && !cosmeticPen && (penBrush.style() == Qt::SolidPattern) && penBrush.isOpaque() && d->opacity == 1.0);
- if (oldSimple != d->simplePen)
+ d->simplePen = (d->hasPen && (penBrush.style() == Qt::SolidPattern) && penBrush.isOpaque() && d->opacity == 1.0);
+ if (oldSimple != d->simplePen || oldCosmetic != d->stroker.cosmeticPen)
flags |= DirtyTransform;
} else if (flags & DirtyHints) {
d->stroker.setPen(d->pen, state.renderHints());
@@ -1224,8 +1225,13 @@ void QPdfEngine::setupGraphicsState(QPaintEngine::DirtyFlags flags)
if (flags & DirtyTransform) {
*d->currentPage << "q\n";
- if (d->simplePen && !d->stroker.matrix.isIdentity())
- *d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
+ d->needsTransform = false;
+ if (!d->stroker.matrix.isIdentity()) {
+ if (d->simplePen && !d->stroker.cosmeticPen)
+ *d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
+ else
+ d->needsTransform = true; // I.e. page-wide xf not set, local xf needed
+ }
}
if (flags & DirtyBrush)
setBrush();
@@ -1480,7 +1486,7 @@ int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
QPdfEnginePrivate::QPdfEnginePrivate()
: clipEnabled(false), allClipped(false), hasPen(true), hasBrush(false), simplePen(false),
- pdfVersion(QPdfEngine::Version_1_4),
+ needsTransform(false), pdfVersion(QPdfEngine::Version_1_4),
outDevice(nullptr), ownsDevice(false),
embedFonts(true),
grayscale(false),
@@ -1539,6 +1545,7 @@ bool QPdfEngine::begin(QPaintDevice *pdev)
d->graphicsState = 0;
d->patternColorSpace = 0;
d->simplePen = false;
+ d->needsTransform = false;
d->pages.clear();
d->imageCache.clear();
diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h
index 4ff540e67b..6964c67d93 100644
--- a/src/gui/painting/qpdf_p.h
+++ b/src/gui/painting/qpdf_p.h
@@ -271,6 +271,7 @@ public:
bool hasPen;
bool hasBrush;
bool simplePen;
+ bool needsTransform;
qreal opacity;
QPdfEngine::PdfVersion pdfVersion;
diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp
index cf30ea496c..ae140f31b5 100644
--- a/src/gui/painting/qpdfwriter.cpp
+++ b/src/gui/painting/qpdfwriter.cpp
@@ -489,4 +489,6 @@ QT_WARNING_POP
QT_END_NAMESPACE
+#include "moc_qpdfwriter.cpp"
+
#endif // QT_NO_PDF
diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp
index 01e581d2ed..254abf88c0 100644
--- a/src/gui/painting/qpen.cpp
+++ b/src/gui/painting/qpen.cpp
@@ -653,12 +653,15 @@ qreal QPen::widthF() const
*/
void QPen::setWidth(int width)
{
- if (width < 0)
- qWarning("QPen::setWidth: Setting a pen width with a negative value is not defined");
+ if (width < 0 || width >= (1 << 15)) {
+ qWarning("QPen::setWidth: Setting a pen width that is out of range");
+ return;
+ }
if ((qreal)width == d->width)
return;
detach();
d->width = width;
+ d->defaultWidth = false;
}
/*!
@@ -677,8 +680,8 @@ void QPen::setWidth(int width)
void QPen::setWidthF(qreal width)
{
- if (width < 0.f) {
- qWarning("QPen::setWidthF: Setting a pen width with a negative value is not defined");
+ if (width < 0.f || width >= (1 << 15)) {
+ qWarning("QPen::setWidthF: Setting a pen width that is out of range");
return;
}
if (qAbs(d->width - width) < 0.00000001f)
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index c092a7153f..9c9b053b2b 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -751,3 +751,5 @@ bool QPlatformBackingStore::scroll(const QRegion &area, int dx, int dy)
}
QT_END_NAMESPACE
+
+#include "moc_qplatformbackingstore.cpp"
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 2ecc97af04..13ffd93640 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -3647,6 +3647,8 @@ static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
POINTBLOCK *tmpPtBlock;
int numFullPtBlocks = 0;
+ Q_ASSUME(Count > 1);
+
region = new QRegionPrivate;
/* special case a rectangle */
diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp
index 22302f9790..3b6357a893 100644
--- a/src/gui/painting/qstroker.cpp
+++ b/src/gui/painting/qstroker.cpp
@@ -1179,32 +1179,42 @@ void QDashStroker::processCurrentSubpath()
bool done = pos >= estop;
- if (clipping) {
- // Check if the entire line can be clipped away.
- if (!lineIntersectsRect(prev, e, clip_tl, clip_br)) {
- // Cut away full dash sequences.
- elen -= qFloor(elen * invSumLength) * sumLength;
- // Update dash offset.
- while (!done) {
- qreal dpos = pos + dashes[idash] - doffset - estart;
-
- Q_ASSERT(dpos >= 0);
-
- if (dpos > elen) { // dash extends this line
- doffset = dashes[idash] - (dpos - elen); // subtract the part already used
- pos = estop; // move pos to next path element
- done = true;
- } else { // Dash is on this line
- pos = dpos + estart;
- done = pos >= estop;
- if (++idash >= dashCount)
- idash = 0;
- doffset = 0; // full segment so no offset on next.
- }
+ // Check if the entire line should be clipped away or simplified
+ bool clipIt = clipping && !lineIntersectsRect(prev, e, clip_tl, clip_br);
+ bool skipDashing = elen * invSumLength > repetitionLimit();
+ int maxDashes = dashCount;
+ if (skipDashing || clipIt) {
+ // Cut away full dash sequences.
+ elen -= std::floor(elen * invSumLength) * sumLength;
+ // Update dash offset.
+ while (!done) {
+ qreal dpos = pos + dashes[idash] - doffset - estart;
+
+ Q_ASSERT(dpos >= 0);
+
+ if (dpos > elen) { // dash extends this line
+ doffset = dashes[idash] - (dpos - elen); // subtract the part already used
+ pos = estop; // move pos to next path element
+ done = true;
+ } else { // Dash is on this line
+ pos = --maxDashes > 0 ? dpos + estart : estop;
+ done = pos >= estop;
+ if (++idash >= dashCount)
+ idash = 0;
+ doffset = 0; // full segment so no offset on next.
}
+ }
+ if (clipIt) {
hasMoveTo = false;
- move_to_pos = e;
+ } else {
+ // skip costly dashing, just draw solid line
+ if (!hasMoveTo) {
+ emitMoveTo(move_to_pos.x, move_to_pos.y);
+ hasMoveTo = true;
+ }
+ emitLineTo(e.x, e.y);
}
+ move_to_pos = e;
}
// Dash away...
diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h
index 06446ae3df..72e211d046 100644
--- a/src/gui/painting/qstroker_p.h
+++ b/src/gui/painting/qstroker_p.h
@@ -268,6 +268,7 @@ public:
QStroker *stroker() const { return m_stroker; }
static QVector<qfixed> patternForStyle(Qt::PenStyle style);
+ static int repetitionLimit() { return 10000; }
void setDashPattern(const QVector<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
QVector<qfixed> dashPattern() const { return m_dashPattern; }
diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json
index 7b16e8c211..1a2b907606 100644
--- a/src/gui/painting/qt_attribution.json
+++ b/src/gui/painting/qt_attribution.json
@@ -10,7 +10,7 @@
"Homepage": "http://www.freetype.org",
"License": "Freetype Project License or GNU General Public License v2.0 only",
"LicenseId": "FTL or GPL-2.0",
- "LicenseFile": "../../3rdparty/freetype/docs/LICENSE.TXT",
+ "LicenseFile": "../../3rdparty/freetype/LICENSE.txt",
"Copyright": "Copyright 2000-2016 by David Turner, Robert Wilhelm, and Werner Lemberg."
},
{
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 141b195a42..7b2fcc2239 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -93,7 +93,7 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const
}
bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
- const QFixedPoint *positions)
+ const QFixedPoint *positions, bool includeGlyphCacheScale)
{
#ifdef CACHE_DEBUG
printf("Populating with %d glyphs\n", numGlyphs);
@@ -120,6 +120,8 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
m_cy = padding;
}
+ qreal glyphCacheScaleX = transform().m11();
+
QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
int rowHeight = 0;
@@ -130,6 +132,8 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
QFixed subPixelPosition;
if (supportsSubPixelPositions) {
QFixed x = positions != nullptr ? positions[i].x : QFixed();
+ if (includeGlyphCacheScale)
+ x = QFixed::fromReal(x.toReal() * glyphCacheScaleX);
subPixelPosition = fontEngine->subPixelPositionForX(x);
}
diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h
index b6fc7230a8..cbf5224039 100644
--- a/src/gui/painting/qtextureglyphcache_p.h
+++ b/src/gui/painting/qtextureglyphcache_p.h
@@ -110,7 +110,7 @@ public:
};
bool populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
- const QFixedPoint *positions);
+ const QFixedPoint *positions, bool includeGlyphCacheScale = false);
bool hasPendingGlyphs() const { return !m_pendingGlyphs.isEmpty(); };
void fillInPendingGlyphs();
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index 9d8bb0c3e2..e86aff1cae 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -222,6 +222,7 @@ static void nanWarning(const char *func)
transformation is achieved by setting both the projection factors and
the scaling factors.
+ \section2 Combining Transforms
Here's the combined transformations example using basic matrix
operations:
@@ -232,6 +233,26 @@ static void nanWarning(const char *func)
\snippet transform/main.cpp 2
\endtable
+ The combined transform first scales each operand, then rotates it, and
+ finally translates it, just as in the order in which the product of its
+ factors is written. This means the point to which the transforms are
+ applied is implicitly multiplied on the left with the transform
+ to its right.
+
+ \section2 Relation to Matrix Notation
+ The matrix notation in QTransform is the transpose of a commonly-taught
+ convention which represents transforms and points as matrices and vectors.
+ That convention multiplies its matrix on the left and column vector to the
+ right. In other words, when several transforms are applied to a point, the
+ right-most matrix acts directly on the vector first. Then the next matrix
+ to the left acts on the result of the first operation - and so on. As a
+ result, that convention multiplies the matrices that make up a composite
+ transform in the reverse of the order in QTransform, as you can see in
+ \l {Combining Transforms}. Transposing the matrices, and combining them to
+ the right of a row vector that represents the point, lets the matrices of
+ transforms appear, in their product, in the order in which we think of the
+ transforms being applied to the point.
+
\sa QPainter, {Coordinate System}, {painting/affine}{Affine
Transformations Example}, {Transformations Example}
*/
@@ -2126,7 +2147,7 @@ QTransform::TransformationType QTransform::type() const
case TxShear:
case TxRotate:
if (!qFuzzyIsNull(affine._m12) || !qFuzzyIsNull(affine._m21)) {
- const qreal dot = affine._m11 * affine._m12 + affine._m21 * affine._m22;
+ const qreal dot = affine._m11 * affine._m21 + affine._m12 * affine._m22;
if (qFuzzyIsNull(dot))
m_type = TxRotate;
else
diff --git a/src/gui/painting/qtriangulatingstroker.cpp b/src/gui/painting/qtriangulatingstroker.cpp
index 9490e11dd9..bdcf49d6c8 100644
--- a/src/gui/painting/qtriangulatingstroker.cpp
+++ b/src/gui/painting/qtriangulatingstroker.cpp
@@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE
void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal *cur,
bool implicitClose, bool endsAtStart)
{
+ Q_ASSERT(start);
if (endsAtStart) {
join(start + 2);
} else if (implicitClose) {
diff --git a/src/gui/qtgui.tracepoints b/src/gui/qtgui.tracepoints
index 932115fd97..a85f905454 100644
--- a/src/gui/qtgui.tracepoints
+++ b/src/gui/qtgui.tracepoints
@@ -1,6 +1,9 @@
{
QT_BEGIN_NAMESPACE
class QImageReader;
+#include <private/qopengl2pexvertexarray_p.h>
+#include <private/qopengltextureuploader_p.h>
+#include <qopenglframebufferobject.h>
QT_END_NAMESPACE
}
@@ -39,3 +42,10 @@ QPixmap_scaledToHeight_exit()
QImageReader_read_before_reading(QImageReader *reader, const QString &filename)
QImageReader_read_after_reading(QImageReader *reader, bool result)
+
+QOpenGLFramebufferObjectPrivate_init_entry(QOpenGLFramebufferObject *qfbo, const QSize &size, QOpenGLFramebufferObject::Attachment attachment, GLenum texture_target, GLenum internal_format, GLint samples, bool mipmap)
+QOpenGLFramebufferObjectPrivate_init_exit()
+QOpenGL2PaintEngineExPrivate_drawTexture_entry(const QOpenGLRect& dest, const QOpenGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
+QOpenGL2PaintEngineExPrivate_drawTexture_exit()
+QOpenGLTextureCache_bindTexture_entry(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureUploader::BindOptions options)
+QOpenGLTextureCache_bindTexture_exit()
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 65f0a2262b..ac6c43693b 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -131,7 +131,7 @@ QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *import
dev = reinterpret_cast<ID3D11Device *>(importDevice->dev);
if (dev) {
ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(importDevice->context);
- if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
+ if (SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)))) {
// get rid of the ref added by QueryInterface
ctx->Release();
} else {
@@ -171,7 +171,7 @@ static IDXGIFactory1 *createDXGIFactory2()
using PtrCreateDXGIFactory2 = HRESULT (WINAPI *)(UINT, REFIID, void **);
QSystemLibrary dxgilib(QStringLiteral("dxgi"));
if (auto createDXGIFactory2 = reinterpret_cast<PtrCreateDXGIFactory2>(dxgilib.resolve("CreateDXGIFactory2"))) {
- const HRESULT hr = createDXGIFactory2(0, IID_IDXGIFactory2, reinterpret_cast<void **>(&result));
+ const HRESULT hr = createDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&result));
if (FAILED(hr)) {
qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", qPrintable(comErrorMessage(hr)));
result = nullptr;
@@ -186,7 +186,7 @@ static IDXGIFactory1 *createDXGIFactory2()
static IDXGIFactory1 *createDXGIFactory1()
{
IDXGIFactory1 *result = nullptr;
- const HRESULT hr = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast<void **>(&result));
+ const HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void **>(&result));
if (FAILED(hr)) {
qWarning("CreateDXGIFactory1() failed to create DXGI factory: %s", qPrintable(comErrorMessage(hr)));
result = nullptr;
@@ -269,7 +269,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
qWarning("Failed to create D3D11 device and context: %s", qPrintable(comErrorMessage(hr)));
return false;
}
- if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
+ if (SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)))) {
ctx->Release();
} else {
qWarning("ID3D11DeviceContext1 not supported");
@@ -280,7 +280,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
featureLevel = dev->GetFeatureLevel();
}
- if (FAILED(context->QueryInterface(IID_ID3DUserDefinedAnnotation, reinterpret_cast<void **>(&annotations))))
+ if (FAILED(context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), reinterpret_cast<void **>(&annotations))))
annotations = nullptr;
deviceLost = false;
@@ -336,7 +336,7 @@ void QRhiD3D11::reportLiveObjects(ID3D11Device *device)
{
// this works only when params.enableDebugLayer was true
ID3D11Debug *debug;
- if (SUCCEEDED(device->QueryInterface(IID_ID3D11Debug, reinterpret_cast<void **>(&debug)))) {
+ if (SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void **>(&debug)))) {
debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
debug->Release();
}
@@ -4197,7 +4197,7 @@ bool QD3D11SwapChain::buildOrResize()
// swapchain."
// So just query index 0 once (per resize) and be done with it.
- HRESULT hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast<void **>(&backBufferTex));
+ HRESULT hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBufferTex));
if (FAILED(hr)) {
qWarning("Failed to query swapchain backbuffer: %s", qPrintable(comErrorMessage(hr)));
return false;
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 0806c8a052..acd53b3dfd 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -75,6 +75,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiMetalInitParams
\inmodule QtRhi
+ \internal
\brief Metal specific initialization parameters.
A Metal-based QRhi needs no special parameters for initialization.
@@ -106,6 +107,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiMetalNativeHandles
\inmodule QtRhi
+ \internal
\brief Holds the Metal device used by the QRhi.
\note The class uses \c{void *} as the type since including the Objective C
@@ -116,6 +118,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiMetalCommandBufferNativeHandles
\inmodule QtRhi
+ \internal
\brief Holds the MTLCommandBuffer and MTLRenderCommandEncoder objects that are backing a QRhiCommandBuffer.
\note The command buffer object is only guaranteed to be valid while
@@ -3735,10 +3738,42 @@ QRhiRenderTarget *QMetalSwapChain::currentFrameRenderTarget()
return &rtWrapper;
}
+#ifdef TARGET_IPHONE_SIMULATOR
+API_AVAILABLE(ios(13.0))
+#endif
+static inline CAMetalLayer *layerForWindow(QWindow *window)
+{
+ Q_ASSERT(window);
+#ifdef Q_OS_MACOS
+ NSView *view = reinterpret_cast<NSView *>(window->winId());
+#else
+ UIView *view = reinterpret_cast<UIView *>(window->winId());
+#endif
+ Q_ASSERT(view);
+ return static_cast<CAMetalLayer *>(view.layer);
+}
+
QSize QMetalSwapChain::surfacePixelSize()
{
+#ifdef TARGET_IPHONE_SIMULATOR
+ if (@available(ios 13.0, *)) {
+#endif
+
Q_ASSERT(m_window);
- return m_window->size() * m_window->devicePixelRatio();
+ CAMetalLayer *layer = d->layer;
+ if (!layer)
+ layer = layerForWindow(m_window);
+
+ CGSize layerSize = layer.bounds.size;
+ layerSize.width *= layer.contentsScale;
+ layerSize.height *= layer.contentsScale;
+ return QSizeF::fromCGSize(layerSize).toSize();
+
+#ifdef TARGET_IPHONE_SIMULATOR
+ } else {
+ return QSize();
+ }
+#endif
}
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
@@ -3797,13 +3832,7 @@ bool QMetalSwapChain::buildOrResize()
return false;
}
-#ifdef Q_OS_MACOS
- NSView *view = reinterpret_cast<NSView *>(window->winId());
-#else
- UIView *view = reinterpret_cast<UIView *>(window->winId());
-#endif
- Q_ASSERT(view);
- d->layer = static_cast<CAMetalLayer *>(view.layer);
+ d->layer = layerForWindow(window);
Q_ASSERT(d->layer);
chooseFormats();
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index 26c153afff..57998119e0 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -540,6 +540,14 @@ bool QRhiVulkan::create(QRhi::Flags flags)
devInfo.enabledExtensionCount = uint32_t(requestedDevExts.count());
devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
+ // Enable all supported 1.0 core features, except ones that likely
+ // involve a performance penalty.
+ VkPhysicalDeviceFeatures features;
+ memset(&features, 0, sizeof(features));
+ f->vkGetPhysicalDeviceFeatures(physDev, &features);
+ features.robustBufferAccess = VK_FALSE;
+ devInfo.pEnabledFeatures = &features;
+
err = f->vkCreateDevice(physDev, &devInfo, nullptr, &dev);
if (err != VK_SUCCESS) {
qWarning("Failed to create device: %d", err);
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp
index 8528f59844..7aa3aa7453 100644
--- a/src/gui/text/qabstracttextdocumentlayout.cpp
+++ b/src/gui/text/qabstracttextdocumentlayout.cpp
@@ -436,7 +436,8 @@ void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *compo
if (!iface)
return; // ### print error message on terminal?
- connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
+ QObjectPrivate::connect(component, &QObject::destroyed, d,
+ &QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed);
QTextObjectHandler h;
h.iface = iface;
@@ -457,7 +458,8 @@ void QAbstractTextDocumentLayout::unregisterHandler(int objectType, QObject *com
const auto it = d->handlers.constFind(objectType);
if (it != d->handlers.cend() && (!component || component == it->component)) {
if (component)
- disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
+ QObjectPrivate::disconnect(component, &QObject::destroyed, d,
+ &QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed);
d->handlers.erase(it);
}
}
diff --git a/src/gui/text/qabstracttextdocumentlayout.h b/src/gui/text/qabstracttextdocumentlayout.h
index 397dcd37d4..1e97ba3785 100644
--- a/src/gui/text/qabstracttextdocumentlayout.h
+++ b/src/gui/text/qabstracttextdocumentlayout.h
@@ -129,7 +129,6 @@ private:
friend class QTextEngine;
friend class QTextLayout;
friend class QTextLine;
- Q_PRIVATE_SLOT(d_func(), void _q_handlerDestroyed(QObject *obj))
Q_PRIVATE_SLOT(d_func(), int _q_dynamicPageCountSlot())
Q_PRIVATE_SLOT(d_func(), QSizeF _q_dynamicDocumentSizeSlot())
};
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 663f727145..bcdeafdbbd 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -1140,14 +1140,14 @@ static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAd
s.chop(2);
value.variant = s;
if (value.variant.convert((QVariant::Type)qMetaTypeId<qreal>())) {
- font->setPointSizeF(value.variant.toReal());
+ font->setPointSizeF(qBound(qreal(0), value.variant.toReal(), qreal(1 << 24) - 1));
valid = true;
}
} else if (s.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) {
s.chop(2);
value.variant = s;
if (value.variant.convert(QMetaType::Int)) {
- font->setPixelSize(value.variant.toInt());
+ font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
valid = true;
}
}
@@ -1192,7 +1192,7 @@ static bool setFontWeightFromValue(const QCss::Value &value, QFont *font)
}
if (value.type != Value::Number)
return false;
- font->setWeight(qMin(value.variant.toInt() / 8, 99));
+ font->setWeight(qRound(qBound(0.0, value.variant.toDouble() / 8.0, 99.0)));
return true;
}
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 2bea0e9a07..9f16af0222 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -116,19 +116,36 @@ bool QFontDef::exactMatch(const QFontDef &other) const
if (stretch != 0 && other.stretch != 0 && stretch != other.stretch)
return false;
- if (families.size() != other.families.size())
+ // If either families or other.families just has 1 entry and the other has 0 then
+ // we will fall back to using the family in that case
+ const int sizeDiff = qAbs(families.size() - other.families.size());
+ if (sizeDiff > 1)
+ return false;
+ if (sizeDiff == 1 && (families.size() > 1 || other.families.size() > 1))
return false;
+ QStringList origFamilies = families;
+ QStringList otherFamilies = other.families;
+ if (sizeDiff != 0) {
+ if (origFamilies.size() != 1)
+ origFamilies << family;
+ else
+ otherFamilies << other.family;
+ }
+
QString this_family, this_foundry, other_family, other_foundry;
- for (int i = 0; i < families.size(); ++i) {
- QFontDatabase::parseFontName(families.at(i), this_foundry, this_family);
- QFontDatabase::parseFontName(other.families.at(i), other_foundry, other_family);
+ for (int i = 0; i < origFamilies.size(); ++i) {
+ QFontDatabase::parseFontName(origFamilies.at(i), this_foundry, this_family);
+ QFontDatabase::parseFontName(otherFamilies.at(i), other_foundry, other_family);
if (this_family != other_family || this_foundry != other_foundry)
return false;
}
- QFontDatabase::parseFontName(family, this_foundry, this_family);
- QFontDatabase::parseFontName(other.family, other_foundry, other_family);
+ // Check family only if families is not set
+ if (origFamilies.size() == 0) {
+ QFontDatabase::parseFontName(family, this_foundry, this_family);
+ QFontDatabase::parseFontName(other.family, other_foundry, other_family);
+ }
return (styleHint == other.styleHint
&& styleStrategy == other.styleStrategy
@@ -203,8 +220,10 @@ QFontPrivate::~QFontPrivate()
if (engineData && !engineData->ref.deref())
delete engineData;
engineData = nullptr;
- if (scFont && scFont != this)
- scFont->ref.deref();
+ if (scFont && scFont != this) {
+ if (!scFont->ref.deref())
+ delete scFont;
+ }
scFont = nullptr;
}
@@ -613,8 +632,10 @@ void QFont::detach()
if (d->engineData && !d->engineData->ref.deref())
delete d->engineData;
d->engineData = nullptr;
- if (d->scFont && d->scFont != d.data())
- d->scFont->ref.deref();
+ if (d->scFont && d->scFont != d.data()) {
+ if (!d->scFont->ref.deref())
+ delete d->scFont;
+ }
d->scFont = nullptr;
return;
}
@@ -2063,7 +2084,26 @@ QString QFont::key() const
/*!
Returns a description of the font. The description is a
comma-separated list of the attributes, perfectly suited for use
- in QSettings.
+ in QSettings, and consists of the following:
+
+ \list
+ \li Font family
+ \li Point size
+ \li Pixel size
+ \li Style hint
+ \li Font weight
+ \li Font style
+ \li Underline
+ \li Strike out
+ \li Fixed pitch
+ \li Always \e{0}
+ \li Capitalization
+ \li Letter spacing
+ \li Word spacing
+ \li Stretch
+ \li Style strategy
+ \li Font style (omitted when unavailable)
+ \endlist
\sa fromString()
*/
@@ -3280,3 +3320,5 @@ QDebug operator<<(QDebug stream, const QFont &font)
#endif
QT_END_NAMESPACE
+
+#include "moc_qfont.cpp"
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 1a4d8f938b..2011f935a9 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -414,6 +414,25 @@ void QtFontFamily::ensurePopulated()
Q_ASSERT_X(populated, Q_FUNC_INFO, qPrintable(name));
}
+/*!
+ \internal
+
+ Tests if the given family \a family supports writing system \a writingSystem,
+ including the special case for Han script mapping to several subsequent writing systems
+*/
+static bool familySupportsWritingSystem(QtFontFamily *family, size_t writingSystem)
+{
+ Q_ASSERT(family != nullptr);
+ Q_ASSERT(writingSystem != QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount);
+
+ size_t ws = writingSystem;
+ do {
+ if ((family->writingSystems[ws] & QtFontFamily::Supported) != 0)
+ return true;
+ } while (writingSystem >= QFontDatabase::SimplifiedChinese && writingSystem <= QFontDatabase::Japanese && ++ws <= QFontDatabase::Japanese);
+
+ return false;
+}
struct FallbacksCacheKey {
QString family;
@@ -826,7 +845,7 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo
f->ensurePopulated();
- if (writingSystem > QFontDatabase::Any && f->writingSystems[writingSystem] != QtFontFamily::Supported)
+ if (writingSystem > QFontDatabase::Any && !familySupportsWritingSystem(f, writingSystem))
continue;
for (int j = 0; j < f->count; ++j) {
@@ -1219,9 +1238,13 @@ static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
Tries to find the best match for a given request and family/foundry
*/
-static int match(int script, const QFontDef &request,
- const QString &family_name, const QString &foundry_name,
- QtFontDesc *desc, const QList<int> &blacklistedFamilies)
+static int match(int script,
+ const QFontDef &request,
+ const QString &family_name,
+ const QString &foundry_name,
+ QtFontDesc *desc,
+ const QList<int> &blacklistedFamilies,
+ unsigned int *resultingScore = nullptr)
{
int result = -1;
@@ -1271,8 +1294,10 @@ static int match(int script, const QFontDef &request,
test.family->ensurePopulated();
// Check if family is supported in the script we want
- if (writingSystem != QFontDatabase::Any && !(test.family->writingSystems[writingSystem] & QtFontFamily::Supported))
+ if (writingSystem != QFontDatabase::Any
+ && !familySupportsWritingSystem(test.family, writingSystem)) {
continue;
+ }
// as we know the script is supported, we can be sure
// to find a matching font here.
@@ -1296,6 +1321,10 @@ static int match(int script, const QFontDef &request,
if (newscore < 10) // xlfd instead of FT... just accept it
break;
}
+
+ if (resultingScore != nullptr)
+ *resultingScore = score;
+
return result;
}
@@ -1729,13 +1758,19 @@ bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &sty
for (int j = 0; j < f->count; j++) {
QtFontFoundry *foundry = f->foundries[j];
if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
- for (int k = 0; k < foundry->count; k++)
- if ((style.isEmpty() ||
- foundry->styles[k]->styleName == style ||
- foundry->styles[k]->key == styleKey) && foundry->styles[k]->smoothScalable) {
- smoothScalable = true;
+ for (int k = 0; k < foundry->count; k++) {
+ QtFontStyle *fontStyle = foundry->styles[k];
+ smoothScalable =
+ fontStyle->smoothScalable
+ && ((style.isEmpty()
+ || fontStyle->styleName == style
+ || fontStyle->key == styleKey)
+ || (fontStyle->styleName.isEmpty()
+ && style == styleStringHelper(fontStyle->key.weight,
+ QFont::Style(fontStyle->key.style))));
+ if (smoothScalable)
goto end;
- }
+ }
}
}
end:
@@ -2474,13 +2509,12 @@ bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
with removeApplicationFont() or to retrieve the list of family names contained
in the font.
+//! [add-application-font-doc]
The function returns -1 if the font could not be loaded.
Currently only TrueType fonts, TrueType font collections, and OpenType fonts are
supported.
-
- \note Adding application fonts on Unix/X11 platforms without fontconfig is
- currently not supported.
+//! [add-application-font-doc]
\sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
*/
@@ -2508,12 +2542,7 @@ int QFontDatabase::addApplicationFont(const QString &fileName)
with removeApplicationFont() or to retrieve the list of family names contained
in the font.
- The function returns -1 if the font could not be loaded.
-
- Currently only TrueType fonts and TrueType font collections are supported.
-
- \b{Note:} Adding application fonts on Unix/X11 platforms without fontconfig is
- currently not supported.
+ \include qfontdatabase.cpp add-application-font-doc
\sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont()
*/
@@ -2648,7 +2677,9 @@ bool QFontDatabase::supportsThreadedFontRendering()
/*!
\internal
*/
-QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
+QFontEngine *QFontDatabase::findFont(const QFontDef &request,
+ int script,
+ bool preferScriptOverFamily)
{
QMutexLocker locker(fontDatabaseMutex());
@@ -2679,16 +2710,31 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
return engine;
}
+ if (request.pixelSize > 0xffff) {
+ // Stop absurd requests reaching the engines; pixel size is assumed to fit ushort
+ qCDebug(lcFontMatch, "Rejecting request for pixel size %g2, returning box engine", double(request.pixelSize));
+ return new QFontEngineBox(32); // not request.pixelSize, to avoid overflow/DOS
+ }
+
QString family_name, foundry_name;
const QString requestFamily = request.families.size() > 0 ? request.families.at(0) : request.family;
parseFontName(requestFamily, foundry_name, family_name);
QtFontDesc desc;
QList<int> blackListed;
- int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
- if (index < 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
+ unsigned int score = UINT_MAX;
+ int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed, &score);
+ if (score > 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
// We populated familiy aliases (e.g. localized families), so try again
index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
}
+
+ // If we do not find a match and NoFontMerging is set, use the requested font even if it does
+ // not support the script.
+ //
+ // (we do this at the end to prefer foundries that support the script if they exist)
+ if (index < 0 && !multi && !preferScriptOverFamily)
+ index = match(QChar::Script_Common, request, family_name, foundry_name, &desc, blackListed);
+
if (index >= 0) {
QFontDef fontDef = request;
@@ -2881,10 +2927,8 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script
}
uint order = i;
- if (testFamily == nullptr
- || (testFamily->writingSystems[writingSystem] & QtFontFamily::Supported) == 0) {
+ if (testFamily == nullptr || !familySupportsWritingSystem(testFamily, writingSystem))
order |= 1u << 31;
- }
supported.insert(order, family);
}
@@ -2894,3 +2938,5 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script
QT_END_NAMESPACE
+#include "moc_qfontdatabase.cpp"
+
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
index 80b092f177..b581f30a19 100644
--- a/src/gui/text/qfontdatabase.h
+++ b/src/gui/text/qfontdatabase.h
@@ -160,7 +160,7 @@ private:
static void createDatabase();
static void parseFontName(const QString &name, QString &foundry, QString &family);
static QString resolveFontFamilyAlias(const QString &family);
- static QFontEngine *findFont(const QFontDef &request, int script /* QChar::Script */);
+ static QFontEngine *findFont(const QFontDef &request, int script /* QChar::Script */, bool preferScriptOverFamily = false);
static void load(const QFontPrivate *d, int script /* QChar::Script */);
friend struct QFontDef;
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index d745a70a9a..d9c0239940 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1600,7 +1600,7 @@ QFontEngineBox::~QFontEngineBox()
glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
{
Q_UNUSED(ucs4)
- return 0;
+ return 1;
}
bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
@@ -1615,7 +1615,7 @@ bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
QStringIterator it(str, str + len);
while (it.hasNext()) {
it.advance();
- glyphs->glyphs[ucs4Length++] = 0;
+ glyphs->glyphs[ucs4Length++] = 1;
}
*nglyphs = ucs4Length;
@@ -1815,7 +1815,7 @@ void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamili
void QFontEngineMulti::ensureEngineAt(int at)
{
- if (!m_fallbackFamiliesQueried)
+ if (!m_fallbackFamiliesQueried && at > 0)
ensureFallbackFamiliesQueried();
Q_ASSERT(at < m_engines.size());
if (!m_engines.at(at)) {
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 73fcc4bc78..72e3969427 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -273,9 +273,8 @@ bool QFontMetrics::operator ==(const QFontMetrics &other) const
The ascent of a font is the distance from the baseline to the
highest position characters extend to. In practice, some font
designers break this rule, e.g. when they put more than one accent
- on top of a character, or to accommodate an unusual character in
- an exotic language, so it is possible (though rare) that this
- value will be too small.
+ on top of a character, or to accommodate a certain character, so it
+ is possible (though rare) that this value will be too small.
\sa descent()
*/
@@ -310,8 +309,8 @@ int QFontMetrics::capHeight() const
The descent is the distance from the base line to the lowest point
characters extend to. In practice, some font designers break this rule,
- e.g. to accommodate an unusual character in an exotic language, so
- it is possible (though rare) that this value will be too small.
+ e.g. to accommodate a certain character, so it is possible (though
+ rare) that this value will be too small.
\sa ascent()
*/
@@ -1242,9 +1241,8 @@ bool QFontMetricsF::operator ==(const QFontMetricsF &other) const
The ascent of a font is the distance from the baseline to the
highest position characters extend to. In practice, some font
designers break this rule, e.g. when they put more than one accent
- on top of a character, or to accommodate an unusual character in
- an exotic language, so it is possible (though rare) that this
- value will be too small.
+ on top of a character, or to accommodate a certain character, so
+ it is possible (though rare) that this value will be too small.
\sa descent()
*/
@@ -1280,8 +1278,8 @@ qreal QFontMetricsF::capHeight() const
The descent is the distance from the base line to the lowest point
characters extend to. (Note that this is different from X, which
adds 1 pixel.) In practice, some font designers break this rule,
- e.g. to accommodate an unusual character in an exotic language, so
- it is possible (though rare) that this value will be too small.
+ e.g. to accommodate a certain character, so it is possible (though
+ rare) that this value will be too small.
\sa ascent()
*/
@@ -1697,7 +1695,9 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const
Returns the bounding rectangle of the characters in the given \a text.
This is the set of pixels the text would cover if drawn when constrained
- to the bounding rectangle specified by \a rect.
+ to the bounding rectangle specified by \a rect. If \a rect is a reference
+ to a \nullptr object, e.g. when passing a default constructed QRectF, the
+ bounding rectangle will not constrain itself to the size.
The \a flags argument is the bitwise OR of the following flags:
\list
diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp
index d56516fa04..75639ee525 100644
--- a/src/gui/text/qfontsubset.cpp
+++ b/src/gui/text/qfontsubset.cpp
@@ -112,24 +112,6 @@ QByteArray QFontSubset::glyphName(unsigned short unicode, bool symbol)
return buffer;
}
-QByteArray QFontSubset::glyphName(unsigned int glyph, const QVector<int> &reverseMap) const
-{
- uint glyphIndex = glyph_indices[glyph];
-
- if (glyphIndex == 0)
- return "/.notdef";
-
- QByteArray ba;
- QPdf::ByteStream s(&ba);
- if (reverseMap[glyphIndex] && reverseMap[glyphIndex] < 0x10000) {
- s << '/' << glyphName(reverseMap[glyphIndex], false);
- } else {
- s << "/gl" << (int)glyphIndex;
- }
- return ba;
-}
-
-
QByteArray QFontSubset::widthArray() const
{
Q_ASSERT(!widths.isEmpty());
diff --git a/src/gui/text/qfontsubset_p.h b/src/gui/text/qfontsubset_p.h
index e7c6053beb..5b605aac59 100644
--- a/src/gui/text/qfontsubset_p.h
+++ b/src/gui/text/qfontsubset_p.h
@@ -77,7 +77,6 @@ public:
QByteArray widthArray() const;
QByteArray createToUnicodeMap() const;
QVector<int> getReverseMap() const;
- QByteArray glyphName(unsigned int glyph, const QVector<int> &reverseMap) const;
static QByteArray glyphName(unsigned short unicode, bool symbol);
diff --git a/src/gui/text/qinputcontrol.cpp b/src/gui/text/qinputcontrol.cpp
index 3381fdb673..8c05346730 100644
--- a/src/gui/text/qinputcontrol.cpp
+++ b/src/gui/text/qinputcontrol.cpp
@@ -79,6 +79,9 @@ bool QInputControl::isAcceptableInput(const QKeyEvent *event) const
if (c.category() == QChar::Other_PrivateUse)
return true;
+ if (c.isHighSurrogate() && text.length() > 1 && text.at(1).isLowSurrogate())
+ return true;
+
if (m_type == TextEdit && c == QLatin1Char('\t'))
return true;
@@ -137,3 +140,5 @@ bool QInputControl::isCommonTextEditShortcut(const QKeyEvent *ke)
}
QT_END_NAMESPACE
+
+#include "moc_qinputcontrol_p.cpp"
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index b4b60cbaaf..3d6b70a995 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -760,7 +760,7 @@ QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writ
QFontDef request(multiEngine->fontDef);
request.styleStrategy |= QFont::NoFontMerging;
- if (QFontEngine *engine = QFontDatabase::findFont(request, script)) {
+ if (QFontEngine *engine = QFontDatabase::findFont(request, script, true)) {
if (request.weight > QFont::Normal)
engine->fontDef.weight = request.weight;
if (request.style > QFont::StyleNormal)
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 7ee9898537..b75904e885 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -3032,10 +3032,12 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
if (fragmentMarkers && block.position() + block.length() == doc->docHandle()->length())
html += QLatin1String("<!--EndFragment-->");
+ QString closeTags;
+
if (pre)
html += QLatin1String("</pre>");
else if (list)
- html += QLatin1String("</li>");
+ closeTags += QLatin1String("</li>");
else {
int headingLevel = blockFormat.headingLevel();
if (headingLevel > 0 && headingLevel <= 6)
@@ -3047,9 +3049,30 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
if (list) {
if (list->itemNumber(block) == list->count() - 1) { // last item? close list
if (isOrderedList(list->format().style()))
- html += QLatin1String("</ol>");
+ closeTags += QLatin1String("</ol>");
else
- html += QLatin1String("</ul>");
+ closeTags += QLatin1String("</ul>");
+ }
+ const QTextBlock nextBlock = block.next();
+ // If the next block is the beginning of a new deeper nested list, then we don't
+ // want to close the current list item just yet. This should be closed when this
+ // item is fully finished
+ if (nextBlock.isValid() && nextBlock.textList() &&
+ nextBlock.textList()->itemNumber(nextBlock) == 0 &&
+ nextBlock.textList()->format().indent() > list->format().indent()) {
+ QString lastTag;
+ if (!closingTags.isEmpty() && list->itemNumber(block) == list->count() - 1)
+ lastTag = closingTags.takeLast();
+ lastTag.prepend(closeTags);
+ closingTags << lastTag;
+ } else if (list->itemNumber(block) == list->count() - 1) {
+ // If we are at the end of the list now then we can add in the closing tags for that
+ // current block
+ html += closeTags;
+ if (!closingTags.isEmpty())
+ html += closingTags.takeLast();
+ } else {
+ html += closeTags;
}
}
@@ -3476,3 +3499,5 @@ QTextDocumentPrivate *QTextDocument::docHandle() const
*/
QT_END_NAMESPACE
+
+#include "moc_qtextdocument.cpp"
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index 524931ebde..c22dd95d48 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -381,8 +381,11 @@ int QTextDocumentPrivate::insert_block(int pos, uint strPos, int format, int blo
Q_ASSERT(blocks.length() == fragments.length());
QTextBlockGroup *group = qobject_cast<QTextBlockGroup *>(objectForFormat(blockFormat));
- if (group)
+ if (group) {
group->blockInserted(QTextBlock(this, b));
+ docChangeOldLength--;
+ docChangeLength--;
+ }
QTextFrame *frame = qobject_cast<QTextFrame *>(objectForFormat(formats.format(format)));
if (frame) {
diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h
index 7f85d27ba0..9908f14ba3 100644
--- a/src/gui/text/qtextdocument_p.h
+++ b/src/gui/text/qtextdocument_p.h
@@ -405,6 +405,7 @@ private:
QTextCharFormat defaultCharFormat;
const QTextDocument *doc;
bool fragmentMarkers;
+ QStringList closingTags;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index d7bc707491..2fdfcaa2d2 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -1296,5 +1296,6 @@ QTextDocumentFragment QTextDocumentFragment::fromHtml(const QString &html, const
return res;
}
-QT_END_NAMESPACE
#endif // QT_NO_TEXTHTMLPARSER
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index a2b3c8dc76..72267e9380 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -105,14 +105,13 @@ public:
bool sizeDirty;
bool layoutDirty;
- bool fullLayoutCompleted;
QVector<QPointer<QTextFrame> > floats;
};
QTextFrameData::QTextFrameData()
: maximumWidth(QFIXED_MAX),
- currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true), fullLayoutCompleted(false)
+ currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true)
{
}
@@ -2124,7 +2123,7 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
{
Q_Q(const QTextDocumentLayout);
const QTextBlockFormat blockFormat = bl.blockFormat();
- const QTextCharFormat charFormat = QTextCursor(bl).charFormat();
+ const QTextCharFormat charFormat = bl.charFormat();
QFont font(charFormat.font());
if (q->paintDevice())
font = QFont(font, q->paintDevice());
@@ -2187,9 +2186,11 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
painter->setRenderHint(QPainter::Antialiasing);
+ const bool marker = bl.blockFormat().marker() != QTextBlockFormat::MarkerType::NoMarker;
if (selectionFormat) {
painter->setPen(QPen(selectionFormat->foreground(), 0));
- painter->fillRect(r, selectionFormat->background());
+ if (!marker)
+ painter->fillRect(r, selectionFormat->background());
} else {
QBrush fg = charFormat.foreground();
if (fg == Qt::NoBrush)
@@ -2199,19 +2200,21 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
QBrush brush = context.palette.brush(QPalette::Text);
- bool marker = bl.blockFormat().marker() != QTextBlockFormat::MarkerType::NoMarker;
if (marker) {
int adj = fontMetrics.lineSpacing() / 6;
r.adjust(-adj, 0, -adj, 0);
+ const QRectF outer = r.adjusted(-adj, -adj, adj, adj);
+ if (selectionFormat)
+ painter->fillRect(outer, selectionFormat->background());
if (bl.blockFormat().marker() == QTextBlockFormat::MarkerType::Checked) {
- // ### Qt6: render with QStyle / PE_IndicatorCheckBox. We don't currently
+ // ### Qt7: render with QStyle / PE_IndicatorCheckBox. We don't currently
// have access to that here, because it would be a widget dependency.
painter->setPen(QPen(painter->pen().color(), 2));
painter->drawLine(r.topLeft(), r.bottomRight());
painter->drawLine(r.topRight(), r.bottomLeft());
painter->setPen(QPen(painter->pen().color(), 0));
}
- painter->drawRect(r.adjusted(-adj, -adj, adj, adj));
+ painter->drawRect(outer);
}
switch (style) {
@@ -2358,9 +2361,10 @@ QTextLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QT
floatMinWidth = qMax(floatMinWidth, cd->minimumWidth);
}
- // constraint the maximumWidth by the minimum width of the fixed size floats, to
- // keep them visible
+ // constraint the maximum/minimumWidth by the minimum width of the fixed size floats,
+ // to keep them visible
layoutStruct.maximumWidth = qMax(layoutStruct.maximumWidth, floatMinWidth);
+ layoutStruct.minimumWidth = qMax(layoutStruct.minimumWidth, floatMinWidth);
// as floats in cells get added to the table's float list but must not affect
// floats in other cells we must clear the list here.
@@ -2537,6 +2541,8 @@ recalc_minmax_widths:
for (int n = 0; n < cspan; ++n) {
const int col = i + n;
QFixed w = widthToDistribute / (cspan - n);
+ if (td->maxWidths[col] != QFIXED_MAX)
+ w = qMax(td->maxWidths[col], w);
td->maxWidths[col] = qMax(td->minWidths.at(col), w);
widthToDistribute -= td->maxWidths.at(col);
if (widthToDistribute <= 0)
@@ -2944,7 +2950,7 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in
QTextFrameData *fd = data(f);
QFixed newContentsWidth;
- bool fullLayout = (f == document->rootFrame() && !fd->fullLayoutCompleted);
+ bool fullLayout = false;
{
QTextFrameFormat fformat = f->frameFormat();
// set sizes of this frame from the format
@@ -3398,7 +3404,6 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout
cp.contentsWidth = layoutStruct->contentsWidth;
checkPoints.append(cp);
checkPoints.reserve(checkPoints.size());
- fd->fullLayoutCompleted = true;
} else {
currentLazyLayoutPosition = checkPoints.constLast().positionInFrame;
// #######
@@ -3810,7 +3815,6 @@ void QTextDocumentLayout::documentChanged(int from, int oldLength, int length)
d->contentHasAlignment = false;
d->currentLazyLayoutPosition = 0;
d->checkPoints.clear();
- data(d->docPrivate->rootFrame())->fullLayoutCompleted = false;
d->layoutStep();
} else {
d->ensureLayoutedByPosition(from);
diff --git a/src/gui/text/qtextdocumentwriter.cpp b/src/gui/text/qtextdocumentwriter.cpp
index 0bafa5d9ff..800b72ea9c 100644
--- a/src/gui/text/qtextdocumentwriter.cpp
+++ b/src/gui/text/qtextdocumentwriter.cpp
@@ -83,7 +83,6 @@ public:
\inmodule QtGui
\ingroup richtext-processing
- \ingroup io
To write a document, construct a QTextDocumentWriter object with either a
file name or a device object, and specify the document format to be
@@ -249,9 +248,11 @@ QString QTextDocumentWriter::fileName () const
*/
bool QTextDocumentWriter::write(const QTextDocument *document)
{
- QByteArray suffix;
+ if (!d->device)
+ return false;
- if (d->device && d->format.isEmpty()) {
+ QByteArray suffix;
+ if (d->format.isEmpty()) {
// if there's no format, see if device is a file, and if so, find
// the file suffix
if (QFile *file = qobject_cast<QFile *>(d->device))
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index b7459bf826..6336fadf74 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -258,7 +258,7 @@ struct QBidiAlgorithm {
for (int i = 0; i < length; ++i) {
int pos = i;
uint uc = text[i].unicode();
- if (QChar::isHighSurrogate(uc) && i < length - 1) {
+ if (QChar::isHighSurrogate(uc) && i < length - 1 && text[i + 1].isLowSurrogate()) {
++i;
analysis[i].bidiDirection = QChar::DirNSM;
uc = QChar::surrogateToUcs4(ushort(uc), text[i].unicode());
@@ -1373,9 +1373,15 @@ static void applyVisibilityRules(ushort ucs, QGlyphLayout *glyphs, uint glyphPos
if (!fontEngine->symbol) {
// U+00AD [SOFT HYPHEN] is a default ignorable codepoint,
// so we replace its glyph and metrics with ones for
- // U+002D [HYPHEN-MINUS] and make it visible if it appears at line-break
+ // U+002D [HYPHEN-MINUS] or U+2010 [HYPHEN] and make
+ // it visible if it appears at line-break
const uint engineIndex = glyphs->glyphs[glyphPosition] & 0xff000000;
- glyphs->glyphs[glyphPosition] = fontEngine->glyphIndex('-');
+ glyph_t glyph = fontEngine->glyphIndex(0x002d);
+ if (glyph == 0)
+ glyph = fontEngine->glyphIndex(0x2010);
+ if (glyph == 0)
+ glyph = fontEngine->glyphIndex(0x00ad);
+ glyphs->glyphs[glyphPosition] = glyph;
if (Q_LIKELY(glyphs->glyphs[glyphPosition] != 0)) {
glyphs->glyphs[glyphPosition] |= engineIndex;
QGlyphLayout tmp = glyphs->mid(glyphPosition, 1);
@@ -1547,12 +1553,27 @@ void QTextEngine::shapeText(int item) const
} else {
si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);
}
+
if (Q_UNLIKELY(si.num_glyphs == 0)) {
- Q_UNREACHABLE(); // ### report shaping errors somehow
+ if (Q_UNLIKELY(!ensureSpace(si.glyph_data_offset + 1))) {
+ qWarning() << "Unable to allocate space for place-holder glyph";
+ return;
+ }
+
+ si.num_glyphs = 1;
+
+ // Overwrite with 0 token to indicate failure
+ QGlyphLayout g = availableGlyphs(&si);
+ g.glyphs[0] = 0;
+ g.attributes[0].clusterStart = true;
+
+ ushort *log_clusters = logClusters(&si);
+ for (int i = 0; i < itemLength; ++i)
+ log_clusters[i] = 0;
+
return;
}
-
layoutData->used += si.num_glyphs;
QGlyphLayout glyphs = shapedGlyphs(&si);
@@ -2164,20 +2185,35 @@ void QTextEngine::itemize() const
QTextDocumentPrivate::FragmentIterator end = p->find(block.position() + block.length() - 1); // -1 to omit the block separator char
int format = it.value()->format;
+ int preeditPosition = s ? s->preeditPosition : INT_MAX;
int prevPosition = 0;
int position = prevPosition;
while (1) {
const QTextFragmentData * const frag = it.value();
if (it == end || format != frag->format) {
- if (s && position >= s->preeditPosition) {
+ if (s && position >= preeditPosition) {
position += s->preeditText.length();
- s = nullptr;
+ preeditPosition = INT_MAX;
}
Q_ASSERT(position <= length);
QFont::Capitalization capitalization =
formatCollection()->charFormat(format).hasProperty(QTextFormat::FontCapitalization)
? formatCollection()->charFormat(format).fontCapitalization()
: formatCollection()->defaultFont().capitalization();
+ if (s) {
+ for (const auto &range : qAsConst(s->formats)) {
+ if (range.start + range.length <= prevPosition || range.start >= position)
+ continue;
+ if (range.format.hasProperty(QTextFormat::FontCapitalization)) {
+ if (range.start > prevPosition)
+ itemizer.generate(prevPosition, range.start - prevPosition, capitalization);
+ int newStart = std::max(prevPosition, range.start);
+ int newEnd = std::min(position, range.start + range.length);
+ itemizer.generate(newStart, newEnd - newStart, range.format.fontCapitalization());
+ prevPosition = newEnd;
+ }
+ }
+ }
itemizer.generate(prevPosition, position - prevPosition, capitalization);
if (it == end) {
if (position < length)
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 4e5ee41e24..560a0a1c5f 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -3929,3 +3929,5 @@ QDebug operator<<(QDebug dbg, const QTextFormat &f)
#endif
QT_END_NAMESPACE
+
+#include "moc_qtextformat.cpp"
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 8b58f69770..5458e646c5 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -784,8 +784,8 @@ void QTextHtmlParser::parseCloseTag()
void QTextHtmlParser::parseExclamationTag()
{
++pos;
- if (hasPrefix(QLatin1Char('-'),1) && hasPrefix(QLatin1Char('-'),2)) {
- pos += 3;
+ if (hasPrefix(QLatin1Char('-')) && hasPrefix(QLatin1Char('-'), 1)) {
+ pos += 2;
// eat comments
int end = txt.indexOf(QLatin1String("-->"), pos);
pos = (end >= 0 ? end + 3 : len);
@@ -880,7 +880,7 @@ QString QTextHtmlParser::parseWord()
while (pos < len) {
QChar c = txt.at(pos++);
if (c == QLatin1Char('>')
- || (c == QLatin1Char('/') && hasPrefix(QLatin1Char('>'), 1))
+ || (c == QLatin1Char('/') && hasPrefix(QLatin1Char('>')))
|| c == QLatin1Char('<')
|| c == QLatin1Char('=')
|| c.isSpace()) {
@@ -1677,7 +1677,7 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
node->tableCellRowSpan = qMax(1, node->tableCellRowSpan);
} else if (key == QLatin1String("colspan")) {
if (setIntAttribute(&node->tableCellColSpan, value))
- node->tableCellColSpan = qMax(1, node->tableCellColSpan);
+ node->tableCellColSpan = qBound(1, node->tableCellColSpan, 20480);
}
break;
case Html_table:
diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h
index 31f558709f..e5622afe9d 100644
--- a/src/gui/text/qtexthtmlparser_p.h
+++ b/src/gui/text/qtexthtmlparser_p.h
@@ -323,7 +323,9 @@ protected:
void applyAttributes(const QStringList &attributes);
void eatSpace();
inline bool hasPrefix(QChar c, int lookahead = 0) const
- {return pos + lookahead < len && txt.at(pos) == c; }
+ {
+ return pos + lookahead < len && txt.at(pos + lookahead) == c;
+ }
int margin(int i, int mar) const;
bool nodeIsChildOf(int i, QTextHTMLElements id) const;
diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp
index 0d87a2135d..e650984c63 100644
--- a/src/gui/text/qtextimagehandler.cpp
+++ b/src/gui/text/qtextimagehandler.cpp
@@ -53,40 +53,21 @@ QT_BEGIN_NAMESPACE
extern QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio,
qreal *sourceDevicePixelRatio);
-static QString resolveFileName(QString fileName, QUrl *url, qreal targetDevicePixelRatio,
- qreal *sourceDevicePixelRatio)
-{
- // We might use the fileName for loading if url loading fails
- // try to make sure it is a valid file path.
- // Also, QFile{Info}::exists works only on filepaths (not urls)
-
- if (url->isValid()) {
- if (url->scheme() == QLatin1String("qrc")) {
- fileName = fileName.right(fileName.length() - 3);
- }
- else if (url->scheme() == QLatin1String("file")) {
- fileName = url->toLocalFile();
- }
- }
- if (targetDevicePixelRatio <= 1.0)
- return fileName;
-
- // try to find a Nx version
- return qt_findAtNxFile(fileName, targetDevicePixelRatio, sourceDevicePixelRatio);
+static inline QUrl fromLocalfileOrResources(QString path)
+{
+ if (path.startsWith(QLatin1String(":/"))) // auto-detect resources and convert them to url
+ path.prepend(QLatin1String("qrc"));
+ return QUrl(path);
}
-
static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0)
{
- QPixmap pm;
-
- QString name = format.name();
- if (name.startsWith(QLatin1String(":/"))) // auto-detect resources and convert them to url
- name.prepend(QLatin1String("qrc"));
- QUrl url = QUrl(name);
qreal sourcePixelRatio = 1.0;
- name = resolveFileName(name, &url, devicePixelRatio, &sourcePixelRatio);
+ const QString name = qt_findAtNxFile(format.name(), devicePixelRatio, &sourcePixelRatio);
+ const QUrl url = fromLocalfileOrResources(name);
+
+ QPixmap pm;
const QVariant data = doc->resource(QTextDocument::ImageResource, url);
if (data.userType() == QMetaType::QPixmap || data.userType() == QMetaType::QImage) {
pm = qvariant_cast<QPixmap>(data);
@@ -161,14 +142,11 @@ static QSize getPixmapSize(QTextDocument *doc, const QTextImageFormat &format)
static QImage getImage(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0)
{
- QImage image;
-
- QString name = format.name();
- if (name.startsWith(QLatin1String(":/"))) // auto-detect resources
- name.prepend(QLatin1String("qrc"));
- QUrl url = QUrl(name);
qreal sourcePixelRatio = 1.0;
- name = resolveFileName(name, &url, devicePixelRatio, &sourcePixelRatio);
+ const QString name = qt_findAtNxFile(format.name(), devicePixelRatio, &sourcePixelRatio);
+ const QUrl url = fromLocalfileOrResources(name);
+
+ QImage image;
const QVariant data = doc->resource(QTextDocument::ImageResource, url);
if (data.userType() == QMetaType::QImage) {
image = qvariant_cast<QImage>(data);
@@ -266,3 +244,5 @@ void QTextImageHandler::drawObject(QPainter *p, const QRectF &rect, QTextDocumen
}
QT_END_NAMESPACE
+
+#include "moc_qtextimagehandler_p.cpp"
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index b2f12ef1ce..7e1fb822fc 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -850,6 +850,10 @@ QTextLine QTextLayout::createLine()
int l = d->lines.size();
if (l && d->lines.at(l-1).length < 0) {
QTextLine(l-1, d).setNumColumns(INT_MAX);
+ if (d->maxWidth > QFIXED_MAX / 2) {
+ qWarning("QTextLayout: text too long, truncated.");
+ return QTextLine();
+ }
}
int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length + d->lines.at(l-1).trailingSpaces : 0;
int strlen = d->layoutData->string.length();
@@ -1169,10 +1173,17 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang
QRectF fullLineRect(tl.rect());
fullLineRect.translate(position);
fullLineRect.setRight(QFIXED_MAX);
- if (!selectionEndInLine)
- region.addRect(clipIfValid(QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
- if (!selectionStartInLine)
- region.addRect(clipIfValid(QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
+
+ const bool rightToLeft = d->isRightToLeft();
+
+ if (!selectionEndInLine) {
+ region.addRect(clipIfValid(rightToLeft ? QRectF(fullLineRect.topLeft(), lineRect.bottomLeft())
+ : QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
+ }
+ if (!selectionStartInLine) {
+ region.addRect(clipIfValid(rightToLeft ? QRectF(lineRect.topRight(), fullLineRect.bottomRight())
+ : QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
+ }
} else if (!selectionEndInLine
&& isLastLineInBlock
&&!(d->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) {
@@ -1325,13 +1336,13 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
bool rightToLeft = d->isRightToLeft();
if (itm >= 0) {
const QScriptItem &si = d->layoutData->items.at(itm);
- if (si.ascent > 0)
+ if (si.ascent >= 0)
base = si.ascent;
- if (si.descent > 0)
+ if (si.descent >= 0)
descent = si.descent;
rightToLeft = si.analysis.bidiLevel % 2;
}
- qreal y = position.y() + (sl.y + sl.base() - base).toReal();
+ qreal y = position.y() + (sl.y + sl.base() + sl.descent - base - descent).toReal();
bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
&& (p->transform().type() > QTransform::TxTranslate);
if (toggleAntialiasing)
@@ -1339,7 +1350,20 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
QPainter::CompositionMode origCompositionMode = p->compositionMode();
if (p->paintEngine()->hasFeature(QPaintEngine::RasterOpModes))
p->setCompositionMode(QPainter::RasterOp_NotDestination);
- p->fillRect(QRectF(x, y, qreal(width), (base + descent).toReal()), p->pen().brush());
+ const QTransform &deviceTransform = p->deviceTransform();
+ const qreal xScale = deviceTransform.m11();
+ if (deviceTransform.type() != QTransform::TxScale || std::trunc(xScale) == xScale) {
+ p->fillRect(QRectF(x, y, qreal(width), (base + descent).toReal()), p->pen().brush());
+ } else {
+ // Ensure consistently rendered cursor width under fractional scaling
+ const QPen origPen = p->pen();
+ QPen pen(origPen.brush(), qRound(width * xScale), Qt::SolidLine, Qt::FlatCap);
+ pen.setCosmetic(true);
+ const qreal center = x + qreal(width) / 2;
+ p->setPen(pen);
+ p->drawLine(QPointF(center, y), QPointF(center, y + (base + descent).toReal()));
+ p->setPen(origPen);
+ }
p->setCompositionMode(origCompositionMode);
if (toggleAntialiasing)
p->setRenderHint(QPainter::Antialiasing, false);
@@ -1976,7 +2000,8 @@ void QTextLine::layout_helper(int maxGlyphs)
if (lbh.currentPosition >= eng->layoutData->string.length()
|| isBreakableSpace
- || attributes[lbh.currentPosition].lineBreak) {
+ || attributes[lbh.currentPosition].lineBreak
+ || lbh.tmpData.textWidth >= QFIXED_MAX) {
sb_or_ws = true;
break;
} else if (attributes[lbh.currentPosition].graphemeBoundary) {
@@ -2393,14 +2418,18 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
// when we're breaking a RTL script item, since the expected position passed into
// getGlyphPositions() is the left-most edge of the left-most glyph in an RTL run.
if (relativeFrom != (iterator.itemStart - si.position) && !rtl) {
- for (int i=itemGlyphsStart; i<glyphsStart; ++i) {
- QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
- pos.rx() += (glyphLayout.advances[i] + justification).toReal();
+ for (int i = itemGlyphsStart; i < glyphsStart; ++i) {
+ if (!glyphLayout.attributes[i].dontPrint) {
+ QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
+ pos.rx() += (glyphLayout.advances[i] + justification).toReal();
+ }
}
} else if (relativeTo != (iterator.itemEnd - si.position - 1) && rtl) {
- for (int i=itemGlyphsEnd; i>glyphsEnd; --i) {
- QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
- pos.rx() += (glyphLayout.advances[i] + justification).toReal();
+ for (int i = itemGlyphsEnd; i > glyphsEnd; --i) {
+ if (!glyphLayout.attributes[i].dontPrint) {
+ QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
+ pos.rx() += (glyphLayout.advances[i] + justification).toReal();
+ }
}
}
@@ -2449,8 +2478,10 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
relativeFrom + si.position,
relativeTo - relativeFrom + 1));
for (int i = 0; i < subLayout.numGlyphs; ++i) {
- QFixed justification = QFixed::fromFixed(subLayout.justifications[i].space_18d6);
- pos.rx() += (subLayout.advances[i] + justification).toReal();
+ if (!subLayout.attributes[i].dontPrint) {
+ QFixed justification = QFixed::fromFixed(subLayout.justifications[i].space_18d6);
+ pos.rx() += (subLayout.advances[i] + justification).toReal();
+ }
}
if (rtl)
@@ -2535,6 +2566,9 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR
return;
}
+ static QRectF maxFixedRect(QPointF(-QFIXED_MAX, -QFIXED_MAX), QPointF(QFIXED_MAX, QFIXED_MAX));
+ if (!maxFixedRect.contains(pos))
+ return;
QTextLineItemIterator iterator(eng, index, pos, selection);
QFixed lineBase = line.base();
diff --git a/src/gui/text/qtextlist.cpp b/src/gui/text/qtextlist.cpp
index 5857afa048..523c22ff87 100644
--- a/src/gui/text/qtextlist.cpp
+++ b/src/gui/text/qtextlist.cpp
@@ -320,3 +320,5 @@ void QTextList::add(const QTextBlock &block)
}
QT_END_NAMESPACE
+
+#include "moc_qtextlist.cpp"
diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp
index e0d16d2d2a..7296a6fe41 100644
--- a/src/gui/text/qtextmarkdownimporter.cpp
+++ b/src/gui/text/qtextmarkdownimporter.cpp
@@ -418,6 +418,7 @@ int QTextMarkdownImporter::cbEnterSpan(int spanType, void *det)
}
case MD_SPAN_CODE:
charFmt.setFont(m_monoFont);
+ charFmt.setFontFixedPitch(true);
break;
case MD_SPAN_DEL:
charFmt.setFontStrikeOut(true);
@@ -607,6 +608,9 @@ void QTextMarkdownImporter::insertBlock()
if (m_doc->isEmpty()) {
m_cursor->setBlockFormat(blockFormat);
m_cursor->setCharFormat(charFormat);
+ } else if (m_listItem) {
+ m_cursor->insertBlock(blockFormat, QTextCharFormat());
+ m_cursor->setCharFormat(charFormat);
} else {
m_cursor->insertBlock(blockFormat, charFormat);
}
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp
index ae63fcb4dd..3b4d794c1a 100644
--- a/src/gui/text/qtextmarkdownwriter.cpp
+++ b/src/gui/text/qtextmarkdownwriter.cpp
@@ -531,7 +531,7 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
col += s.length();
} else {
QFontInfo fontInfo(fmt.font());
- bool monoFrag = fontInfo.fixedPitch();
+ bool monoFrag = fontInfo.fixedPitch() || fmt.fontFixedPitch();
QString markers;
if (!ignoreFormat) {
if (monoFrag != mono && !m_indentedCodeBlock && !m_fencedCodeBlock) {
diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp
index 77dcae0dc8..2d307ab30e 100644
--- a/src/gui/text/qtextobject.cpp
+++ b/src/gui/text/qtextobject.cpp
@@ -1863,3 +1863,5 @@ QString QTextFragment::text() const
}
QT_END_NAMESPACE
+
+#include "moc_qtextobject.cpp"
diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp
index 155ec43c50..b3ec43702c 100644
--- a/src/gui/text/qtextodfwriter.cpp
+++ b/src/gui/text/qtextodfwriter.cpp
@@ -455,7 +455,7 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF
name.prepend(QLatin1String("qrc"));
QUrl url = QUrl(name);
const QVariant variant = m_document->resource(QTextDocument::ImageResource, url);
- if (variant.userType() == QMetaType::QImage) {
+ if (variant.userType() == QMetaType::QPixmap || variant.userType() == QMetaType::QImage) {
image = qvariant_cast<QImage>(variant);
} else if (variant.userType() == QMetaType::QByteArray) {
data = variant.toByteArray();
@@ -476,7 +476,7 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF
QBuffer imageBytes;
int imgQuality = imageFormat.quality();
- if (imgQuality >= 100 || imgQuality < 0 || image.hasAlphaChannel()) {
+ if (imgQuality >= 100 || imgQuality <= 0 || image.hasAlphaChannel()) {
QImageWriter imageWriter(&imageBytes, "png");
imageWriter.write(image);
diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp
index 39f26d5d42..0b656ce8a1 100644
--- a/src/gui/text/qtexttable.cpp
+++ b/src/gui/text/qtexttable.cpp
@@ -318,13 +318,6 @@ QTextFrame::iterator QTextTableCell::end() const
Destroys the table cell.
*/
-QTextTablePrivate::~QTextTablePrivate()
-{
- if (grid)
- free(grid);
-}
-
-
QTextTable *QTextTablePrivate::createTable(QTextDocumentPrivate *pieceTable, int pos, int rows, int cols, const QTextTableFormat &tableFormat)
{
QTextTableFormat fmt = tableFormat;
@@ -446,8 +439,7 @@ void QTextTablePrivate::update() const
nRows = (cells.size() + nCols-1)/nCols;
// qDebug(">>>> QTextTablePrivate::update, nRows=%d, nCols=%d", nRows, nCols);
- grid = q_check_ptr((int *)realloc(grid, nRows*nCols*sizeof(int)));
- memset(grid, 0, nRows*nCols*sizeof(int));
+ grid.assign(nRows * nCols, 0);
QTextDocumentPrivate *p = pieceTable;
QTextFormatCollection *c = p->formatCollection();
@@ -470,8 +462,7 @@ void QTextTablePrivate::update() const
cellIndices[i] = cell;
if (r + rowspan > nRows) {
- grid = q_check_ptr((int *)realloc(grid, sizeof(int)*(r + rowspan)*nCols));
- memset(grid + (nRows*nCols), 0, sizeof(int)*(r+rowspan-nRows)*nCols);
+ grid.resize((r + rowspan) * nCols, 0);
nRows = r + rowspan;
}
@@ -1344,3 +1335,5 @@ void QTextTable::setFormat(const QTextTableFormat &format)
*/
QT_END_NAMESPACE
+
+#include "moc_qtexttable.cpp"
diff --git a/src/gui/text/qtexttable_p.h b/src/gui/text/qtexttable_p.h
index 5c05611009..784c8824ba 100644
--- a/src/gui/text/qtexttable_p.h
+++ b/src/gui/text/qtexttable_p.h
@@ -55,14 +55,15 @@
#include "private/qtextobject_p.h"
#include "private/qtextdocument_p.h"
+#include <vector>
+
QT_BEGIN_NAMESPACE
class QTextTablePrivate : public QTextFramePrivate
{
Q_DECLARE_PUBLIC(QTextTable)
public:
- QTextTablePrivate(QTextDocument *document) : QTextFramePrivate(document), grid(nullptr), nRows(0), nCols(0), dirty(true), blockFragmentUpdates(false) {}
- ~QTextTablePrivate();
+ QTextTablePrivate(QTextDocument *document) : QTextFramePrivate(document), nRows(0), nCols(0), dirty(true), blockFragmentUpdates(false) {}
static QTextTable *createTable(QTextDocumentPrivate *, int pos, int rows, int cols, const QTextTableFormat &tableFormat);
void fragmentAdded(QChar type, uint fragment) override;
@@ -76,7 +77,7 @@ public:
// symmetric to cells array and maps to indecs in grid,
// used for fast-lookup for row/column by fragment
mutable QVector<int> cellIndices;
- mutable int *grid;
+ mutable std::vector<int> grid;
mutable int nRows;
mutable int nCols;
mutable bool dirty;
diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp
index 80c0f122e8..feab5b85b9 100644
--- a/src/gui/text/qzip.cpp
+++ b/src/gui/text/qzip.cpp
@@ -1024,13 +1024,33 @@ bool QZipReader::extractAll(const QString &destinationDir) const
// create directories first
const QVector<FileInfo> allFiles = fileInfoList();
+ bool foundDirs = false;
+ bool hasDirs = false;
for (const FileInfo &fi : allFiles) {
const QString absPath = destinationDir + QDir::separator() + fi.filePath;
if (fi.isDir) {
+ foundDirs = true;
if (!baseDir.mkpath(fi.filePath))
return false;
if (!QFile::setPermissions(absPath, fi.permissions))
return false;
+ } else if (!hasDirs && fi.filePath.contains(u"/")) {
+ // filePath does not have leading or trailing '/', so if we find
+ // one, than the file path contains directories.
+ hasDirs = true;
+ }
+ }
+
+ // Some zip archives can be broken in the sense that they do not report
+ // separate entries for directories, only for files. In this case we
+ // need to recreate directory structure based on the file paths.
+ if (hasDirs && !foundDirs) {
+ for (const FileInfo &fi : allFiles) {
+ const auto dirPath = fi.filePath.left(fi.filePath.lastIndexOf(u"/"));
+ if (!baseDir.mkpath(dirPath))
+ return false;
+ // We will leave the directory permissions default in this case,
+ // because setting dir permissions based on file is incorrect
}
}
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index fbb63a9408..4446b4297a 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -54,6 +54,8 @@
#include <qpa/qplatformintegration.h>
#include <qdir.h>
+#include <QtCore/private/qlocking_p.h>
+
QT_BEGIN_NAMESPACE
class QOpenUrlHandlerRegistry : public QObject
@@ -72,24 +74,33 @@ public:
typedef QHash<QString, Handler> HandlerHash;
HandlerHash handlers;
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
public Q_SLOTS:
void handlerDestroyed(QObject *handler);
+#endif
};
Q_GLOBAL_STATIC(QOpenUrlHandlerRegistry, handlerRegistry)
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
void QOpenUrlHandlerRegistry::handlerDestroyed(QObject *handler)
{
+ const auto lock = qt_scoped_lock(mutex);
HandlerHash::Iterator it = handlers.begin();
while (it != handlers.end()) {
if (it->receiver == handler) {
it = handlers.erase(it);
+ qWarning("Please call QDesktopServices::unsetUrlHandler() before destroying a "
+ "registered URL handler object.\n"
+ "Support for destroying a registered URL handler object is deprecated, "
+ "and will be removed in Qt 6.6.");
} else {
++it;
}
}
}
+#endif
/*!
\class QDesktopServices
@@ -279,6 +290,10 @@ bool QDesktopServices::openUrl(const QUrl &url)
Note that the handler will always be called from within the same thread that
calls QDesktopServices::openUrl().
+ You must call unsetUrlHandler() before destroying the handler object, so
+ the destruction of the handler object does not overlap with concurrent
+ invocations of openUrl() using it.
+
\sa openUrl(), unsetUrlHandler()
*/
void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, const char *method)
@@ -293,13 +308,20 @@ void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, c
h.receiver = receiver;
h.name = method;
registry->handlers.insert(scheme.toLower(), h);
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
QObject::connect(receiver, SIGNAL(destroyed(QObject*)),
- registry, SLOT(handlerDestroyed(QObject*)));
+ registry, SLOT(handlerDestroyed(QObject*)),
+ Qt::DirectConnection);
+#endif
}
/*!
Removes a previously set URL handler for the specified \a scheme.
+ Call this function before the handler object that was registered for \a scheme
+ is destroyed, to prevent concurrent openUrl() calls from continuing to call
+ the destroyed handler object.
+
\sa setUrlHandler()
*/
void QDesktopServices::unsetUrlHandler(const QString &scheme)
diff --git a/src/gui/util/qlayoutpolicy.cpp b/src/gui/util/qlayoutpolicy.cpp
index 507df44a45..063a220f94 100644
--- a/src/gui/util/qlayoutpolicy.cpp
+++ b/src/gui/util/qlayoutpolicy.cpp
@@ -133,3 +133,5 @@ QDebug operator<<(QDebug dbg, const QLayoutPolicy &p)
#endif
QT_END_NAMESPACE
+
+#include "moc_qlayoutpolicy_p.cpp"
diff --git a/src/gui/util/qpkmhandler.cpp b/src/gui/util/qpkmhandler.cpp
index e0c3b75efe..3414f9d8ba 100644
--- a/src/gui/util/qpkmhandler.cpp
+++ b/src/gui/util/qpkmhandler.cpp
@@ -57,7 +57,7 @@ struct PkmType
quint32 bytesPerBlock;
};
-static PkmType typeMap[5] = {
+static constexpr PkmType typeMap[5] = {
{ 0x8D64, 8 }, // GL_ETC1_RGB8_OES
{ 0x9274, 8 }, // GL_COMPRESSED_RGB8_ETC2
{ 0, 0 }, // unused (obsolete)
diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp
index 86f4db5dbd..ed2b9e4367 100644
--- a/src/gui/util/qvalidator.cpp
+++ b/src/gui/util/qvalidator.cpp
@@ -84,8 +84,8 @@ QT_BEGIN_NAMESPACE
\list
\li For a line edit that accepts integers from 10 to 1000 inclusive,
- 42 and 123 are \l Acceptable, the empty string and 5 are \l
- Intermediate, and "asdf" and 1114 is \l Invalid.
+ 42 and 123 are \l Acceptable, the empty string, 5, or 1234 are \l
+ Intermediate, and "asdf" and 10114 is \l Invalid.
\li For an editable combobox that accepts URLs, any well-formed URL
is \l Acceptable, "http://example.com/," is \l Intermediate
@@ -500,7 +500,7 @@ void QIntValidator::setRange(int bottom, int top)
\brief the validator's lowest acceptable value
By default, this property's value is derived from the lowest signed
- integer available (typically -2147483647).
+ integer available (-2147483648).
\sa setRange()
*/
@@ -514,7 +514,7 @@ void QIntValidator::setBottom(int bottom)
\brief the validator's highest acceptable value
By default, this property's value is derived from the highest signed
- integer available (typically 2147483647).
+ integer available (2147483647).
\sa setRange()
*/
@@ -1095,4 +1095,6 @@ void QRegularExpressionValidatorPrivate::setRegularExpression(const QRegularExpr
QT_END_NAMESPACE
+#include "moc_qvalidator.cpp"
+
#endif // QT_NO_VALIDATOR
diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp
index 555dee3a9c..19a88074af 100644
--- a/src/gui/vulkan/qvulkaninstance.cpp
+++ b/src/gui/vulkan/qvulkaninstance.cpp
@@ -531,6 +531,13 @@ void QVulkanInstance::setExtensions(const QByteArrayList &extensions)
\note This function can only be called before create() and has no effect if
called afterwards.
+
+ \note Be aware that Vulkan 1.1 changes the behavior with regards to the
+ Vulkan API version field. In Vulkan 1.0 specifying an unsupported \a
+ vulkanVersion led to failing create() with \c VK_ERROR_INCOMPATIBLE_DRIVER,
+ as was mandated by the specification. Starting with Vulkan 1.1, the
+ specification disallows this, the driver must accept any version without
+ failing the instance creation.
*/
void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion)
{
diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp
index cb89b0b1e6..e2baf298b9 100644
--- a/src/gui/vulkan/qvulkanwindow.cpp
+++ b/src/gui/vulkan/qvulkanwindow.cpp
@@ -195,6 +195,23 @@ Q_LOGGING_CATEGORY(lcGuiVk, "qt.vulkan")
\note QVulkanWindow does not expose device layers since this functionality
has been deprecated since version 1.0.13 of the Vulkan API.
+ \section1 Layers, device features, and extensions
+
+ To enable instance layers, call QVulkanInstance::setLayers() before creating
+ the QVulkanInstance. To query what instance layer are available, call
+ QVulkanInstance::supportedLayers().
+
+ To enable device extensions, call setDeviceExtensions() early on when setting
+ up the QVulkanWindow. To query what device extensions are available, call
+ supportedDeviceExtensions().
+
+ Specifying an unsupported layer or extension is handled gracefully: this will
+ not fail instance or device creation, but the layer or extension request is
+ rather ignored.
+
+ When it comes to device features, QVulkanWindow enables all Vulkan 1.0
+ features that are reported as supported from vkGetPhysicalDeviceFeatures().
+
\sa QVulkanInstance, QWindow
*/
@@ -712,6 +729,14 @@ void QVulkanWindowPrivate::init()
devInfo.enabledExtensionCount = devExts.count();
devInfo.ppEnabledExtensionNames = devExts.constData();
+ // Enable all supported 1.0 core features, except ones that likely
+ // involve a performance penalty.
+ VkPhysicalDeviceFeatures features;
+ memset(&features, 0, sizeof(features));
+ f->vkGetPhysicalDeviceFeatures(physDev, &features);
+ features.robustBufferAccess = VK_FALSE;
+ devInfo.pEnabledFeatures = &features;
+
// Device layers are not supported by QVulkanWindow since that's an already deprecated
// API. However, have a workaround for systems with older API and layers (f.ex. L4T
// 24.2 for the Jetson TX1 provides API 1.0.13 and crashes when the validation layer
@@ -1043,9 +1068,11 @@ void QVulkanWindowPrivate::recreateSwapChain()
VkPhysicalDevice physDev = physDevs.at(physDevIndex);
VkSurfaceCapabilitiesKHR surfaceCaps;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, surface, &surfaceCaps);
- uint32_t reqBufferCount = swapChainBufferCount;
- if (surfaceCaps.maxImageCount)
- reqBufferCount = qBound(surfaceCaps.minImageCount, reqBufferCount, surfaceCaps.maxImageCount);
+ uint32_t reqBufferCount;
+ if (surfaceCaps.maxImageCount == 0)
+ reqBufferCount = qMax<uint32_t>(2, surfaceCaps.minImageCount);
+ else
+ reqBufferCount = qMax(qMin<uint32_t>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
VkExtent2D bufferSize = surfaceCaps.currentExtent;
if (bufferSize.width == uint32_t(-1)) {
@@ -2018,7 +2045,7 @@ void QVulkanWindowPrivate::endFrame()
// order to circumvent driver frame callbacks
inst->presentAboutToBeQueued(q);
- err = vkQueuePresentKHR(gfxQueue, &presInfo);
+ err = vkQueuePresentKHR(presQueue, &presInfo);
if (err != VK_SUCCESS) {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapChain();
@@ -2727,3 +2754,5 @@ QMatrix4x4 QVulkanWindow::clipCorrectionMatrix()
}
QT_END_NAMESPACE
+
+#include "moc_qvulkanwindow.cpp"
diff --git a/src/gui/vulkan/qvulkanwindow_p.h b/src/gui/vulkan/qvulkanwindow_p.h
index 915e359673..336d1f098a 100644
--- a/src/gui/vulkan/qvulkanwindow_p.h
+++ b/src/gui/vulkan/qvulkanwindow_p.h
@@ -132,7 +132,7 @@ public:
// rendering thread will get throttled to the presentation rate (vsync).
// This is in effect Example 5 from the VK_KHR_swapchain spec.
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
- int swapChainBufferCount = 2;
+ int swapChainBufferCount = 0;
int frameLag = 2;
QSize swapChainImageSize;