summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/doc/src/coordsys.qdoc2
-rw-r--r--src/gui/doc/src/qt6-changes.qdoc12
-rw-r--r--src/gui/image/qicon.cpp2
-rw-r--r--src/gui/image/qimage.cpp36
-rw-r--r--src/gui/image/qimagereader.cpp4
-rw-r--r--src/gui/image/qpnghandler.cpp4
-rw-r--r--src/gui/image/qxpmhandler.cpp2
-rw-r--r--src/gui/itemmodels/qfilesystemmodel.cpp7
-rw-r--r--src/gui/itemmodels/qstandarditemmodel.cpp47
-rw-r--r--src/gui/kernel/qevent.cpp6
-rw-r--r--src/gui/kernel/qguiapplication.cpp2
-rw-r--r--src/gui/kernel/qoffscreensurface_platform.h2
-rw-r--r--src/gui/kernel/qplatformwindow.cpp37
-rw-r--r--src/gui/math3d/qmatrix4x4.h10
-rw-r--r--src/gui/math3d/qquaternion.cpp6
-rw-r--r--src/gui/painting/qcolorspace.cpp1
-rw-r--r--src/gui/painting/qcolortransfertable_p.h8
-rw-r--r--src/gui/painting/qcolortrc_p.h2
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp8
-rw-r--r--src/gui/painting/qdrawhelper.cpp9
-rw-r--r--src/gui/painting/qicc.cpp35
-rw-r--r--src/gui/painting/qmemrotate.cpp42
-rw-r--r--src/gui/painting/qpagesize.h2
-rw-r--r--src/gui/painting/qpaintengineex.cpp44
-rw-r--r--src/gui/painting/qpainterpath.cpp2
-rw-r--r--src/gui/painting/qpainterpath_p.h1
-rw-r--r--src/gui/painting/qpixellayout.cpp22
-rw-r--r--src/gui/painting/qrasterizer.cpp2
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp17
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h2
-rw-r--r--src/gui/platform/unix/dbustray/qdbustrayicon.cpp8
-rw-r--r--src/gui/platform/unix/qxkbcommon.cpp13
-rw-r--r--src/gui/platform/windows/qwindowsnativeinterface.cpp1
-rw-r--r--src/gui/rhi/qrhigles2.cpp30
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h4
-rw-r--r--src/gui/rhi/qrhimetal.mm64
-rw-r--r--src/gui/text/freetype/qfontengine_ft.cpp6
-rw-r--r--src/gui/text/qcssparser.cpp4
-rw-r--r--src/gui/text/qfontdatabase.cpp4
-rw-r--r--src/gui/text/qfontmetrics.cpp18
-rw-r--r--src/gui/text/qtextdocumentwriter.cpp5
-rw-r--r--src/gui/text/qtextengine.cpp27
-rw-r--r--src/gui/text/qtexthtmlparser.cpp2
-rw-r--r--src/gui/text/qtextlayout.cpp10
44 files changed, 370 insertions, 202 deletions
diff --git a/src/gui/doc/src/coordsys.qdoc b/src/gui/doc/src/coordsys.qdoc
index ed413b500f..4df7151750 100644
--- a/src/gui/doc/src/coordsys.qdoc
+++ b/src/gui/doc/src/coordsys.qdoc
@@ -119,7 +119,7 @@
\table
\header
- \li {3,1} QRectF
+ \li {2,1} QRectF
\row
\li \inlineimage qrect-diagram-zero.png
\li \inlineimage qrectf-diagram-one.png
diff --git a/src/gui/doc/src/qt6-changes.qdoc b/src/gui/doc/src/qt6-changes.qdoc
index 94073a3fb8..b835706f80 100644
--- a/src/gui/doc/src/qt6-changes.qdoc
+++ b/src/gui/doc/src/qt6-changes.qdoc
@@ -43,18 +43,18 @@
\section1 Kernel classes
- \section2 QBitmap
+ \section2 The QBitmap class
Implicit construction of a QBitmap from a QPixmap is no longer supported.
The constructor and assignment operator have been made explicit and marked as
deprecated. Use the new static factory function \l{QBitmap::}{fromPixmap} instead.
- \section2 QCursor
+ \section2 The QCursor class
Implicit construction of a QCursor from a QPixmap is no longer supported, the
constructor has been made explicit.
- \section2 QKeyCombination
+ \section2 The QKeyCombination class
QKeyCombination is a new class for storing a combination of a key with an
optional modifier. It should be used as a replacement for combining values from
@@ -70,7 +70,7 @@
\section1 Text classes
- \section2 QFontDatabase
+ \section2 The QFontDatabase class
The QFontDatabase class has now only static member functions. The constructor
has been deprecated. Instead of e.g.
@@ -85,7 +85,7 @@
const QStringList fontFamilies = QFontDatabase::families();
\endcode
- \section2 QFont
+ \section2 The QFont class
The numerical values of the QFont::Weight enumerator have been changed to
be in line with OpenType weight values. QFont::setWeight() expects an enum value
@@ -117,7 +117,7 @@
In addition, the class \l QOpenGLWidget has been moved to a new module, named
Qt OpenGL Widgets.
- \section2 QOpenGLContext
+ \section2 The QOpenGLContext class
The QOpenGLContext::versionFunctions() function is replaced by
QOpenGLVersionFunctionsFactory::get(). QOpenGLVersionFunctionsFactory is a public
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index fdb2ab0f9b..4f31414e10 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -174,7 +174,7 @@ void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode
auto paintDevice = painter->device();
qreal dpr = paintDevice ? paintDevice->devicePixelRatio() : qApp->devicePixelRatio();
const QSize pixmapSize = rect.size() * dpr;
- QPixmap px = pixmap(pixmapSize, mode, state);
+ QPixmap px = scaledPixmap(pixmapSize, mode, state, dpr);
painter->drawPixmap(rect, px);
}
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 7ca5b13373..9a9ab873ff 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -1709,10 +1709,14 @@ void QImage::fill(uint pixel)
w, d->height, d->bytes_per_line);
return;
} else if (d->depth == 16) {
+ if (d->format == Format_RGB444)
+ pixel |= 0xf000;
qt_rectfill<quint16>(reinterpret_cast<quint16*>(d->data), pixel,
0, 0, d->width, d->height, d->bytes_per_line);
return;
} else if (d->depth == 24) {
+ if (d->format == Format_RGB666)
+ pixel |= 0xfc0000;
qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
0, 0, d->width, d->height, d->bytes_per_line);
return;
@@ -1781,6 +1785,8 @@ void QImage::fill(const QColor &color)
if (!d)
return;
+ QRgba64 opaque = color.rgba64();
+ opaque.setAlpha(65535);
switch (d->format) {
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
@@ -1799,12 +1805,10 @@ void QImage::fill(const QColor &color)
fill(ARGB2RGBA(qPremultiply(color.rgba())));
break;
case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- fill(qConvertRgb64ToRgb30<PixelOrderBGR>(color.rgba64()));
+ fill(qConvertRgb64ToRgb30<PixelOrderBGR>(opaque));
break;
case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- fill(qConvertRgb64ToRgb30<PixelOrderRGB>(color.rgba64()));
+ fill(qConvertRgb64ToRgb30<PixelOrderRGB>(opaque));
break;
case QImage::Format_RGB16:
fill((uint) qConvertRgb32To16(color.rgba()));
@@ -1827,19 +1831,18 @@ void QImage::fill(const QColor &color)
else
fill((uint) 0);
break;
- case QImage::Format_RGBX64: {
- QRgba64 c = color.rgba64();
- c.setAlpha(65535);
- qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), c,
+ case QImage::Format_RGBX64:
+ qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), opaque,
0, 0, d->width, d->height, d->bytes_per_line);
break;
-
- }
case QImage::Format_RGBA64:
- case QImage::Format_RGBA64_Premultiplied:
qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), color.rgba64(),
0, 0, d->width, d->height, d->bytes_per_line);
break;
+ case QImage::Format_RGBA64_Premultiplied:
+ qt_rectfill<quint64>(reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
+ 0, 0, d->width, d->height, d->bytes_per_line);
+ break;
default: {
QPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_Source);
@@ -2467,7 +2470,7 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
((uint *)s)[x] = index_or_rgb;
return;
case Format_RGB16:
- ((quint16 *)s)[x] = qConvertRgb32To16(qUnpremultiply(index_or_rgb));
+ ((quint16 *)s)[x] = qConvertRgb32To16(index_or_rgb);
return;
case Format_RGBX8888:
((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
@@ -2488,6 +2491,10 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
case Format_A2RGB30_Premultiplied:
((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
return;
+ case Format_RGBA64:
+ case Format_RGBA64_Premultiplied:
+ ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
+ return;
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
@@ -2497,7 +2504,10 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
}
const QPixelLayout *layout = &qPixelLayouts[d->format];
- layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
+ if (!hasAlphaChannel())
+ layout->storeFromRGB32(s, &index_or_rgb, x, 1, nullptr, nullptr);
+ else
+ layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
}
/*!
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 611cbb1df1..fccf67b428 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -769,7 +769,7 @@ bool QImageReader::decideFormatFromContent() const
otherwise left unchanged.
If the device is not already open, QImageReader will attempt to
- open the device in \l QIODevice::ReadOnly mode by calling
+ open the device in \l {QIODeviceBase::}{ReadOnly} mode by calling
open(). Note that this does not work for certain devices, such as
QProcess, QTcpSocket and QUdpSocket, where more logic is required
to open the device.
@@ -799,7 +799,7 @@ QIODevice *QImageReader::device() const
/*!
Sets the file name of QImageReader to \a fileName. Internally,
QImageReader will create a QFile object and open it in \l
- QIODevice::ReadOnly mode, and use this when reading images.
+ {QIODeviceBase::}{ReadOnly} mode, and use this when reading images.
If \a fileName does not include a file extension (e.g., .png or .bmp),
QImageReader will cycle through all supported extensions until it finds
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index de913af320..20a86b4f8f 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -500,7 +500,7 @@ static void read_image_scaled(QImage *outImage, png_structp png_ptr, png_infop i
extern "C" {
static void qt_png_warning(png_structp /*png_ptr*/, png_const_charp message)
{
- qCWarning(lcImageIo, "libpng warning: %s", message);
+ qCInfo(lcImageIo, "libpng warning: %s", message);
}
}
@@ -590,7 +590,7 @@ bool QPngHandlerPrivate::readPngHeader()
png_get_iCCP(png_ptr, info_ptr, &name, &compressionType, &profileData, &profLen);
colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen));
if (!colorSpace.isValid()) {
- qCWarning(lcImageIo) << "QPngHandler: Failed to parse ICC profile";
+ qCDebug(lcImageIo) << "QPngHandler: Failed to parse ICC profile";
} else {
QColorSpacePrivate *csD = QColorSpacePrivate::get(colorSpace);
if (csD->description.isEmpty())
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index 7b545614a7..8ec09f2480 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -934,7 +934,7 @@ static bool read_xpm_body(
colorMap.insert(xpmHash(QLatin1String(index.constData())), 0);
}
} else {
- QRgb c_rgb;
+ QRgb c_rgb = 0;
if (((buf.length()-1) % 3) && (buf[0] == '#')) {
buf.truncate(((buf.length()-1) / 4 * 3) + 1); // remove alpha channel left by imagemagick
}
diff --git a/src/gui/itemmodels/qfilesystemmodel.cpp b/src/gui/itemmodels/qfilesystemmodel.cpp
index 70c274b816..e0274e5fef 100644
--- a/src/gui/itemmodels/qfilesystemmodel.cpp
+++ b/src/gui/itemmodels/qfilesystemmodel.cpp
@@ -391,8 +391,11 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS
if (absolutePath.endsWith(QLatin1Char('/')))
trailingSeparator = QLatin1String("\\");
int r = 0;
- QFileSystemModelPrivate::QFileSystemNode *rootNode = const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
- if (!root.children.contains(host.toLower())) {
+ auto rootNode = const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
+ auto it = root.children.constFind(host);
+ if (it != root.children.cend()) {
+ host = it.key(); // Normalize case for lookup in visibleLocation()
+ } else {
if (pathElements.count() == 1 && !absolutePath.endsWith(QLatin1Char('/')))
return rootNode;
QFileInfo info(host);
diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp
index 234296271b..03c7b5c152 100644
--- a/src/gui/itemmodels/qstandarditemmodel.cpp
+++ b/src/gui/itemmodels/qstandarditemmodel.cpp
@@ -968,31 +968,29 @@ void QStandardItem::clearData()
*/
QVariant QStandardItem::data(int role) const
{
- QModelRoleData result(role);
- multiData(result);
- return result.data();
+ Q_D(const QStandardItem);
+ const int r = (role == Qt::EditRole) ? Qt::DisplayRole : role;
+ for (const auto &value : d->values) {
+ if (value.role == r)
+ return value.value;
+ }
+ return QVariant();
}
-void QStandardItem::multiData(QModelRoleDataSpan roleDataSpan) const
-{
- Q_D(const QStandardItem);
+/*!
+ \since 6.0
- const auto valuesBegin = d->values.begin();
- const auto valuesEnd = d->values.end();
+ Fills the \a roleDataSpan span with the data from this item.
- for (auto &roleData : roleDataSpan) {
- const int role = (roleData.role() == Qt::EditRole) ? Qt::DisplayRole : roleData.role();
- const auto hasSameRole = [role](const QStandardItemData &data)
- {
- return data.role == role;
- };
+ The default implementation simply calls data() for each role
+ in the span.
- auto dataIt = std::find_if(valuesBegin, valuesEnd, hasSameRole);
- if (dataIt != valuesEnd)
- roleData.setData(dataIt->value);
- else
- roleData.clearData();
- }
+ \sa data()
+*/
+void QStandardItem::multiData(QModelRoleDataSpan roleDataSpan) const
+{
+ for (auto &roleData : roleDataSpan)
+ roleData.setData(data(roleData.role()));
}
/*!
@@ -2846,10 +2844,11 @@ QVariant QStandardItemModel::data(const QModelIndex &index, int role) const
*/
void QStandardItemModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
{
- Q_D(const QStandardItemModel);
- QStandardItem *item = d->itemFromIndex(index);
- if (item)
- item->multiData(roleDataSpan);
+ // Cannot offer a better implementation; users may be overriding
+ // data(), and thus multiData() may fall out of sync for them.
+ // The base class' implementation will simply call data() in a loop,
+ // so it's fine.
+ QAbstractItemModel::multiData(index, roleDataSpan);
}
/*!
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 0caba17ddd..751ef65c8b 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -253,6 +253,12 @@ QInputEvent::~QInputEvent()
*/
/*!
+ \fn const QList<QEventPoint> &QPointerEvent::points() const
+
+ Returns a list of points in this pointer event.
+*/
+
+/*!
\fn QPointingDevice::PointerType QPointerEvent::pointerType() const
Returns the type of point that generated the event.
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 259399e029..e452e97cd8 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -2176,7 +2176,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
diff --git a/src/gui/kernel/qoffscreensurface_platform.h b/src/gui/kernel/qoffscreensurface_platform.h
index f95b606dba..addba347b9 100644
--- a/src/gui/kernel/qoffscreensurface_platform.h
+++ b/src/gui/kernel/qoffscreensurface_platform.h
@@ -44,7 +44,7 @@
#include <QtGui/qoffscreensurface.h>
#if defined(Q_OS_ANDROID)
-QT_FORWARD_DECLARE_CLASS(ANativeWindow);
+struct ANativeWindow;
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index f9e984c9cb..0bee2968f7 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -678,16 +678,16 @@ void QPlatformWindow::invalidateSurface()
{
}
-static QSize fixInitialSize(QSize size, const QWindow *w,
- int defaultWidth, int defaultHeight)
+static QSize fixInitialSize(QSize size, const QWindow *w, int deviceIndependentDefaultWidth,
+ int deviceIndependentDefaultHeight)
{
if (size.width() == 0) {
const int minWidth = w->minimumWidth();
- size.setWidth(minWidth > 0 ? minWidth : defaultWidth);
+ size.setWidth(minWidth > 0 ? minWidth : deviceIndependentDefaultWidth);
}
if (size.height() == 0) {
const int minHeight = w->minimumHeight();
- size.setHeight(minHeight > 0 ? minHeight : defaultHeight);
+ size.setHeight(minHeight > 0 ? minHeight : deviceIndependentDefaultHeight);
}
return size;
}
@@ -700,6 +700,10 @@ static QSize fixInitialSize(QSize size, const QWindow *w,
layout new windows to optimize usage of the available desktop space.
However if the given window already has geometry which the application has
initialized, it takes priority.
+
+ \a initialGeometry has to be provided in native pixels.
+ \a defaultWidth has to be provided in device independent pixels
+ \a defaultHeight has to be provided in device independent pixels
*/
QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry,
int defaultWidth, int defaultHeight,
@@ -709,9 +713,10 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeo
*resultingScreenReturn = w->screen();
if (!w->isTopLevel()) {
const qreal factor = QHighDpiScaling::factor(w);
- const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor),
- w, defaultWidth, defaultHeight);
- return QRect(initialGeometry.topLeft(), QHighDpi::toNative(size, factor));
+ const QSize deviceIndependentSize =
+ fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor), w,
+ defaultWidth, defaultHeight);
+ return QRect(initialGeometry.topLeft(), QHighDpi::toNative(deviceIndependentSize, factor));
}
const auto *wp = qt_window_private(const_cast<QWindow*>(w));
const bool position = wp->positionAutomatic && w->type() != Qt::Popup;
@@ -725,26 +730,28 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeo
if (resultingScreenReturn)
*resultingScreenReturn = screen;
// initialGeometry refers to window's screen
- QRect rect(QHighDpi::fromNativePixels(initialGeometry, w));
+ QRect deviceIndependentRect(QHighDpi::fromNativePixels(initialGeometry, w));
if (wp->resizeAutomatic)
- rect.setSize(fixInitialSize(rect.size(), w, defaultWidth, defaultHeight));
+ deviceIndependentRect.setSize(
+ fixInitialSize(deviceIndependentRect.size(), w, defaultWidth, defaultHeight));
if (position) {
- const QRect availableGeometry = screen->availableGeometry();
+ const QRect availableDeviceIndependentGeometry = screen->availableGeometry();
// Center unless the geometry ( + unknown window frame) is too large for the screen).
- if (rect.height() < (availableGeometry.height() * 8) / 9
- && rect.width() < (availableGeometry.width() * 8) / 9) {
+ if (deviceIndependentRect.height() < (availableDeviceIndependentGeometry.height() * 8) / 9
+ && deviceIndependentRect.width()
+ < (availableDeviceIndependentGeometry.width() * 8) / 9) {
const QWindow *tp = w->transientParent();
if (tp) {
// A transient window should be centered w.r.t. its transient parent.
- rect.moveCenter(tp->geometry().center());
+ deviceIndependentRect.moveCenter(tp->geometry().center());
} else {
// Center the window on the screen. (Only applicable on platforms
// which do not provide a better way.)
- rect.moveCenter(availableGeometry.center());
+ deviceIndependentRect.moveCenter(availableDeviceIndependentGeometry.center());
}
}
}
- return QHighDpi::toNativePixels(rect, screen);
+ return QHighDpi::toNativePixels(deviceIndependentRect, screen);
}
/*!
diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h
index 402f27fcb5..ec4253133a 100644
--- a/src/gui/math3d/qmatrix4x4.h
+++ b/src/gui/math3d/qmatrix4x4.h
@@ -157,14 +157,14 @@ public:
QTransform toTransform() const;
QTransform toTransform(float distanceToPlane) const;
- QPoint map(const QPoint& point) const;
- QPointF map(const QPointF& point) const;
+ inline QPoint map(const QPoint& point) const;
+ inline QPointF map(const QPointF& point) const;
#ifndef QT_NO_VECTOR3D
- QVector3D map(const QVector3D& point) const;
- QVector3D mapVector(const QVector3D& vector) const;
+ inline QVector3D map(const QVector3D& point) const;
+ inline QVector3D mapVector(const QVector3D& vector) const;
#endif
#ifndef QT_NO_VECTOR4D
- QVector4D map(const QVector4D& point) const;
+ inline QVector4D map(const QVector4D& point) const;
#endif
QRect mapRect(const QRect& rect) const;
QRectF mapRect(const QRectF& rect) const;
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index 440ed3c99b..86e7d8ce62 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -527,7 +527,11 @@ void QQuaternion::getEulerAngles(float *pitch, float *yaw, float *roll) const
zw /= lengthSquared;
}
- *pitch = std::asin(-2.0f * (yz - xw));
+ const float sinp = -2.0f * (yz - xw);
+ if (std::abs(sinp) >= 1.0f)
+ *pitch = std::copysign(M_PI_2, sinp);
+ else
+ *pitch = std::asin(sinp);
if (*pitch < M_PI_2) {
if (*pitch > -M_PI_2) {
*yaw = std::atan2(2.0f * (xz + yw), 1.0f - 2.0f * (xx + yy));
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index ed25ead262..c9c32c6bb7 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -331,6 +331,7 @@ void QColorSpacePrivate::setTransferFunction()
}
trc[1] = trc[0];
trc[2] = trc[0];
+ lut.generated.storeRelease(0);
}
QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpacePrivate *out) const
diff --git a/src/gui/painting/qcolortransfertable_p.h b/src/gui/painting/qcolortransfertable_p.h
index fdf68b78da..2d8f41e086 100644
--- a/src/gui/painting/qcolortransfertable_p.h
+++ b/src/gui/painting/qcolortransfertable_p.h
@@ -136,7 +136,7 @@ public:
return 1.0f;
if (!m_table16.isEmpty()) {
float v = x * 65535.0f;
- uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1;
+ uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1));
for ( ; i < m_tableSize; ++i) {
if (m_table16[i] > v)
break;
@@ -145,14 +145,14 @@ public:
return 1.0f;
float y1 = m_table16[i - 1];
float y2 = m_table16[i];
- Q_ASSERT(x >= y1 && x < y2);
+ Q_ASSERT(v >= y1 && v <= y2);
float fr = (v - y1) / (y2 - y1);
return (i + fr) * (1.0f / (m_tableSize - 1));
}
if (!m_table8.isEmpty()) {
float v = x * 255.0f;
- uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1;
+ uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1));
for ( ; i < m_tableSize; ++i) {
if (m_table8[i] > v)
break;
@@ -161,7 +161,7 @@ public:
return 1.0f;
float y1 = m_table8[i - 1];
float y2 = m_table8[i];
- Q_ASSERT(x >= y1 && x < y2);
+ Q_ASSERT(v >= y1 && v <= y2);
float fr = (v - y1) / (y2 - y1);
return (i + fr) * (1.0f / (m_tableSize - 1));
}
diff --git a/src/gui/painting/qcolortrc_p.h b/src/gui/painting/qcolortrc_p.h
index 3ef9d442fc..058be3c7ce 100644
--- a/src/gui/painting/qcolortrc_p.h
+++ b/src/gui/painting/qcolortrc_p.h
@@ -114,7 +114,7 @@ public:
if (x >= 0.0f && x <= 1.0f)
return applyInverse(x);
if (m_type == Type::Function)
- return std::copysign(applyInverse(x), x);
+ return std::copysign(applyInverse(std::abs(x)), x);
if (m_type == Type::Table)
return x < 0.0f ? 0.0f : 1.0f;
return x;
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
index 2b7ad91ec5..5b00362c66 100644
--- a/src/gui/painting/qcosmeticstroker.cpp
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -377,14 +377,14 @@ bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2)
{
- if (p1 == p2) {
+ QPointF start = p1 * state->matrix;
+ QPointF end = p2 * state->matrix;
+
+ if (start == end) {
drawPoints(&p1, 1);
return;
}
- QPointF start = p1 * state->matrix;
- QPointF end = p2 * state->matrix;
-
patternOffset = state->lastPen.dashOffset()*64;
lastPixel.x = INT_MIN;
lastPixel.y = INT_MIN;
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index ee0e17d917..3cff7386e1 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -2407,6 +2407,7 @@ static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QIm
#define FIXPT_BITS 8
#define FIXPT_SIZE (1<<FIXPT_BITS)
+#define FIXPT_MAX (INT_MAX >> (FIXPT_BITS + 1))
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
{
@@ -2503,10 +2504,12 @@ static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template(
const BlendType *end = buffer + length;
if (affine) {
if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
- GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length);
+ if (std::abs(t) < FIXPT_MAX)
+ GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length);
+ else
+ GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, t / GRADIENT_STOPTABLE_SIZE), length);
} else {
- if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
- t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
+ if (std::abs(t) < FIXPT_MAX && std::abs(inc) < FIXPT_MAX && std::abs(t + inc * length) < FIXPT_MAX) {
// we can use fixed point math
int t_fixed = int(t * FIXPT_SIZE);
int inc_fixed = int(inc * FIXPT_SIZE);
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index 5e30ace549..09ac40b50e 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -52,7 +52,7 @@
#include <array>
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc")
+Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc", QtWarningMsg)
struct ICCProfileHeader
{
@@ -165,7 +165,7 @@ struct XYZTagData : GenericTagData {
struct CurvTagData : GenericTagData {
quint32_be valueCount;
- quint16_be value[1];
+ // followed by curv values: quint16_be[]
};
struct ParaTagData : GenericTagData {
@@ -237,18 +237,20 @@ static bool isValidIccProfile(const ICCProfileHeader &header)
}
if (header.profileClass != uint(ProfileClass::Input)
- && header.profileClass != uint(ProfileClass::Display)) {
- qCWarning(lcIcc, "Unsupported ICC profile class %x", quint32(header.profileClass));
+ && header.profileClass != uint(ProfileClass::Display)
+ && (header.profileClass != uint(ProfileClass::Output)
+ || header.inputColorSpace != uint(ColorSpaceType::Gray))) {
+ qCInfo(lcIcc, "Unsupported ICC profile class 0x%x", quint32(header.profileClass));
return false;
}
if (header.inputColorSpace != uint(ColorSpaceType::Rgb)
&& header.inputColorSpace != uint(ColorSpaceType::Gray)) {
- qCWarning(lcIcc, "Unsupported ICC input color space %x", quint32(header.inputColorSpace));
+ qCInfo(lcIcc, "Unsupported ICC input color space 0x%x", quint32(header.inputColorSpace));
return false;
}
if (header.pcs != 0x58595a20 /* 'XYZ '*/) {
// ### support PCSLAB
- qCWarning(lcIcc, "Unsupported ICC profile connection space %x", quint32(header.pcs));
+ qCInfo(lcIcc, "Unsupported ICC profile connection space 0x%x", quint32(header.pcs));
return false;
}
@@ -468,25 +470,26 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
const GenericTagData trcData = qFromUnaligned<GenericTagData>(data.constData()
+ tagEntry.offset);
if (trcData.type == quint32(Tag::curv)) {
+ Q_STATIC_ASSERT(sizeof(CurvTagData) == 12);
const CurvTagData curv = qFromUnaligned<CurvTagData>(data.constData() + tagEntry.offset);
if (curv.valueCount > (1 << 16))
return false;
if (tagEntry.size - 12 < 2 * curv.valueCount)
return false;
+ const auto valueOffset = tagEntry.offset + sizeof(CurvTagData);
if (curv.valueCount == 0) {
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(); // Linear
} else if (curv.valueCount == 1) {
- float g = curv.value[0] * (1.0f / 256.0f);
+ const quint16 v = qFromBigEndian<quint16>(data.constData() + valueOffset);
gamma.m_type = QColorTrc::Type::Function;
- gamma.m_fun = QColorTransferFunction::fromGamma(g);
+ gamma.m_fun = QColorTransferFunction::fromGamma(v * (1.0f / 256.0f));
} else {
QList<quint16> tabl;
tabl.resize(curv.valueCount);
static_assert(sizeof(GenericTagData) == 2 * sizeof(quint32_be),
"GenericTagData has padding. The following code is a subject to UB.");
- const auto offset = tagEntry.offset + sizeof(GenericTagData) + sizeof(quint32_be);
- qFromBigEndian<quint16>(data.constData() + offset, curv.valueCount, tabl.data());
+ qFromBigEndian<quint16>(data.constData() + valueOffset, curv.valueCount, tabl.data());
QColorTransferTable table = QColorTransferTable(curv.valueCount, std::move(tabl));
QColorTransferFunction curve;
if (!table.checkValidity()) {
@@ -524,6 +527,8 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
return false;
std::array<quint32_be, 3> parameters =
qFromUnaligned<decltype(parameters)>(data.constData() + parametersOffset);
+ if (parameters[1] == 0)
+ return false;
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
@@ -537,6 +542,8 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
return false;
std::array<quint32_be, 4> parameters =
qFromUnaligned<decltype(parameters)>(data.constData() + parametersOffset);
+ if (parameters[1] == 0)
+ return false;
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
@@ -646,7 +653,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
const ICCProfileHeader header = qFromUnaligned<ICCProfileHeader>(data.constData());
if (!isValidIccProfile(header))
return false; // if failed we already printing a warning
- if (qsizetype(header.profileSize) > data.size()) {
+ if (qsizetype(header.profileSize) > data.size() || qsizetype(header.profileSize) < qsizetype(sizeof(ICCProfileHeader))) {
qCWarning(lcIcc) << "fromIccProfile: failed size sanity 2";
return false;
}
@@ -698,7 +705,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) ||
!tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) ||
!tagIndex.contains(Tag::wtpt)) {
- qCWarning(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based";
+ qCInfo(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based";
return false;
}
} else {
@@ -753,12 +760,12 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
} else {
colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
// Calculate chromaticity from xyz (assuming y == 1.0f).
- float y = 1.0f / (1.0f + whitePoint.z - whitePoint.x);
+ float y = 1.0f / (1.0f + whitePoint.z + whitePoint.x);
float x = whitePoint.x * y;
QColorSpacePrimaries primaries(QColorSpace::Primaries::SRgb);
primaries.whitePoint = QPointF(x,y);
if (!primaries.areValid()) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - invalid white-point";
+ qCWarning(lcIcc, "fromIccProfile: Invalid ICC profile - invalid white-point(%f, %f)", x, y);
return false;
}
colorspaceDPtr->toXyz = primaries.toXyzMatrix();
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index 5c04bcb795..b3bee9e5e7 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -44,12 +44,11 @@ QT_BEGIN_NAMESPACE
static const int tileSize = 32;
-template <class T>
-static
-inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
+template<class T>
+static inline void qt_memrotate90_tiled(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
- sstride /= sizeof(T);
- dstride /= sizeof(T);
+ const qsizetype sstride = isstride / sizeof(T);
+ const qsizetype dstride = idstride / sizeof(T);
const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
@@ -103,11 +102,11 @@ inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *des
}
}
-template <class T>
-static
-inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
+template<class T>
+static inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
const int numTilesX = (w + tileSize - 1) / tileSize;
const int numTilesY = (h + tileSize - 1) / tileSize;
@@ -131,12 +130,11 @@ inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int sstrid
}
}
-template <class T>
-static
-inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
+template<class T>
+static inline void qt_memrotate270_tiled(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
- sstride /= sizeof(T);
- dstride /= sizeof(T);
+ const qsizetype sstride = isstride / sizeof(T);
+ const qsizetype dstride = idstride / sizeof(T);
const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
@@ -190,11 +188,11 @@ inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *de
}
}
-template <class T>
-static
-inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
+template<class T>
+static inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
const int numTilesX = (w + tileSize - 1) / tileSize;
const int numTilesY = (h + tileSize - 1) / tileSize;
@@ -246,10 +244,12 @@ inline void qt_memrotate90_template<quint64>(const quint64 *src, int w, int h, i
qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
-template <class T>
-static
-inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
+template<class T>
+static inline void qt_memrotate180_template(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
+
const char *s = (const char*)(src) + (h - 1) * sstride;
for (int dy = 0; dy < h; ++dy) {
T *d = reinterpret_cast<T*>((char *)(dest) + dy * dstride);
diff --git a/src/gui/painting/qpagesize.h b/src/gui/painting/qpagesize.h
index 72d24ed938..f4e7af0f6c 100644
--- a/src/gui/painting/qpagesize.h
+++ b/src/gui/painting/qpagesize.h
@@ -224,7 +224,7 @@ public:
};
QPageSize();
- explicit QPageSize(PageSizeId pageSizeId);
+ Q_IMPLICIT QPageSize(PageSizeId pageSizeId);
explicit QPageSize(const QSize &pointSize,
const QString &name = QString(),
SizeMatchPolicy matchPolicy = FuzzyMatch);
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 7e26928e32..d752c01f6a 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 (pen.isCosmetic()) {
+ 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
+ QRectF extentRect = cpRect & clipRect;
+ qreal extent = qMax(extentRect.width(), extentRect.height());
+ qreal patternLength = 0;
+ const QList<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));
+ if (pen.widthF())
+ patternLength *= pen.widthF();
+ if (qFuzzyIsNull(patternLength)) {
+ pen.setStyle(Qt::NoPen);
+ } else if (extent / patternLength > 10000) {
+ // 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 (pen.isCosmetic()) {
- 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/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 38acc66ba4..9479cadd8f 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1369,7 +1369,7 @@ void QPainterPath::addRegion(const QRegion &region)
*/
Qt::FillRule QPainterPath::fillRule() const
{
- return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
+ return !d_func() ? Qt::OddEvenFill : d_func()->fillRule;
}
/*!
diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h
index 24feaf410b..c283b7f27e 100644
--- a/src/gui/painting/qpainterpath_p.h
+++ b/src/gui/painting/qpainterpath_p.h
@@ -292,7 +292,6 @@ inline void QPainterPathPrivate::clear()
elements.clear();
cStart = 0;
- fillRule = Qt::OddEvenFill;
bounds = {};
controlBounds = {};
diff --git a/src/gui/painting/qpixellayout.cpp b/src/gui/painting/qpixellayout.cpp
index 3b05e98318..c0b0b1c2e8 100644
--- a/src/gui/painting/qpixellayout.cpp
+++ b/src/gui/painting/qpixellayout.cpp
@@ -1303,7 +1303,7 @@ static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int in
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
for (int i = 0; i < count; ++i)
- d[i] = QRgba64::fromArgb32(src[i]);
+ d[i] = QRgba64::fromArgb32(src[i] | 0xff000000);
}
static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
@@ -1315,12 +1315,24 @@ static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *
return buffer;
}
+template<bool Mask>
static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
- for (int i = 0; i < count; ++i)
+ for (int i = 0; i < count; ++i) {
d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied();
+ if (Mask)
+ d[i].setAlpha(65535);
+ }
+}
+
+static void QT_FASTCALL storeRGBA64FromARGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgba64::fromArgb32(src[i]);
}
// Note:
@@ -1407,15 +1419,15 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
{ false, false, QPixelLayout::BPP64, nullptr,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBX64
+ storeRGBA64FromARGB32PM<true>, storeRGB64FromRGB32 }, // Format_RGBX64
{ true, false, QPixelLayout::BPP64, nullptr,
convertARGB32ToARGB32PM, nullptr,
fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
- storeRGBA64FromARGB32PM, storeRGB64FromRGB32 }, // Format_RGBA64
+ storeRGBA64FromARGB32PM<false>, storeRGB64FromRGB32 }, // Format_RGBA64
{ true, true, QPixelLayout::BPP64, nullptr,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
+ storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
{ false, false, QPixelLayout::BPP16, nullptr,
convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp
index 48d41f41f0..e851a3876a 100644
--- a/src/gui/painting/qrasterizer.cpp
+++ b/src/gui/painting/qrasterizer.cpp
@@ -864,7 +864,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
if (leftWidth == QScFixedFactor)
coverage[0] = rightWidth * 255;
else
- coverage[0] = (leftWidth + rightWidth) * 255;
+ coverage[0] = (rightWidth + leftWidth - QScFixedFactor) * 255;
x[0] = iLeft;
len[0] = 1;
} else {
diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp
index 7f7c3975e8..d6eb8c255c 100644
--- a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp
+++ b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp
@@ -106,13 +106,7 @@ void QDBusMenuConnection::unregisterTrayIconMenu(QDBusTrayIcon *item)
bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item)
{
- bool success = connection().registerService(item->instanceId());
- if (!success) {
- qWarning() << "failed to register service" << item->instanceId();
- return false;
- }
-
- success = connection().registerObject(StatusNotifierItemPath, item);
+ bool success = connection().registerObject(StatusNotifierItemPath, item);
if (!success) {
unregisterTrayIcon(item);
qWarning() << "failed to register" << item->instanceId() << StatusNotifierItemPath;
@@ -127,21 +121,18 @@ bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item)
bool QDBusMenuConnection::registerTrayIconWithWatcher(QDBusTrayIcon *item)
{
+ Q_UNUSED(item);
QDBusMessage registerMethod = QDBusMessage::createMethodCall(
StatusNotifierWatcherService, StatusNotifierWatcherPath, StatusNotifierWatcherService,
QLatin1String("RegisterStatusNotifierItem"));
- registerMethod.setArguments(QVariantList() << item->instanceId());
+ registerMethod.setArguments(QVariantList() << m_connection.baseService());
return m_connection.callWithCallback(registerMethod, this, SIGNAL(trayIconRegistered()), SLOT(dbusError(QDBusError)));
}
-bool QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item)
+void QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item)
{
unregisterTrayIconMenu(item);
connection().unregisterObject(StatusNotifierItemPath);
- bool success = connection().unregisterService(item->instanceId());
- if (!success)
- qWarning() << "failed to unregister service" << item->instanceId();
- return success;
}
#endif // QT_NO_SYSTEMTRAYICON
diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
index acd34c20ac..37183b021d 100644
--- a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
+++ b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
@@ -79,7 +79,7 @@ public:
void unregisterTrayIconMenu(QDBusTrayIcon *item);
bool registerTrayIcon(QDBusTrayIcon *item);
bool registerTrayIconWithWatcher(QDBusTrayIcon *item);
- bool unregisterTrayIcon(QDBusTrayIcon *item);
+ void unregisterTrayIcon(QDBusTrayIcon *item);
#endif // QT_NO_SYSTEMTRAYICON
Q_SIGNALS:
diff --git a/src/gui/platform/unix/dbustray/qdbustrayicon.cpp b/src/gui/platform/unix/dbustray/qdbustrayicon.cpp
index 1194e4ac66..892a99d726 100644
--- a/src/gui/platform/unix/dbustray/qdbustrayicon.cpp
+++ b/src/gui/platform/unix/dbustray/qdbustrayicon.cpp
@@ -208,6 +208,14 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon)
uint pid = session.interface()->servicePid(KDEWatcherService).value();
QString processName = QLockFilePrivate::processNameByPid(pid);
necessary = processName.endsWith(QLatin1String("indicator-application-service"));
+ if (!necessary) {
+ necessary = session.interface()->isServiceRegistered(
+ QStringLiteral("com.canonical.indicator.application"));
+ }
+ if (!necessary) {
+ necessary = session.interface()->isServiceRegistered(
+ QStringLiteral("org.ayatana.indicator.application"));
+ }
if (!necessary && QGuiApplication::desktopSettingsAware()) {
// Accessing to process name might be not allowed if the application
// is confined, thus we can just rely on the current desktop in use
diff --git a/src/gui/platform/unix/qxkbcommon.cpp b/src/gui/platform/unix/qxkbcommon.cpp
index f8ef8479e1..4e254044de 100644
--- a/src/gui/platform/unix/qxkbcommon.cpp
+++ b/src/gui/platform/unix/qxkbcommon.cpp
@@ -93,6 +93,7 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_Clear, Qt::Key_Delete>,
Xkb2Qt<XKB_KEY_Pause, Qt::Key_Pause>,
Xkb2Qt<XKB_KEY_Print, Qt::Key_Print>,
+ Xkb2Qt<XKB_KEY_Sys_Req, Qt::Key_SysReq>,
Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq
Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq
@@ -551,6 +552,12 @@ static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers mod
auto it = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
if (it != KeyTbl.end() && !(searchKey < *it))
qtKey = it->qt;
+
+ // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
+ if (superAsMeta && (qtKey == Qt::Key_Super_L || qtKey == Qt::Key_Super_R))
+ qtKey = Qt::Key_Meta;
+ if (hyperAsMeta && (qtKey == Qt::Key_Hyper_L || qtKey == Qt::Key_Hyper_R))
+ qtKey = Qt::Key_Meta;
}
if (qtKey)
@@ -577,12 +584,6 @@ static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers mod
}
}
- // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
- if (superAsMeta && (qtKey == Qt::Key_Super_L || qtKey == Qt::Key_Super_R))
- qtKey = Qt::Key_Meta;
- if (hyperAsMeta && (qtKey == Qt::Key_Hyper_L || qtKey == Qt::Key_Hyper_R))
- qtKey = Qt::Key_Meta;
-
return qtKey;
}
diff --git a/src/gui/platform/windows/qwindowsnativeinterface.cpp b/src/gui/platform/windows/qwindowsnativeinterface.cpp
index cacfceeb7c..850713db2c 100644
--- a/src/gui/platform/windows/qwindowsnativeinterface.cpp
+++ b/src/gui/platform/windows/qwindowsnativeinterface.cpp
@@ -53,6 +53,7 @@ using namespace QNativeInterface::Private;
/*!
\class QNativeInterface::QWGLContext
+ \inheaderfile QOpenGLContext
\since 6.0
\brief Native interface to a WGL context on Windows.
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index 5fdd3b7179..53e47b027c 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -1149,7 +1149,29 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
}
- const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
+ bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
+
+ // The Command::BindShaderResources command generated below is what will
+ // cause uniforms to be set (glUniformNxx). This needs some special
+ // handling here in this backend without real uniform buffers, because,
+ // like in other backends, we optimize out the setShaderResources when the
+ // srb that was set before is attempted to be set again on the command
+ // buffer, but that is incorrect if the same srb is now used with another
+ // pipeline. (because that could mean a glUseProgram not followed by
+ // up-to-date glUniform calls, i.e. with GL we have a strong dependency
+ // between the pipeline (== program) and the srb, unlike other APIs) This
+ // is the reason there is a second level of srb(+generation) tracking in
+ // the pipeline objects.
+ if (gfxPsD && (gfxPsD->currentSrb != srb || gfxPsD->currentSrbGeneration != srbD->generation)) {
+ srbChanged = true;
+ gfxPsD->currentSrb = srb;
+ gfxPsD->currentSrbGeneration = srbD->generation;
+ } else if (compPsD && (compPsD->currentSrb != srb || compPsD->currentSrbGeneration != srbD->generation)) {
+ srbChanged = true;
+ compPsD->currentSrb = srb;
+ compPsD->currentSrbGeneration = srbD->generation;
+ }
+
if (srbChanged || cbD->currentSrbGeneration != srbD->generation || srbD->hasDynamicOffset) {
if (gfxPsD) {
cbD->currentGraphicsSrb = srb;
@@ -4580,6 +4602,9 @@ bool QGles2GraphicsPipeline::create()
memset(uniformState, 0, sizeof(uniformState));
+ currentSrb = nullptr;
+ currentSrbGeneration = 0;
+
generation += 1;
rhiD->registerResource(this);
return true;
@@ -4653,6 +4678,9 @@ bool QGles2ComputePipeline::create()
memset(uniformState, 0, sizeof(uniformState));
+ currentSrb = nullptr;
+ currentSrbGeneration = 0;
+
generation += 1;
rhiD->registerResource(this);
return true;
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index a336497b63..49ab684363 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -290,6 +290,8 @@ struct QGles2GraphicsPipeline : public QRhiGraphicsPipeline
QGles2UniformDescriptionVector uniforms;
QGles2SamplerDescriptionVector samplers;
QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1];
+ QRhiShaderResourceBindings *currentSrb = nullptr;
+ uint currentSrbGeneration = 0;
uint generation = 0;
friend class QRhiGles2;
};
@@ -305,6 +307,8 @@ struct QGles2ComputePipeline : public QRhiComputePipeline
QGles2UniformDescriptionVector uniforms;
QGles2SamplerDescriptionVector samplers;
QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1];
+ QRhiShaderResourceBindings *currentSrb = nullptr;
+ uint currentSrbGeneration = 0;
uint generation = 0;
friend class QRhiGles2;
};
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 9e0655ef06..71f6eabb4c 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -224,7 +224,11 @@ struct QMetalBufferData
bool managed;
bool slotted;
id<MTLBuffer> buf[QMTL_FRAMES_IN_FLIGHT];
- QVarLengthArray<QRhiResourceUpdateBatchPrivate::BufferOp, 16> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
+ struct BufferUpdate {
+ int offset;
+ QRhiBufferData data;
+ };
+ QVarLengthArray<BufferUpdate, 16> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
};
struct QMetalRenderBufferData
@@ -1699,8 +1703,11 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
- for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
- bufD->d->pendingUpdates[i].append(u);
+ for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
+ if (u.offset == 0 && u.data.size() == bufD->m_size)
+ bufD->d->pendingUpdates[i].clear();
+ bufD->d->pendingUpdates[i].append({ u.offset, u.data });
+ }
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
// Due to the Metal API the handling of static and dynamic buffers is
// basically the same. So go through the same pendingUpdates machinery.
@@ -1708,8 +1715,7 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
for (int i = 0, ie = bufD->d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1; i != ie; ++i)
- bufD->d->pendingUpdates[i].append(
- QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(u.buf, u.offset, u.data.size(), u.data.constData()));
+ bufD->d->pendingUpdates[i].append({ u.offset, u.data });
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
executeBufferHostWritesForCurrentFrame(bufD);
@@ -1869,8 +1875,7 @@ void QRhiMetal::executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot)
void *p = [bufD->d->buf[slot] contents];
int changeBegin = -1;
int changeEnd = -1;
- for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[slot])) {
- Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf));
+ for (const QMetalBufferData::BufferUpdate &u : qAsConst(bufD->d->pendingUpdates[slot])) {
memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
changeBegin = u.offset;
@@ -2285,6 +2290,9 @@ void QMetalBuffer::endFullDynamicBufferUpdateForCurrentFrame()
static inline MTLPixelFormat toMetalTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags, const QRhiMetalData *d)
{
+#ifndef Q_OS_MACOS
+ Q_UNUSED(d);
+#endif
const bool srgb = flags.testFlag(QRhiTexture::sRGB);
switch (format) {
case QRhiTexture::RGBA8:
@@ -3787,10 +3795,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()
@@ -3849,13 +3889,7 @@ bool QMetalSwapChain::createOrResize()
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/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp
index 42cf147901..59300b6eca 100644
--- a/src/gui/text/freetype/qfontengine_ft.cpp
+++ b/src/gui/text/freetype/qfontengine_ft.cpp
@@ -1078,7 +1078,11 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
renderMode = FT_RENDER_MODE_MONO;
break;
case Format_A32:
- Q_ASSERT(hsubpixel || vfactor != 1);
+ if (!hsubpixel && vfactor == 1) {
+ qWarning("Format_A32 requested, but subpixel layout is unknown.");
+ return nullptr;
+ }
+
renderMode = hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
break;
case Format_A8:
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 9670568792..417587fab0 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -1143,14 +1143,14 @@ static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAd
s.chop(2);
value.variant = s;
if (value.variant.convert(QMetaType::fromType<qreal>())) {
- font->setPointSizeF(value.variant.toReal());
+ font->setPointSizeF(qBound(qreal(0), value.variant.toReal(), qreal(1 << 24) - 1));
valid = true;
}
} else if (s.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) {
s.chop(2);
value.variant = s;
if (value.variant.convert(QMetaType::fromType<int>())) {
- font->setPixelSize(value.variant.toInt());
+ font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
valid = true;
}
}
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index cf2573c984..203230636b 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -304,10 +304,12 @@ void QFontDatabasePrivate::invalidate()
emit static_cast<QGuiApplication *>(QCoreApplication::instance())->fontDatabaseChanged();
}
-QtFontFamily *QFontDatabasePrivate::family(const QString &f, FamilyRequestFlags flags)
+QtFontFamily *QFontDatabasePrivate::family(const QString &family, FamilyRequestFlags flags)
{
QtFontFamily *fam = nullptr;
+ const QString f = family.trimmed();
+
int low = 0;
int high = count;
int pos = count / 2;
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 341fd2a0e7..42c17ced58 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -261,9 +261,8 @@ bool QFontMetrics::operator ==(const QFontMetrics &other) const
The ascent of a font is the distance from the baseline to the
highest position characters extend to. In practice, some font
designers break this rule, e.g. when they put more than one accent
- on top of a character, or to accommodate an unusual character in
- an exotic language, so it is possible (though rare) that this
- value will be too small.
+ on top of a character, or to accommodate a certain character, so it
+ is possible (though rare) that this value will be too small.
\sa descent()
*/
@@ -298,8 +297,8 @@ int QFontMetrics::capHeight() const
The descent is the distance from the base line to the lowest point
characters extend to. In practice, some font designers break this rule,
- e.g. to accommodate an unusual character in an exotic language, so
- it is possible (though rare) that this value will be too small.
+ e.g. to accommodate a certain character, so it is possible (though
+ rare) that this value will be too small.
\sa ascent()
*/
@@ -1075,9 +1074,8 @@ bool QFontMetricsF::operator ==(const QFontMetricsF &other) const
The ascent of a font is the distance from the baseline to the
highest position characters extend to. In practice, some font
designers break this rule, e.g. when they put more than one accent
- on top of a character, or to accommodate an unusual character in
- an exotic language, so it is possible (though rare) that this
- value will be too small.
+ on top of a character, or to accommodate a certain character, so
+ it is possible (though rare) that this value will be too small.
\sa descent()
*/
@@ -1113,8 +1111,8 @@ qreal QFontMetricsF::capHeight() const
The descent is the distance from the base line to the lowest point
characters extend to. (Note that this is different from X, which
adds 1 pixel.) In practice, some font designers break this rule,
- e.g. to accommodate an unusual character in an exotic language, so
- it is possible (though rare) that this value will be too small.
+ e.g. to accommodate a certain character, so it is possible (though
+ rare) that this value will be too small.
\sa ascent()
*/
diff --git a/src/gui/text/qtextdocumentwriter.cpp b/src/gui/text/qtextdocumentwriter.cpp
index 31dfb9436f..74db049aa6 100644
--- a/src/gui/text/qtextdocumentwriter.cpp
+++ b/src/gui/text/qtextdocumentwriter.cpp
@@ -182,7 +182,7 @@ QByteArray QTextDocumentWriter::format () const
unchanged.
If the device is not already open, QTextDocumentWriter will attempt to
- open the device in \l QIODevice::WriteOnly mode by calling open().
+ open the device in \l {QIODeviceBase::}{WriteOnly} mode by calling open().
\note This will not work for certain devices, such as QProcess,
QTcpSocket and QUdpSocket, where some configuration is required before
@@ -211,7 +211,8 @@ QIODevice *QTextDocumentWriter::device () const
/*!
Sets the name of the file to be written to \a fileName. Internally,
QTextDocumentWriter will create a QFile and open it in \l
- QIODevice::WriteOnly mode, and use this file when writing the document.
+ {QIODeviceBase::}{WriteOnly} mode, and use this file when writing the
+ document.
\sa fileName(), setDevice()
*/
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index d3a28d8d02..94c0addeaa 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -258,7 +258,7 @@ struct QBidiAlgorithm {
for (int i = 0; i < length; ++i) {
int pos = i;
char32_t 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);
@@ -1546,12 +1552,21 @@ void QTextEngine::shapeText(int item) const
si.num_glyphs = glyph_pos;
}
+
if (Q_UNLIKELY(si.num_glyphs == 0)) {
- Q_UNREACHABLE(); // ### report shaping errors somehow
+ if (Q_UNLIKELY(!ensureSpace(si.glyph_data_offset + 1))) {
+ qWarning() << "Unable to allocate space for place-holder glyph";
+ return;
+ }
+
+ si.num_glyphs = 1;
+
+ // Overwrite with 0 token to indicate failure
+ QGlyphLayout g = availableGlyphs(&si);
+ g.glyphs[0] = 0;
return;
}
-
layoutData->used += si.num_glyphs;
QGlyphLayout glyphs = shapedGlyphs(&si);
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 996980b764..2772f8bdc3 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -1671,7 +1671,7 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
node->tableCellRowSpan = qMax(1, node->tableCellRowSpan);
} else if (key == QLatin1String("colspan")) {
if (setIntAttribute(&node->tableCellColSpan, value))
- node->tableCellColSpan = qMax(1, node->tableCellColSpan);
+ node->tableCellColSpan = qBound(1, node->tableCellColSpan, 20480);
}
break;
case Html_table:
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index d303219bb9..c1a27b2556 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -820,6 +820,10 @@ QTextLine QTextLayout::createLine()
int l = d->lines.size();
if (l && d->lines.at(l-1).length < 0) {
QTextLine(l-1, d).setNumColumns(INT_MAX);
+ if (d->maxWidth > QFIXED_MAX / 2) {
+ qWarning("QTextLayout: text too long, truncated.");
+ return QTextLine();
+ }
}
int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length + d->lines.at(l-1).trailingSpaces : 0;
int strlen = d->layoutData->string.length();
@@ -1295,13 +1299,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)