summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/accessible/qaccessible.cpp30
-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.json1
-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/external-resources.qdoc2
-rw-r--r--src/gui/image/qiconengineplugin.cpp2
-rw-r--r--src/gui/image/qimage.cpp26
-rw-r--r--src/gui/image/qimage_neon.cpp2
-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.cpp4
-rw-r--r--src/gui/image/qppmhandler.cpp49
-rw-r--r--src/gui/image/qxpmhandler.cpp33
-rw-r--r--src/gui/kernel/qclipboard.cpp6
-rw-r--r--src/gui/kernel/qcursor.cpp3
-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.cpp19
-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.cpp2
-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/qplatformsharedgraphicscache.cpp2
-rw-r--r--src/gui/kernel/qplatformthemeplugin.cpp2
-rw-r--r--src/gui/kernel/qplatformwindow.cpp2
-rw-r--r--src/gui/kernel/qrasterwindow.cpp2
-rw-r--r--src/gui/kernel/qscreen.cpp2
-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.cpp25
-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.cpp2
-rw-r--r--src/gui/painting/qcolorspace.cpp16
-rw-r--r--src/gui/painting/qcolortrclut_p.h1
-rw-r--r--src/gui/painting/qcompositionfunctions.cpp8
-rw-r--r--src/gui/painting/qdrawhelper.cpp2
-rw-r--r--src/gui/painting/qicc.cpp2
-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/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/qplatformbackingstore.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.cpp21
-rw-r--r--src/gui/qtgui.tracepoints10
-rw-r--r--src/gui/rhi/qrhid3d11.cpp14
-rw-r--r--src/gui/rhi/qrhimetal.mm42
-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/qfont.cpp14
-rw-r--r--src/gui/text/qfontdatabase.cpp96
-rw-r--r--src/gui/text/qfontdatabase.h2
-rw-r--r--src/gui/text/qfontsubset.cpp18
-rw-r--r--src/gui/text/qfontsubset_p.h1
-rw-r--r--src/gui/text/qinputcontrol.cpp2
-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.cpp21
-rw-r--r--src/gui/text/qtextdocumentwriter.cpp7
-rw-r--r--src/gui/text/qtextengine.cpp37
-rw-r--r--src/gui/text/qtextformat.cpp2
-rw-r--r--src/gui/text/qtexthtmlparser.cpp6
-rw-r--r--src/gui/text/qtexthtmlparser_p.h4
-rw-r--r--src/gui/text/qtextimagehandler.cpp2
-rw-r--r--src/gui/text/qtextlayout.cpp39
-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.cpp2
-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.cpp29
125 files changed, 1126 insertions, 477 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp
index d705bfccb5..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());
@@ -696,14 +715,15 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
// Find a QAccessiblePlugin (factory) for the class name. If there's
// no entry in the cache try to create it using the plugin loader.
if (!qAccessiblePlugins()->contains(cn)) {
+ QAccessiblePlugin *factory = nullptr; // 0 means "no plugin found". This is cached as well.
const int index = loader()->indexOf(cn);
- if (index != -1) {
- QAccessiblePlugin *factory = qobject_cast<QAccessiblePlugin *>(loader()->instance(index));
- qAccessiblePlugins()->insert(cn, factory);
- }
+ if (index != -1)
+ factory = qobject_cast<QAccessiblePlugin *>(loader()->instance(index));
+ qAccessiblePlugins()->insert(cn, factory);
}
// At this point the cache should contain a valid factory pointer or 0:
+ Q_ASSERT(qAccessiblePlugins()->contains(cn));
QAccessiblePlugin *factory = qAccessiblePlugins()->value(cn);
if (factory) {
QAccessibleInterface *result = factory->create(cn, object);
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 1f08795c57..7b80162faa 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -1363,6 +1363,7 @@
"vkgen": {
"label": "vkgen",
"condition": "features.xmlstreamreader",
+ "disable": "input.vulkan == 'no'",
"output": [ "privateFeature" ]
},
"vulkan": {
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/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 a5d708661f..04e1a00429 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -2157,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();
@@ -2258,6 +2258,7 @@ bool QImage::reinterpretAsFormat(Format format)
// In case detach() ran out of memory
if (!d) {
d = oldD;
+ d->ref.ref();
return false;
}
}
@@ -4693,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());
@@ -4721,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());
@@ -4733,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());
@@ -4974,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;
}
@@ -5016,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
@@ -5051,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);
}
};
@@ -5647,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_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/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 bbf44a484f..2811d2e049 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -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 16fd78f25f..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
@@ -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 d6ccaff8ed..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.
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 a95331e246..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;
@@ -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)
@@ -2156,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
@@ -3061,7 +3064,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QEvent::Type mouseEventType = QEvent::MouseMove;
Qt::MouseButton button = Qt::NoButton;
Qt::MouseButtons buttons = Qt::LeftButton;
- if (eventType == QEvent::TouchBegin && m_fakeMouseSourcePointId < 0)
+ if (eventType == QEvent::TouchBegin || m_fakeMouseSourcePointId < 0)
m_fakeMouseSourcePointId = touchPoints.first().id();
for (const auto &touchPoint : touchPoints) {
if (touchPoint.id() == m_fakeMouseSourcePointId) {
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 4654e52c72..a192b7aef4 100644
--- a/src/gui/kernel/qpalette.cpp
+++ b/src/gui/kernel/qpalette.cpp
@@ -1234,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/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/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 e75229324c..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;
}
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 8e0eb35116..990272b0c2 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -849,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 e248a04392..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()
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 9e5605dd48..08d7055b82 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -2638,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/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 8b2ea4e04d..dd30c64640 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -146,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;
@@ -844,3 +848,5 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
#endif
QT_END_NAMESPACE
+
+#include "moc_qcolorspace.cpp"
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/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index a61793508a..5ba2d277b7 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -6091,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);
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index 15e236ac9e..4651adbd2a 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -750,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;
}
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/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/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/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 0952bd22fb..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}
*/
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 5fe18c9827..acd53b3dfd 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -3738,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()
@@ -3800,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/qfont.cpp b/src/gui/text/qfont.cpp
index 5a1fa36e5c..9f16af0222 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -220,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;
}
@@ -630,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;
}
@@ -3316,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 72dcac6904..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;
@@ -503,12 +522,10 @@ void QFontDatabasePrivate::invalidate()
emit static_cast<QGuiApplication *>(QCoreApplication::instance())->fontDatabaseChanged();
}
-QtFontFamily *QFontDatabasePrivate::family(const QString &family, FamilyRequestFlags flags)
+QtFontFamily *QFontDatabasePrivate::family(const QString &f, FamilyRequestFlags flags)
{
QtFontFamily *fam = nullptr;
- const QString f = family.trimmed();
-
int low = 0;
int high = count;
int pos = count / 2;
@@ -828,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) {
@@ -1221,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;
@@ -1273,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.
@@ -1298,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;
}
@@ -1731,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:
@@ -2476,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()
*/
@@ -2510,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()
*/
@@ -2650,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());
@@ -2692,11 +2721,20 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
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;
@@ -2889,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);
}
@@ -2902,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/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 80d5e6af4e..8c05346730 100644
--- a/src/gui/text/qinputcontrol.cpp
+++ b/src/gui/text/qinputcontrol.cpp
@@ -140,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 9d70873590..72267e9380 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -2123,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());
@@ -2186,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)
@@ -2198,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) {
@@ -2357,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.
@@ -2536,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)
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 8af64f9cf8..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);
@@ -1559,6 +1565,12 @@ void QTextEngine::shapeText(int item) const
// 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;
}
@@ -2173,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 124c530cb5..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()) {
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 053be89959..e650984c63 100644
--- a/src/gui/text/qtextimagehandler.cpp
+++ b/src/gui/text/qtextimagehandler.cpp
@@ -244,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 5ae41d9459..30f07ba69b 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1173,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)) {
@@ -1329,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)
@@ -1343,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);
@@ -1980,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) {
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 125b97a382..0b656ce8a1 100644
--- a/src/gui/text/qtexttable.cpp
+++ b/src/gui/text/qtexttable.cpp
@@ -1335,3 +1335,5 @@ void QTextTable::setFormat(const QTextTableFormat &format)
*/
QT_END_NAMESPACE
+
+#include "moc_qtexttable.cpp"
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 cee1f2540f..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
@@ -2020,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();
@@ -2729,3 +2754,5 @@ QMatrix4x4 QVulkanWindow::clipCorrectionMatrix()
}
QT_END_NAMESPACE
+
+#include "moc_qvulkanwindow.cpp"