diff options
Diffstat (limited to 'src/gui')
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 ®ion) */ 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) |